summaryrefslogtreecommitdiffstats
path: root/kde/patch/digikam
diff options
context:
space:
mode:
Diffstat (limited to 'kde/patch/digikam')
-rw-r--r--kde/patch/digikam/digikam_clang_fix.patch38
-rw-r--r--kde/patch/digikam/digikam_databasemodel.patch13337
-rw-r--r--kde/patch/digikam/digikam_imagemagick7.patch40
3 files changed, 0 insertions, 13415 deletions
diff --git a/kde/patch/digikam/digikam_clang_fix.patch b/kde/patch/digikam/digikam_clang_fix.patch
deleted file mode 100644
index a4d77b0..0000000
--- a/kde/patch/digikam/digikam_clang_fix.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-Taken from:
-http://pkgs.fedoraproject.org/cgit/rpms/digikam.git/
-And added and extra '/core/' path componenent.
-
-From 86cd0d1d89c8b4d13f06dc8a353bdd99f13c4758 Mon Sep 17 00:00:00 2001
-From: Gilles Caulier <caulier.gilles@gmail.com>
-Date: Wed, 18 Jan 2017 10:13:20 +0100
-Subject: [PATCH 2/2] Fix compilation with clang
-
----
- libs/dmetadata/metaengine_p.cpp | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/core/libs/dmetadata/metaengine_p.cpp b/core/libs/dmetadata/metaengine_p.cpp
-index 2c83b58..2b44e06 100644
---- a/core/libs/dmetadata/metaengine_p.cpp
-+++ b/core/libs/dmetadata/metaengine_p.cpp
-@@ -49,7 +49,7 @@ extern "C"
- #include "digikam_debug.h"
-
- // Pragma directives to reduce warnings from Exiv2.
--#if not defined(__APPLE__) && defined(__GNUC__)
-+#if !defined(__APPLE__) && defined(__GNUC__)
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- #endif
-@@ -723,7 +723,7 @@ void MetaEngine::Private::loadSidecarData(Exiv2::Image::AutoPtr xmpsidecar)
- } // namespace Digikam
-
- // Restore warnings
--#if not defined(__APPLE__) && defined(__GNUC__)
-+#if !defined(__APPLE__) && defined(__GNUC__)
- #pragma GCC diagnostic pop
- #endif
-
---
-2.9.3
-
diff --git a/kde/patch/digikam/digikam_databasemodel.patch b/kde/patch/digikam/digikam_databasemodel.patch
deleted file mode 100644
index 8b2fff7..0000000
--- a/kde/patch/digikam/digikam_databasemodel.patch
+++ /dev/null
@@ -1,13337 +0,0 @@
-From 7e00441c257e7e9e5dc5ab983fc06046fb72b0c5 Mon Sep 17 00:00:00 2001
-From: Gilles Caulier <caulier.gilles@gmail.com>
-Date: Sat, 22 Jul 2017 15:46:08 +0200
-Subject: fix broken linking stage under MacOS with macports. move database
- models into libdigikamdatabase. Let's others model in place to be included
- into libdigikamcore
-
----
- libs/database/CMakeLists.txt | 16 +-
- libs/database/models/imagefiltermodel.cpp | 1116 ++++++++++++++++++
- libs/database/models/imagefiltermodel.h | 299 +++++
- libs/database/models/imagefiltermodelpriv.cpp | 258 ++++
- libs/database/models/imagefiltermodelpriv.h | 159 +++
- libs/database/models/imagefiltermodelthreads.cpp | 40 +
- libs/database/models/imagefiltermodelthreads.h | 100 ++
- libs/database/models/imagefiltersettings.cpp | 952 +++++++++++++++
- libs/database/models/imagefiltersettings.h | 349 ++++++
- libs/database/models/imagelistmodel.cpp | 70 ++
- libs/database/models/imagelistmodel.h | 63 +
- libs/database/models/imagemodel.cpp | 1368 ++++++++++++++++++++++
- libs/database/models/imagemodel.h | 364 ++++++
- libs/database/models/imagesortsettings.cpp | 400 +++++++
- libs/database/models/imagesortsettings.h | 225 ++++
- libs/database/models/imagethumbnailmodel.cpp | 323 +++++
- libs/database/models/imagethumbnailmodel.h | 140 +++
- libs/database/models/imageversionsmodel.cpp | 183 +++
- libs/database/models/imageversionsmodel.h | 75 ++
- libs/models/CMakeLists.txt | 15 +-
- libs/models/imagefiltermodel.cpp | 1116 ------------------
- libs/models/imagefiltermodel.h | 299 -----
- libs/models/imagefiltermodelpriv.cpp | 258 ----
- libs/models/imagefiltermodelpriv.h | 159 ---
- libs/models/imagefiltermodelthreads.cpp | 40 -
- libs/models/imagefiltermodelthreads.h | 100 --
- libs/models/imagefiltersettings.cpp | 952 ---------------
- libs/models/imagefiltersettings.h | 349 ------
- libs/models/imagelistmodel.cpp | 70 --
- libs/models/imagelistmodel.h | 63 -
- libs/models/imagemodel.cpp | 1368 ----------------------
- libs/models/imagemodel.h | 364 ------
- libs/models/imagesortsettings.cpp | 400 -------
- libs/models/imagesortsettings.h | 225 ----
- libs/models/imagethumbnailmodel.cpp | 323 -----
- libs/models/imagethumbnailmodel.h | 140 ---
- libs/models/imageversionsmodel.cpp | 183 ---
- libs/models/imageversionsmodel.h | 75 --
- 38 files changed, 6499 insertions(+), 6500 deletions(-)
- create mode 100644 libs/database/models/imagefiltermodel.cpp
- create mode 100644 libs/database/models/imagefiltermodel.h
- create mode 100644 libs/database/models/imagefiltermodelpriv.cpp
- create mode 100644 libs/database/models/imagefiltermodelpriv.h
- create mode 100644 libs/database/models/imagefiltermodelthreads.cpp
- create mode 100644 libs/database/models/imagefiltermodelthreads.h
- create mode 100644 libs/database/models/imagefiltersettings.cpp
- create mode 100644 libs/database/models/imagefiltersettings.h
- create mode 100644 libs/database/models/imagelistmodel.cpp
- create mode 100644 libs/database/models/imagelistmodel.h
- create mode 100644 libs/database/models/imagemodel.cpp
- create mode 100644 libs/database/models/imagemodel.h
- create mode 100644 libs/database/models/imagesortsettings.cpp
- create mode 100644 libs/database/models/imagesortsettings.h
- create mode 100644 libs/database/models/imagethumbnailmodel.cpp
- create mode 100644 libs/database/models/imagethumbnailmodel.h
- create mode 100644 libs/database/models/imageversionsmodel.cpp
- create mode 100644 libs/database/models/imageversionsmodel.h
- delete mode 100644 libs/models/imagefiltermodel.cpp
- delete mode 100644 libs/models/imagefiltermodel.h
- delete mode 100644 libs/models/imagefiltermodelpriv.cpp
- delete mode 100644 libs/models/imagefiltermodelpriv.h
- delete mode 100644 libs/models/imagefiltermodelthreads.cpp
- delete mode 100644 libs/models/imagefiltermodelthreads.h
- delete mode 100644 libs/models/imagefiltersettings.cpp
- delete mode 100644 libs/models/imagefiltersettings.h
- delete mode 100644 libs/models/imagelistmodel.cpp
- delete mode 100644 libs/models/imagelistmodel.h
- delete mode 100644 libs/models/imagemodel.cpp
- delete mode 100644 libs/models/imagemodel.h
- delete mode 100644 libs/models/imagesortsettings.cpp
- delete mode 100644 libs/models/imagesortsettings.h
- delete mode 100644 libs/models/imagethumbnailmodel.cpp
- delete mode 100644 libs/models/imagethumbnailmodel.h
- delete mode 100644 libs/models/imageversionsmodel.cpp
- delete mode 100644 libs/models/imageversionsmodel.h
-
-diff --git a/libs/database/CMakeLists.txt b/libs/database/CMakeLists.txt
-index 7d05536..a431a36 100644
---- a/libs/database/CMakeLists.txt
-+++ b/libs/database/CMakeLists.txt
-@@ -13,6 +13,18 @@ endif (POLICY CMP0063)
- # Boost uses operator names (and, not, ...)
- string(REPLACE "-fno-operator-names" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
-
-+set(libdatabasemodels_SRCS
-+ models/imagemodel.cpp
-+ models/imagefiltermodel.cpp
-+ models/imagefiltermodelpriv.cpp
-+ models/imagefiltermodelthreads.cpp
-+ models/imagefiltersettings.cpp
-+ models/imagelistmodel.cpp
-+ models/imagesortsettings.cpp
-+ models/imagethumbnailmodel.cpp
-+ models/imageversionsmodel.cpp
-+)
-+
- set(libdatabasecore_SRCS
- server/databaseserverstarter.cpp
- server/databaseservererror.cpp
-@@ -152,10 +164,10 @@ if(ENABLE_DBUS)
- include_directories($<TARGET_PROPERTY:Qt5::DBus,INTERFACE_INCLUDE_DIRECTORIES>)
- endif()
-
--add_library(digikamdatabase_src OBJECT ${digikamdatabase_LIB_SRCS})
-+add_library(digikamdatabase_src OBJECT ${digikamdatabase_LIB_SRCS} ${libdatabasemodels_SRCS})
- add_library(digikamdatabasemain_src OBJECT ${libdatabaseutils_SRCS} ${libimgqsort_SRCS})
- add_library(digikamdatabasecore_src OBJECT ${libdatabasecore_SRCS})
--add_library(digikamdatabase SHARED $<TARGET_OBJECTS:digikamdatabase_src> $<TARGET_OBJECTS:digikamdatabasemodels_src>)
-+add_library(digikamdatabase $<TARGET_OBJECTS:digikamdatabase_src>)
-
- generate_export_header(digikamdatabase
- BASE_NAME digikam_database
-diff --git a/libs/database/models/imagefiltermodel.cpp b/libs/database/models/imagefiltermodel.cpp
-new file mode 100644
-index 0000000..3d57e05
---- /dev/null
-+++ b/libs/database/models/imagefiltermodel.cpp
-@@ -0,0 +1,1116 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Qt item model for database entries
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-+ * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-+ * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-+ * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagefiltermodel.h"
-+#include "imagefiltermodelpriv.h"
-+#include "imagefiltermodelthreads.h"
-+
-+// Local includes
-+
-+#include "digikam_debug.h"
-+#include "coredbaccess.h"
-+#include "coredbchangesets.h"
-+#include "coredbwatch.h"
-+#include "imageinfolist.h"
-+#include "imagemodel.h"
-+
-+namespace Digikam
-+{
-+
-+ImageSortFilterModel::ImageSortFilterModel(QObject* parent)
-+ : DCategorizedSortFilterProxyModel(parent), m_chainedModel(0)
-+{
-+}
-+
-+void ImageSortFilterModel::setSourceImageModel(ImageModel* source)
-+{
-+ if (m_chainedModel)
-+ {
-+ m_chainedModel->setSourceImageModel(source);
-+ }
-+ else
-+ {
-+ setDirectSourceImageModel(source);
-+ }
-+}
-+
-+void ImageSortFilterModel::setSourceFilterModel(ImageSortFilterModel* source)
-+{
-+ if (source)
-+ {
-+ ImageModel* const model = sourceImageModel();
-+
-+ if (model)
-+ {
-+ source->setSourceImageModel(model);
-+ }
-+ }
-+
-+ m_chainedModel = source;
-+ setSourceModel(source);
-+}
-+
-+void ImageSortFilterModel::setDirectSourceImageModel(ImageModel* model)
-+{
-+ setSourceModel(model);
-+}
-+
-+void ImageSortFilterModel::setSourceModel(QAbstractItemModel* model)
-+{
-+ // made it protected, only setSourceImageModel is public
-+ DCategorizedSortFilterProxyModel::setSourceModel(model);
-+}
-+
-+ImageModel* ImageSortFilterModel::sourceImageModel() const
-+{
-+ if (m_chainedModel)
-+ {
-+ return m_chainedModel->sourceImageModel();
-+ }
-+
-+ return static_cast<ImageModel*>(sourceModel());
-+}
-+
-+ImageSortFilterModel* ImageSortFilterModel::sourceFilterModel() const
-+{
-+ return m_chainedModel;
-+}
-+
-+ImageFilterModel* ImageSortFilterModel::imageFilterModel() const
-+{
-+ // reimplemented in ImageFilterModel
-+ if (m_chainedModel)
-+ {
-+ return m_chainedModel->imageFilterModel();
-+ }
-+
-+ return 0;
-+}
-+
-+QModelIndex ImageSortFilterModel::mapToSourceImageModel(const QModelIndex& index) const
-+{
-+ if (m_chainedModel)
-+ {
-+ return m_chainedModel->mapToSourceImageModel(mapToSource(index));
-+ }
-+
-+ return mapToSource(index);
-+}
-+
-+QModelIndex ImageSortFilterModel::mapFromSourceImageModel(const QModelIndex& albummodel_index) const
-+{
-+ if (m_chainedModel)
-+ {
-+ return mapFromSource(m_chainedModel->mapFromSourceImageModel(albummodel_index));
-+ }
-+
-+ return mapFromSource(albummodel_index);
-+}
-+
-+
-+QModelIndex ImageSortFilterModel::mapFromDirectSourceToSourceImageModel(const QModelIndex& sourceModel_index) const
-+{
-+ if (m_chainedModel)
-+ {
-+ return m_chainedModel->mapToSourceImageModel(sourceModel_index);
-+ }
-+ return sourceModel_index;
-+}
-+
-+// -------------- Convenience mappers -------------------------------------------------------------------
-+
-+QList<QModelIndex> ImageSortFilterModel::mapListToSource(const QList<QModelIndex>& indexes) const
-+{
-+ QList<QModelIndex> sourceIndexes;
-+ foreach(const QModelIndex& index, indexes)
-+ {
-+ sourceIndexes << mapToSourceImageModel(index);
-+ }
-+ return sourceIndexes;
-+}
-+
-+QList<QModelIndex> ImageSortFilterModel::mapListFromSource(const QList<QModelIndex>& sourceIndexes) const
-+{
-+ QList<QModelIndex> indexes;
-+ foreach(const QModelIndex& index, sourceIndexes)
-+ {
-+ indexes << mapFromSourceImageModel(index);
-+ }
-+ return indexes;
-+}
-+
-+ImageInfo ImageSortFilterModel::imageInfo(const QModelIndex& index) const
-+{
-+ return sourceImageModel()->imageInfo(mapToSourceImageModel(index));
-+}
-+
-+qlonglong ImageSortFilterModel::imageId(const QModelIndex& index) const
-+{
-+ return sourceImageModel()->imageId(mapToSourceImageModel(index));
-+}
-+
-+QList<ImageInfo> ImageSortFilterModel::imageInfos(const QList<QModelIndex>& indexes) const
-+{
-+ QList<ImageInfo> infos;
-+ ImageModel* const model = sourceImageModel();
-+
-+ foreach(const QModelIndex& index, indexes)
-+ {
-+ infos << model->imageInfo(mapToSourceImageModel(index));
-+ }
-+
-+ return infos;
-+}
-+
-+QList<qlonglong> ImageSortFilterModel::imageIds(const QList<QModelIndex>& indexes) const
-+{
-+ QList<qlonglong> ids;
-+ ImageModel* const model = sourceImageModel();
-+
-+ foreach(const QModelIndex& index, indexes)
-+ {
-+ ids << model->imageId(mapToSourceImageModel(index));
-+ }
-+
-+ return ids;
-+}
-+
-+QModelIndex ImageSortFilterModel::indexForPath(const QString& filePath) const
-+{
-+ return mapFromSourceImageModel(sourceImageModel()->indexForPath(filePath));
-+}
-+
-+QModelIndex ImageSortFilterModel::indexForImageInfo(const ImageInfo& info) const
-+{
-+ return mapFromSourceImageModel(sourceImageModel()->indexForImageInfo(info));
-+}
-+
-+QModelIndex ImageSortFilterModel::indexForImageId(qlonglong id) const
-+{
-+ return mapFromSourceImageModel(sourceImageModel()->indexForImageId(id));
-+}
-+
-+QList<ImageInfo> ImageSortFilterModel::imageInfosSorted() const
-+{
-+ QList<ImageInfo> infos;
-+ const int size = rowCount();
-+ ImageModel* const model = sourceImageModel();
-+
-+ for (int i=0; i<size; ++i)
-+ {
-+ infos << model->imageInfo(mapToSourceImageModel(index(i, 0)));
-+ }
-+
-+ return infos;
-+}
-+
-+// --------------------------------------------------------------------------------------------
-+
-+ImageFilterModel::ImageFilterModel(QObject* parent)
-+ : ImageSortFilterModel(parent),
-+ d_ptr(new ImageFilterModelPrivate)
-+{
-+ d_ptr->init(this);
-+}
-+
-+ImageFilterModel::ImageFilterModel(ImageFilterModelPrivate& dd, QObject* parent)
-+ : ImageSortFilterModel(parent),
-+ d_ptr(&dd)
-+{
-+ d_ptr->init(this);
-+}
-+
-+ImageFilterModel::~ImageFilterModel()
-+{
-+ Q_D(ImageFilterModel);
-+ delete d;
-+}
-+
-+void ImageFilterModel::setDirectSourceImageModel(ImageModel* sourceModel)
-+{
-+ Q_D(ImageFilterModel);
-+
-+ if (d->imageModel)
-+ {
-+ d->imageModel->unsetPreprocessor(d);
-+ disconnect(d->imageModel, SIGNAL(modelReset()),
-+ this, SLOT(slotModelReset()));
-+ slotModelReset();
-+ }
-+
-+ d->imageModel = sourceModel;
-+
-+ if (d->imageModel)
-+ {
-+ d->imageModel->setPreprocessor(d);
-+
-+ connect(d->imageModel, SIGNAL(preprocess(QList<ImageInfo>,QList<QVariant>)),
-+ d, SLOT(preprocessInfos(QList<ImageInfo>,QList<QVariant>)));
-+
-+ connect(d->imageModel, SIGNAL(processAdded(QList<ImageInfo>,QList<QVariant>)),
-+ d, SLOT(processAddedInfos(QList<ImageInfo>,QList<QVariant>)));
-+
-+ connect(d, SIGNAL(reAddImageInfos(QList<ImageInfo>,QList<QVariant>)),
-+ d->imageModel, SLOT(reAddImageInfos(QList<ImageInfo>,QList<QVariant>)));
-+
-+ connect(d, SIGNAL(reAddingFinished()),
-+ d->imageModel, SLOT(reAddingFinished()));
-+
-+ connect(d->imageModel, SIGNAL(modelReset()),
-+ this, SLOT(slotModelReset()));
-+
-+ connect(d->imageModel, SIGNAL(imageChange(ImageChangeset,QItemSelection)),
-+ this, SLOT(slotImageChange(ImageChangeset)));
-+
-+ connect(d->imageModel, SIGNAL(imageTagChange(ImageTagChangeset,QItemSelection)),
-+ this, SLOT(slotImageTagChange(ImageTagChangeset)));
-+ }
-+
-+ setSourceModel(d->imageModel);
-+}
-+
-+QVariant ImageFilterModel::data(const QModelIndex& index, int role) const
-+{
-+ Q_D(const ImageFilterModel);
-+
-+ if (!index.isValid())
-+ {
-+ return QVariant();
-+ }
-+
-+ switch (role)
-+ {
-+ // Attention: This breaks should there ever be another filter model between this and the ImageModel
-+
-+ case DCategorizedSortFilterProxyModel::CategoryDisplayRole:
-+ return categoryIdentifier(d->imageModel->imageInfoRef(mapToSource(index)));
-+ case CategorizationModeRole:
-+ return d->sorter.categorizationMode;
-+ case SortOrderRole:
-+ return d->sorter.sortRole;
-+ //case CategoryCountRole:
-+ // return categoryCount(d->imageModel->imageInfoRef(mapToSource(index)));
-+ case CategoryAlbumIdRole:
-+ return d->imageModel->imageInfoRef(mapToSource(index)).albumId();
-+ case CategoryFormatRole:
-+ return d->imageModel->imageInfoRef(mapToSource(index)).format();
-+ case GroupIsOpenRole:
-+ return d->groupFilter.isAllOpen() ||
-+ d->groupFilter.isOpen(d->imageModel->imageInfoRef(mapToSource(index)).id());
-+ case ImageFilterModelPointerRole:
-+ return QVariant::fromValue(const_cast<ImageFilterModel*>(this));
-+ }
-+
-+ return DCategorizedSortFilterProxyModel::data(index, role);
-+}
-+
-+ImageFilterModel* ImageFilterModel::imageFilterModel() const
-+{
-+ return const_cast<ImageFilterModel*>(this);
-+}
-+
-+DatabaseFields::Set ImageFilterModel::suggestedWatchFlags() const
-+{
-+ DatabaseFields::Set watchFlags;
-+ watchFlags |= DatabaseFields::Name | DatabaseFields::FileSize | DatabaseFields::ModificationDate;
-+ watchFlags |= DatabaseFields::Rating | DatabaseFields::CreationDate | DatabaseFields::Orientation |
-+ DatabaseFields::Width | DatabaseFields::Height;
-+ watchFlags |= DatabaseFields::Comment;
-+ watchFlags |= DatabaseFields::ImageRelations;
-+ return watchFlags;
-+}
-+
-+// -------------- Filter settings --------------
-+
-+void ImageFilterModel::setDayFilter(const QList<QDateTime>& days)
-+{
-+ Q_D(ImageFilterModel);
-+ d->filter.setDayFilter(days);
-+ setImageFilterSettings(d->filter);
-+}
-+
-+void ImageFilterModel::setTagFilter(const QList<int>& includedTags, const QList<int>& excludedTags,
-+ ImageFilterSettings::MatchingCondition matchingCond,
-+ bool showUnTagged, const QList<int>& clTagIds, const QList<int>& plTagIds)
-+{
-+ Q_D(ImageFilterModel);
-+ d->filter.setTagFilter(includedTags, excludedTags, matchingCond, showUnTagged, clTagIds, plTagIds);
-+ setImageFilterSettings(d->filter);
-+}
-+
-+void ImageFilterModel::setRatingFilter(int rating, ImageFilterSettings::RatingCondition ratingCond, bool isUnratedExcluded)
-+{
-+ Q_D(ImageFilterModel);
-+ d->filter.setRatingFilter(rating, ratingCond, isUnratedExcluded);
-+ setImageFilterSettings(d->filter);
-+}
-+
-+void ImageFilterModel::setUrlWhitelist(const QList<QUrl> urlList, const QString& id)
-+{
-+ Q_D(ImageFilterModel);
-+ d->filter.setUrlWhitelist(urlList, id);
-+ setImageFilterSettings(d->filter);
-+}
-+
-+void ImageFilterModel::setIdWhitelist(const QList<qlonglong>& idList, const QString& id)
-+{
-+ Q_D(ImageFilterModel);
-+ d->filter.setIdWhitelist(idList, id);
-+ setImageFilterSettings(d->filter);
-+}
-+
-+void ImageFilterModel::setMimeTypeFilter(int mimeTypeFilter)
-+{
-+ Q_D(ImageFilterModel);
-+ d->filter.setMimeTypeFilter(mimeTypeFilter);
-+ setImageFilterSettings(d->filter);
-+}
-+
-+void ImageFilterModel::setGeolocationFilter(const ImageFilterSettings::GeolocationCondition& condition)
-+{
-+ Q_D(ImageFilterModel);
-+ d->filter.setGeolocationFilter(condition);
-+ setImageFilterSettings(d->filter);
-+}
-+
-+void ImageFilterModel::setTextFilter(const SearchTextFilterSettings& settings)
-+{
-+ Q_D(ImageFilterModel);
-+ d->filter.setTextFilter(settings);
-+ setImageFilterSettings(d->filter);
-+}
-+
-+void ImageFilterModel::setImageFilterSettings(const ImageFilterSettings& settings)
-+{
-+ Q_D(ImageFilterModel);
-+
-+ {
-+ QMutexLocker lock(&d->mutex);
-+ d->version++;
-+ d->filter = settings;
-+ d->filterCopy = settings;
-+ d->versionFilterCopy = d->versionFilter;
-+ d->groupFilterCopy = d->groupFilter;
-+
-+ d->needPrepareComments = settings.isFilteringByText();
-+ d->needPrepareTags = settings.isFilteringByTags();
-+ d->needPrepareGroups = true;
-+ d->needPrepare = d->needPrepareComments || d->needPrepareTags || d->needPrepareGroups;
-+
-+ d->hasOneMatch = false;
-+ d->hasOneMatchForText = false;
-+ }
-+
-+ d->filterResults.clear();
-+
-+ //d->categoryCountHashInt.clear();
-+ //d->categoryCountHashString.clear();
-+ if (d->imageModel)
-+ {
-+ d->infosToProcess(d->imageModel->imageInfos());
-+ }
-+
-+ emit filterSettingsChanged(settings);
-+}
-+
-+void ImageFilterModel::setVersionManagerSettings(const VersionManagerSettings& settings)
-+{
-+ Q_D(ImageFilterModel);
-+ d->versionFilter.setVersionManagerSettings(settings);
-+ setVersionImageFilterSettings(d->versionFilter);
-+}
-+
-+void ImageFilterModel::setExceptionList(const QList<qlonglong>& idList, const QString& id)
-+{
-+ Q_D(ImageFilterModel);
-+ d->versionFilter.setExceptionList(idList, id);
-+ setVersionImageFilterSettings(d->versionFilter);
-+}
-+
-+void ImageFilterModel::setVersionImageFilterSettings(const VersionImageFilterSettings& settings)
-+{
-+ Q_D(ImageFilterModel);
-+ d->versionFilter = settings;
-+ slotUpdateFilter();
-+}
-+
-+bool ImageFilterModel::isGroupOpen(qlonglong group) const
-+{
-+ Q_D(const ImageFilterModel);
-+ return d->groupFilter.isOpen(group);
-+}
-+
-+bool ImageFilterModel::isAllGroupsOpen() const
-+{
-+ Q_D(const ImageFilterModel);
-+ return d->groupFilter.isAllOpen();
-+}
-+
-+void ImageFilterModel::setGroupOpen(qlonglong group, bool open)
-+{
-+ Q_D(ImageFilterModel);
-+ d->groupFilter.setOpen(group, open);
-+ setGroupImageFilterSettings(d->groupFilter);
-+}
-+
-+void ImageFilterModel::toggleGroupOpen(qlonglong group)
-+{
-+ setGroupOpen(group, !isGroupOpen(group));
-+}
-+
-+void ImageFilterModel::setAllGroupsOpen(bool open)
-+{
-+ Q_D(ImageFilterModel);
-+ d->groupFilter.setAllOpen(open);
-+ setGroupImageFilterSettings(d->groupFilter);
-+}
-+
-+void ImageFilterModel::setGroupImageFilterSettings(const GroupImageFilterSettings& settings)
-+{
-+ Q_D(ImageFilterModel);
-+ d->groupFilter = settings;
-+ slotUpdateFilter();
-+}
-+
-+void ImageFilterModel::slotUpdateFilter()
-+{
-+ Q_D(ImageFilterModel);
-+ setImageFilterSettings(d->filter);
-+}
-+
-+ImageFilterSettings ImageFilterModel::imageFilterSettings() const
-+{
-+ Q_D(const ImageFilterModel);
-+ return d->filter;
-+}
-+
-+ImageSortSettings ImageFilterModel::imageSortSettings() const
-+{
-+ Q_D(const ImageFilterModel);
-+ return d->sorter;
-+}
-+
-+VersionImageFilterSettings ImageFilterModel::versionImageFilterSettings() const
-+{
-+ Q_D(const ImageFilterModel);
-+ return d->versionFilter;
-+}
-+
-+GroupImageFilterSettings ImageFilterModel::groupImageFilterSettings() const
-+{
-+ Q_D(const ImageFilterModel);
-+ return d->groupFilter;
-+}
-+
-+void ImageFilterModel::slotModelReset()
-+{
-+ Q_D(ImageFilterModel);
-+ {
-+ QMutexLocker lock(&d->mutex);
-+ // discard all packages on the way that are marked as send out for re-add
-+ d->lastDiscardVersion = d->version;
-+ d->sentOutForReAdd = 0;
-+ // discard all packages on the way
-+ d->version++;
-+ d->sentOut = 0;
-+
-+ d->hasOneMatch = false;
-+ d->hasOneMatchForText = false;
-+ }
-+ d->filterResults.clear();
-+}
-+
-+bool ImageFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
-+{
-+ Q_D(const ImageFilterModel);
-+
-+ if (source_parent.isValid())
-+ {
-+ return false;
-+ }
-+
-+ qlonglong id = d->imageModel->imageId(source_row);
-+ QHash<qlonglong, bool>::const_iterator it = d->filterResults.constFind(id);
-+
-+ if (it != d->filterResults.constEnd())
-+ {
-+ return it.value();
-+ }
-+
-+ // usually done in thread and cache, unless source model changed
-+ ImageInfo info = d->imageModel->imageInfo(source_row);
-+ bool match = d->filter.matches(info);
-+ match = match ? d->versionFilter.matches(info) : false;
-+
-+ return match ? d->groupFilter.matches(info) : false;
-+}
-+
-+void ImageFilterModel::setSendImageInfoSignals(bool sendSignals)
-+{
-+ if (sendSignals)
-+ {
-+ connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)),
-+ this, SLOT(slotRowsInserted(QModelIndex,int,int)));
-+
-+ connect(this, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
-+ this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)));
-+ }
-+ else
-+ {
-+ disconnect(this, SIGNAL(rowsInserted(QModelIndex,int,int)),
-+ this, SLOT(slotRowsInserted(QModelIndex,int,int)));
-+
-+ disconnect(this, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
-+ this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)));
-+ }
-+}
-+
-+void ImageFilterModel::slotRowsInserted(const QModelIndex& /*parent*/, int start, int end)
-+{
-+ QList<ImageInfo> infos;
-+
-+ for (int i=start; i<=end; ++i)
-+ {
-+ infos << imageInfo(index(i, 0));
-+ }
-+
-+ emit imageInfosAdded(infos);
-+}
-+
-+void ImageFilterModel::slotRowsAboutToBeRemoved(const QModelIndex& /*parent*/, int start, int end)
-+{
-+ QList<ImageInfo> infos;
-+
-+ for (int i=start; i<=end; ++i)
-+ {
-+ infos << imageInfo(index(i, 0));
-+ }
-+
-+ emit imageInfosAboutToBeRemoved(infos);
-+}
-+
-+// -------------- Threaded preparation & filtering --------------
-+
-+void ImageFilterModel::addPrepareHook(ImageFilterModelPrepareHook* hook)
-+{
-+ Q_D(ImageFilterModel);
-+ QMutexLocker lock(&d->mutex);
-+ d->prepareHooks << hook;
-+}
-+
-+void ImageFilterModel::removePrepareHook(ImageFilterModelPrepareHook* hook)
-+{
-+ Q_D(ImageFilterModel);
-+ QMutexLocker lock(&d->mutex);
-+ d->prepareHooks.removeAll(hook);
-+}
-+
-+void ImageFilterModelPreparer::process(ImageFilterModelTodoPackage package)
-+{
-+ if (!checkVersion(package))
-+ {
-+ emit discarded(package);
-+ return;
-+ }
-+
-+ // get thread-local copy
-+ bool needPrepareTags, needPrepareComments, needPrepareGroups;
-+ QList<ImageFilterModelPrepareHook*> prepareHooks;
-+ {
-+ QMutexLocker lock(&d->mutex);
-+ needPrepareTags = d->needPrepareTags;
-+ needPrepareComments = d->needPrepareComments;
-+ needPrepareGroups = d->needPrepareGroups;
-+ prepareHooks = d->prepareHooks;
-+ }
-+
-+ //TODO: Make efficient!!
-+ if (needPrepareComments)
-+ {
-+ foreach(const ImageInfo& info, package.infos)
-+ {
-+ info.comment();
-+ }
-+ }
-+
-+ if (!checkVersion(package))
-+ {
-+ emit discarded(package);
-+ return;
-+ }
-+
-+ // The downside of QVector: At some point, we may need a QList for an API.
-+ // Nonetheless, QList and ImageInfo is fast. We could as well
-+ // reimplement ImageInfoList to ImageInfoVector (internally with templates?)
-+ ImageInfoList infoList;
-+
-+ if (needPrepareTags || needPrepareGroups)
-+ {
-+ infoList = package.infos.toList();
-+ }
-+
-+ if (needPrepareTags)
-+ {
-+ infoList.loadTagIds();
-+ }
-+
-+ if (needPrepareGroups)
-+ {
-+ infoList.loadGroupImageIds();
-+ }
-+
-+ foreach(ImageFilterModelPrepareHook* hook, prepareHooks)
-+ {
-+ hook->prepare(package.infos);
-+ }
-+
-+ emit processed(package);
-+}
-+
-+void ImageFilterModelFilterer::process(ImageFilterModelTodoPackage package)
-+{
-+ if (!checkVersion(package))
-+ {
-+ emit discarded(package);
-+ return;
-+ }
-+
-+ // get thread-local copy
-+ ImageFilterSettings localFilter;
-+ VersionImageFilterSettings localVersionFilter;
-+ GroupImageFilterSettings localGroupFilter;
-+ bool hasOneMatch;
-+ bool hasOneMatchForText;
-+ {
-+ QMutexLocker lock(&d->mutex);
-+ localFilter = d->filterCopy;
-+ localVersionFilter = d->versionFilterCopy;
-+ localGroupFilter = d->groupFilterCopy;
-+ hasOneMatch = d->hasOneMatch;
-+ hasOneMatchForText = d->hasOneMatchForText;
-+ }
-+
-+ // Actual filtering. The variants to spare checking hasOneMatch over and over again.
-+ if (hasOneMatch && hasOneMatchForText)
-+ {
-+ foreach(const ImageInfo& info, package.infos)
-+ {
-+ package.filterResults[info.id()] = localFilter.matches(info) &&
-+ localVersionFilter.matches(info) &&
-+ localGroupFilter.matches(info);
-+ }
-+ }
-+ else if (hasOneMatch)
-+ {
-+ bool matchForText;
-+
-+ foreach(const ImageInfo& info, package.infos)
-+ {
-+ package.filterResults[info.id()] = localFilter.matches(info, &matchForText) &&
-+ localVersionFilter.matches(info) &&
-+ localGroupFilter.matches(info);
-+
-+ if (matchForText)
-+ {
-+ hasOneMatchForText = true;
-+ }
-+ }
-+ }
-+ else
-+ {
-+ bool result, matchForText;
-+
-+ foreach(const ImageInfo& info, package.infos)
-+ {
-+ result = localFilter.matches(info, &matchForText) &&
-+ localVersionFilter.matches(info) &&
-+ localGroupFilter.matches(info);
-+ package.filterResults[info.id()] = result;
-+
-+ if (result)
-+ {
-+ hasOneMatch = true;
-+ }
-+
-+ if (matchForText)
-+ {
-+ hasOneMatchForText = true;
-+ }
-+ }
-+ }
-+
-+ if (checkVersion(package))
-+ {
-+ QMutexLocker lock(&d->mutex);
-+ d->hasOneMatch = hasOneMatch;
-+ d->hasOneMatchForText = hasOneMatchForText;
-+ }
-+
-+ emit processed(package);
-+}
-+
-+// -------------- Sorting and Categorization -------------------------------------------------------
-+
-+void ImageFilterModel::setImageSortSettings(const ImageSortSettings& sorter)
-+{
-+ Q_D(ImageFilterModel);
-+ d->sorter = sorter;
-+ setCategorizedModel(d->sorter.categorizationMode != ImageSortSettings::NoCategories);
-+ invalidate();
-+}
-+
-+void ImageFilterModel::setCategorizationMode(ImageSortSettings::CategorizationMode mode)
-+{
-+ Q_D(ImageFilterModel);
-+ d->sorter.setCategorizationMode(mode);
-+ setImageSortSettings(d->sorter);
-+}
-+
-+void ImageFilterModel::setCategorizationSortOrder(ImageSortSettings::SortOrder order)
-+{
-+ Q_D(ImageFilterModel);
-+ d->sorter.setCategorizationSortOrder(order);
-+ setImageSortSettings(d->sorter);
-+}
-+
-+void ImageFilterModel::setSortRole(ImageSortSettings::SortRole role)
-+{
-+ Q_D(ImageFilterModel);
-+ d->sorter.setSortRole(role);
-+ setImageSortSettings(d->sorter);
-+}
-+
-+void ImageFilterModel::setSortOrder(ImageSortSettings::SortOrder order)
-+{
-+ Q_D(ImageFilterModel);
-+ d->sorter.setSortOrder(order);
-+ setImageSortSettings(d->sorter);
-+}
-+
-+void ImageFilterModel::setStringTypeNatural(bool natural)
-+{
-+ Q_D(ImageFilterModel);
-+ d->sorter.setStringTypeNatural(natural);
-+ setImageSortSettings(d->sorter);
-+}
-+
-+int ImageFilterModel::compareCategories(const QModelIndex& left, const QModelIndex& right) const
-+{
-+ // source indexes
-+ Q_D(const ImageFilterModel);
-+
-+ if (!d->sorter.isCategorized())
-+ {
-+ return 0;
-+ }
-+
-+ if (!left.isValid() || !right.isValid())
-+ {
-+ return -1;
-+ }
-+
-+ const ImageInfo& leftInfo = d->imageModel->imageInfoRef(left);
-+ const ImageInfo& rightInfo = d->imageModel->imageInfoRef(right);
-+
-+ // Check grouping
-+ qlonglong leftGroupImageId = leftInfo.groupImageId();
-+ qlonglong rightGroupImageId = rightInfo.groupImageId();
-+
-+ return compareInfosCategories(leftGroupImageId == -1 ? leftInfo : ImageInfo(leftGroupImageId),
-+ rightGroupImageId == -1 ? rightInfo : ImageInfo(rightGroupImageId));
-+}
-+
-+bool ImageFilterModel::subSortLessThan(const QModelIndex& left, const QModelIndex& right) const
-+{
-+ // source indexes
-+ Q_D(const ImageFilterModel);
-+
-+ if (!left.isValid() || !right.isValid())
-+ {
-+ return true;
-+ }
-+
-+ if (left == right)
-+ {
-+ return false;
-+ }
-+
-+ const ImageInfo& leftInfo = d->imageModel->imageInfoRef(left);
-+ const ImageInfo& rightInfo = d->imageModel->imageInfoRef(right);
-+
-+ if (leftInfo == rightInfo)
-+ {
-+ return d->sorter.lessThan(left.data(ImageModel::ExtraDataRole), right.data(ImageModel::ExtraDataRole));
-+ }
-+
-+ // Check grouping
-+ qlonglong leftGroupImageId = leftInfo.groupImageId();
-+ qlonglong rightGroupImageId = rightInfo.groupImageId();
-+
-+ // Either no grouping (-1), or same group image, or same image
-+ if (leftGroupImageId == rightGroupImageId)
-+ {
-+ return infosLessThan(leftInfo, rightInfo);
-+ }
-+
-+ // We have grouping to handle
-+
-+ // Is one grouped on the other? Sort behind leader.
-+ if (leftGroupImageId == rightInfo.id())
-+ {
-+ return false;
-+ }
-+ if (rightGroupImageId == leftInfo.id())
-+ {
-+ return true;
-+ }
-+
-+ // Use the group leader for sorting
-+ return infosLessThan(leftGroupImageId == -1 ? leftInfo : ImageInfo(leftGroupImageId),
-+ rightGroupImageId == -1 ? rightInfo : ImageInfo(rightGroupImageId));
-+}
-+
-+int ImageFilterModel::compareInfosCategories(const ImageInfo& left, const ImageInfo& right) const
-+{
-+ // Note: reimplemented in ImageAlbumFilterModel
-+ Q_D(const ImageFilterModel);
-+ return d->sorter.compareCategories(left, right);
-+}
-+
-+// Feel free to optimize. QString::number is 3x slower.
-+static inline QString fastNumberToString(int id)
-+{
-+ const int size = sizeof(int) * 2;
-+ char c[size+1];
-+ c[size] = '\0';
-+ char* p = c;
-+ int number = id;
-+
-+ for (int i=0; i<size; ++i)
-+ {
-+ *p = 'a' + (number & 0xF);
-+ number >>= 4;
-+ ++p;
-+ }
-+
-+ return QString::fromLatin1(c);
-+}
-+
-+QString ImageFilterModel::categoryIdentifier(const ImageInfo& i) const
-+{
-+ Q_D(const ImageFilterModel);
-+
-+ if (!d->sorter.isCategorized())
-+ {
-+ return QString();
-+ }
-+
-+ qlonglong groupedImageId = i.groupImageId();
-+ ImageInfo info = groupedImageId == -1 ? i : ImageInfo(groupedImageId);
-+
-+ switch (d->sorter.categorizationMode)
-+ {
-+ case ImageSortSettings::NoCategories:
-+ return QString();
-+ case ImageSortSettings::OneCategory:
-+ return QString();
-+ case ImageSortSettings::CategoryByAlbum:
-+ return fastNumberToString(info.albumId());
-+ case ImageSortSettings::CategoryByFormat:
-+ return info.format();
-+ default:
-+ return QString();
-+ }
-+}
-+
-+bool ImageFilterModel::infosLessThan(const ImageInfo& left, const ImageInfo& right) const
-+{
-+ Q_D(const ImageFilterModel);
-+ return d->sorter.lessThan(left, right);
-+}
-+
-+// -------------- Watching changes -----------------------------------------------------------------
-+
-+void ImageFilterModel::slotImageTagChange(const ImageTagChangeset& changeset)
-+{
-+ Q_D(ImageFilterModel);
-+
-+ if (!d->imageModel || d->imageModel->isEmpty())
-+ {
-+ return;
-+ }
-+
-+ // already scheduled to re-filter?
-+ if (d->updateFilterTimer->isActive())
-+ {
-+ return;
-+ }
-+
-+ // do we filter at all?
-+ if (!d->versionFilter.isFilteringByTags() &&
-+ !d->filter.isFilteringByTags() &&
-+ !d->filter.isFilteringByText())
-+ {
-+ return;
-+ }
-+
-+ // is one of our images affected?
-+ foreach(const qlonglong& id, changeset.ids())
-+ {
-+ // if one matching image id is found, trigger a refresh
-+ if (d->imageModel->hasImage(id))
-+ {
-+ d->updateFilterTimer->start();
-+ return;
-+ }
-+ }
-+}
-+
-+void ImageFilterModel::slotImageChange(const ImageChangeset& changeset)
-+{
-+ Q_D(ImageFilterModel);
-+
-+ if (!d->imageModel || d->imageModel->isEmpty())
-+ {
-+ return;
-+ }
-+
-+ // already scheduled to re-filter?
-+ if (d->updateFilterTimer->isActive())
-+ {
-+ return;
-+ }
-+
-+ // is one of the values affected that we filter or sort by?
-+ DatabaseFields::Set set = changeset.changes();
-+ bool sortAffected = (set & d->sorter.watchFlags());
-+ bool filterAffected = (set & d->filter.watchFlags()) || (set & d->groupFilter.watchFlags());
-+
-+ if (!sortAffected && !filterAffected)
-+ {
-+ return;
-+ }
-+
-+ // is one of our images affected?
-+ bool imageAffected = false;
-+
-+ foreach(const qlonglong& id, changeset.ids())
-+ {
-+ // if one matching image id is found, trigger a refresh
-+ if (d->imageModel->hasImage(id))
-+ {
-+ imageAffected = true;
-+ break;
-+ }
-+ }
-+
-+ if (!imageAffected)
-+ {
-+ return;
-+ }
-+
-+ if (filterAffected)
-+ {
-+ d->updateFilterTimer->start();
-+ }
-+ else
-+ {
-+ invalidate(); // just resort, reuse filter results
-+ }
-+}
-+
-+// -------------------------------------------------------------------------------------------------------
-+
-+NoDuplicatesImageFilterModel::NoDuplicatesImageFilterModel(QObject* parent)
-+ : ImageSortFilterModel(parent)
-+{
-+}
-+
-+bool NoDuplicatesImageFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
-+{
-+ QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
-+
-+ if (index.data(ImageModel::ExtraDataDuplicateCount).toInt() <= 1)
-+ {
-+ return true;
-+ }
-+
-+ QModelIndex previousIndex = sourceModel()->index(source_row - 1, 0, source_parent);
-+
-+ if (!previousIndex.isValid())
-+ {
-+ return true;
-+ }
-+
-+ if (sourceImageModel()->imageId(mapFromDirectSourceToSourceImageModel(index)) == sourceImageModel()->imageId(mapFromDirectSourceToSourceImageModel(previousIndex)))
-+ {
-+ return false;
-+ }
-+ return true;
-+}
-+
-+/*
-+void NoDuplicatesImageFilterModel::setSourceModel(QAbstractItemModel* model)
-+{
-+ if (sourceModel())
-+ {
-+ }
-+
-+ ImageSortFilterModel::setSourceModel(model);
-+
-+ if (sourceModel())
-+ {
-+ connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
-+ this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)));
-+ }
-+}
-+
-+void NoDuplicatesImageFilterModel::slotRowsAboutToBeRemoved(const QModelIndex& parent, int begin, int end)
-+{
-+ bool needInvalidate = false;
-+
-+ for (int i = begin; i<=end; ++i)
-+ {
-+ QModelIndex index = sourceModel()->index(i, 0, parent);
-+
-+ // filtered out by us?
-+ if (!mapFromSource(index).isValid())
-+ {
-+ continue;
-+ }
-+
-+ QModelIndex sourceIndex = mapFromDirectSourceToSourceImageModel(index);
-+ qlonglong id = sourceImageModel()->imageId(sourceIndex);
-+
-+ if (sourceImageModel()->numberOfIndexesForImageId(id) > 1)
-+ {
-+ needInvalidate = true;
-+ }
-+ }
-+}*/
-+
-+} // namespace Digikam
-diff --git a/libs/database/models/imagefiltermodel.h b/libs/database/models/imagefiltermodel.h
-new file mode 100644
-index 0000000..d131b3e
---- /dev/null
-+++ b/libs/database/models/imagefiltermodel.h
-@@ -0,0 +1,299 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Qt item model for database entries
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ * Copyright (C) 2011 by Gilles Caulier <caulier dot gilles at gmail dot com>
-+ * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-+ * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-+ * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 IMAGEFILTERMODEL_H
-+#define IMAGEFILTERMODEL_H
-+
-+// Local includes
-+
-+#include "dcategorizedsortfilterproxymodel.h"
-+#include "textfilter.h"
-+#include "imagefiltersettings.h"
-+#include "imagemodel.h"
-+#include "imagesortsettings.h"
-+#include "digikam_export.h"
-+
-+namespace Digikam
-+{
-+
-+class ImageChangeset;
-+class ImageFilterModel;
-+class ImageTagChangeset;
-+
-+class DIGIKAM_DATABASE_EXPORT ImageFilterModelPrepareHook
-+{
-+public:
-+
-+ virtual ~ImageFilterModelPrepareHook() {};
-+ virtual void prepare(const QVector<ImageInfo>& infos) = 0;
-+};
-+
-+// -----------------------------------------------------------------------------------------------
-+
-+class DIGIKAM_DATABASE_EXPORT ImageSortFilterModel : public DCategorizedSortFilterProxyModel
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ explicit ImageSortFilterModel(QObject* parent = 0);
-+
-+ void setSourceImageModel(ImageModel* model);
-+ ImageModel* sourceImageModel() const;
-+
-+ void setSourceFilterModel(ImageSortFilterModel* model);
-+ ImageSortFilterModel* sourceFilterModel() const;
-+
-+ QModelIndex mapToSourceImageModel(const QModelIndex& index) const;
-+ QModelIndex mapFromSourceImageModel(const QModelIndex& imagemodel_index) const;
-+ QModelIndex mapFromDirectSourceToSourceImageModel(const QModelIndex& sourceModel_index) const;
-+
-+ /// Convenience methods mapped to ImageModel.
-+ /// Mentioned indexes returned come from the source image model.
-+ QList<QModelIndex> mapListToSource(const QList<QModelIndex>& indexes) const;
-+ QList<QModelIndex> mapListFromSource(const QList<QModelIndex>& sourceIndexes) const;
-+
-+ ImageInfo imageInfo(const QModelIndex& index) const;
-+ qlonglong imageId(const QModelIndex& index) const;
-+ QList<ImageInfo> imageInfos(const QList<QModelIndex>& indexes) const;
-+ QList<qlonglong> imageIds(const QList<QModelIndex>& indexes) const;
-+
-+ QModelIndex indexForPath(const QString& filePath) const;
-+ QModelIndex indexForImageInfo(const ImageInfo& info) const;
-+ QModelIndex indexForImageId(qlonglong id) const;
-+
-+ /** Returns a list of all image infos, sorted according to this model.
-+ * If you do not need a sorted list, use ImageModel's imageInfos() method.
-+ */
-+ QList<ImageInfo> imageInfosSorted() const;
-+
-+ /// Returns this, any chained ImageFilterModel, or 0.
-+ virtual ImageFilterModel* imageFilterModel() const;
-+
-+protected:
-+
-+ /// Reimplement if needed. Called only when model shall be set as (direct) sourceModel.
-+ virtual void setDirectSourceImageModel(ImageModel* model);
-+
-+ // made protected
-+ virtual void setSourceModel(QAbstractItemModel* model);
-+
-+protected:
-+
-+ ImageSortFilterModel* m_chainedModel;
-+};
-+
-+// -----------------------------------------------------------------------------------------------
-+
-+class DIGIKAM_DATABASE_EXPORT ImageFilterModel : public ImageSortFilterModel
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ enum ImageFilterModelRoles
-+ {
-+ /// Returns the current categorization mode
-+ CategorizationModeRole = ImageModel::FilterModelRoles + 1,
-+ /// Returns the current sort order
-+ SortOrderRole = ImageModel::FilterModelRoles + 2,
-+ // / Returns the number of items in the index' category
-+ //CategoryCountRole = ImageModel::FilterModelRoles + 3,
-+ /// Returns the id of the PAlbum of the index which is used for category
-+ CategoryAlbumIdRole = ImageModel::FilterModelRoles + 3,
-+ /// Returns the format of the index which is used for category
-+ CategoryFormatRole = ImageModel::FilterModelRoles + 4,
-+ /// Returns true if the given image is a group leader, and the group is opened
-+ GroupIsOpenRole = ImageModel::FilterModelRoles + 5,
-+ ImageFilterModelPointerRole = ImageModel::FilterModelRoles + 50
-+ };
-+
-+public:
-+
-+ explicit ImageFilterModel(QObject* parent = 0);
-+ ~ImageFilterModel();
-+
-+ /** Add a hook to get added images for preparation tasks before they are added in the model */
-+ void addPrepareHook(ImageFilterModelPrepareHook* hook);
-+ void removePrepareHook(ImageFilterModelPrepareHook* hook);
-+
-+ /** Returns a set of DatabaseFields suggested to set as watch flags on the source ImageModel.
-+ * The contained flags will be those that this model can sort or filter by. */
-+ DatabaseFields::Set suggestedWatchFlags() const;
-+
-+ ImageFilterSettings imageFilterSettings() const;
-+ VersionImageFilterSettings versionImageFilterSettings() const;
-+ GroupImageFilterSettings groupImageFilterSettings() const;
-+ ImageSortSettings imageSortSettings() const;
-+
-+ // group is identified by the id of its group leader
-+ bool isGroupOpen(qlonglong group) const;
-+ bool isAllGroupsOpen() const;
-+
-+ /// Enables sending imageInfosAdded and imageInfosAboutToBeRemoved
-+ void setSendImageInfoSignals(bool sendSignals);
-+
-+ virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
-+ virtual ImageFilterModel* imageFilterModel() const;
-+
-+public Q_SLOTS:
-+
-+ /** Changes the current version image filter settings and refilters. */
-+ void setVersionImageFilterSettings(const VersionImageFilterSettings& settings);
-+
-+ /** Changes the current version image filter settings and refilters. */
-+ void setGroupImageFilterSettings(const GroupImageFilterSettings& settings);
-+
-+ /** Adjust the current ImageFilterSettings.
-+ * Equivalent to retrieving the current filter settings, adjusting the parameter
-+ * and calling setImageFilterSettings.
-+ * Provided for convenience.
-+ * It is encouraged to use setImageFilterSettings if you change more than one
-+ * parameter at a time.
-+ */
-+ void setDayFilter(const QList<QDateTime>& days);
-+ void setTagFilter(const QList<int>& includedTags, const QList<int>& excludedTags,
-+ ImageFilterSettings::MatchingCondition matchingCond, bool showUnTagged,
-+ const QList<int>& clTagIds, const QList<int>& plTagIds);
-+ void setRatingFilter(int rating, ImageFilterSettings::RatingCondition ratingCond, bool isUnratedExcluded);
-+ void setMimeTypeFilter(int mimeTypeFilter);
-+ void setGeolocationFilter(const ImageFilterSettings::GeolocationCondition& condition);
-+ void setTextFilter(const SearchTextFilterSettings& settings);
-+
-+ void setCategorizationMode(ImageSortSettings::CategorizationMode mode);
-+ void setCategorizationSortOrder(ImageSortSettings::SortOrder order);
-+ void setSortRole(ImageSortSettings::SortRole role);
-+ void setSortOrder(ImageSortSettings::SortOrder order);
-+ void setStringTypeNatural(bool natural);
-+ void setUrlWhitelist(const QList<QUrl> urlList, const QString& id);
-+ void setIdWhitelist(const QList<qlonglong>& idList, const QString& id);
-+
-+ void setVersionManagerSettings(const VersionManagerSettings& settings);
-+ void setExceptionList(const QList<qlonglong>& idlist, const QString& id);
-+
-+ void setGroupOpen(qlonglong group, bool open);
-+ void toggleGroupOpen(qlonglong group);
-+ void setAllGroupsOpen(bool open);
-+
-+ /** Changes the current image filter settings and refilters. */
-+ virtual void setImageFilterSettings(const ImageFilterSettings& settings);
-+
-+ /** Changes the current image sort settings and resorts. */
-+ virtual void setImageSortSettings(const ImageSortSettings& settings);
-+
-+Q_SIGNALS:
-+
-+ /// Signals that the set filter matches at least one index
-+ void filterMatches(bool matches);
-+
-+ /** Signals that the set text filter matches at least one entry.
-+ If no text filter is set, this signal is emitted
-+ with 'false' when filterMatches() is emitted.
-+ */
-+ void filterMatchesForText(bool matchesByText);
-+
-+ /** Emitted when the filter settings have been changed
-+ (the model may not yet have been updated)
-+ */
-+ void filterSettingsChanged(const ImageFilterSettings& settings);
-+
-+ /** These signals need to be explicitly enabled with setSendImageInfoSignals()
-+ */
-+ void imageInfosAdded(const QList<ImageInfo>& infos);
-+ void imageInfosAboutToBeRemoved(const QList<ImageInfo>& infos);
-+
-+public:
-+
-+ // Declared as public because of use in sub-classes.
-+ class ImageFilterModelPrivate;
-+
-+protected:
-+
-+ ImageFilterModelPrivate* const d_ptr;
-+
-+protected:
-+
-+ ImageFilterModel(ImageFilterModelPrivate& dd, QObject* parent);
-+
-+ virtual void setDirectSourceImageModel(ImageModel* model);
-+
-+ virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
-+
-+ virtual int compareCategories(const QModelIndex& left, const QModelIndex& right) const;
-+ virtual bool subSortLessThan(const QModelIndex& left, const QModelIndex& right) const;
-+ //virtual int categoryCount(const ImageInfo& info) const;
-+
-+ /** Reimplement to customize category sorting,
-+ * Return negative if category of left < category right,
-+ * Return 0 if left and right are in the same category, else return positive.
-+ */
-+ virtual int compareInfosCategories(const ImageInfo& left, const ImageInfo& right) const;
-+
-+ /** Reimplement to customize sorting. Do not take categories into account here.
-+ */
-+ virtual bool infosLessThan(const ImageInfo& left, const ImageInfo& right) const;
-+
-+ /** Returns a unique identifier for the category if info. The string need not be for user display.
-+ */
-+ virtual QString categoryIdentifier(const ImageInfo& info) const;
-+
-+protected Q_SLOTS:
-+
-+ void slotModelReset();
-+ void slotUpdateFilter();
-+
-+ void slotImageTagChange(const ImageTagChangeset& changeset);
-+ void slotImageChange(const ImageChangeset& changeset);
-+
-+ void slotRowsInserted(const QModelIndex& parent, int start, int end);
-+ void slotRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);
-+
-+private:
-+
-+ Q_DECLARE_PRIVATE(ImageFilterModel)
-+};
-+
-+// -----------------------------------------------------------------------------------------------------
-+
-+class DIGIKAM_DATABASE_EXPORT NoDuplicatesImageFilterModel : public ImageSortFilterModel
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ explicit NoDuplicatesImageFilterModel(QObject* parent = 0);
-+
-+protected:
-+
-+ virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
-+};
-+
-+} // namespace Digikam
-+
-+Q_DECLARE_METATYPE(Digikam::ImageFilterModel*)
-+
-+#endif // IMAGEMODEL_H
-diff --git a/libs/database/models/imagefiltermodelpriv.cpp b/libs/database/models/imagefiltermodelpriv.cpp
-new file mode 100644
-index 0000000..07d9e79
---- /dev/null
-+++ b/libs/database/models/imagefiltermodelpriv.cpp
-@@ -0,0 +1,258 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Qt item model for database entries
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-+ * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-+ * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-+ * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagefiltermodelpriv.h"
-+
-+// Local includes
-+
-+#include "digikam_debug.h"
-+#include "imagefiltermodelthreads.h"
-+
-+namespace Digikam
-+{
-+
-+ImageFilterModel::ImageFilterModelPrivate::ImageFilterModelPrivate()
-+{
-+ imageModel = 0;
-+ version = 0;
-+ lastDiscardVersion = 0;
-+ sentOut = 0;
-+ sentOutForReAdd = 0;
-+ updateFilterTimer = 0;
-+ needPrepare = false;
-+ needPrepareComments = false;
-+ needPrepareTags = false;
-+ needPrepareGroups = false;
-+ preparer = 0;
-+ filterer = 0;
-+ hasOneMatch = false;
-+ hasOneMatchForText = false;
-+
-+ setupWorkers();
-+}
-+
-+ImageFilterModel::ImageFilterModelPrivate::~ImageFilterModelPrivate()
-+{
-+ // facilitate thread stopping
-+ ++version;
-+ preparer->deactivate();
-+ filterer->deactivate();
-+ delete preparer;
-+ delete filterer;
-+}
-+
-+void ImageFilterModel::ImageFilterModelPrivate::init(ImageFilterModel* _q)
-+{
-+ q = _q;
-+
-+ updateFilterTimer = new QTimer(this);
-+ updateFilterTimer->setSingleShot(true);
-+ updateFilterTimer->setInterval(250);
-+
-+ connect(updateFilterTimer, SIGNAL(timeout()),
-+ q, SLOT(slotUpdateFilter()));
-+
-+ // inter-thread redirection
-+ qRegisterMetaType<ImageFilterModelTodoPackage>("ImageFilterModelTodoPackage");
-+}
-+
-+void ImageFilterModel::ImageFilterModelPrivate::preprocessInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ infosToProcess(infos, extraValues, true);
-+}
-+
-+void ImageFilterModel::ImageFilterModelPrivate::processAddedInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ // These have already been added, we just process them afterwards
-+ infosToProcess(infos, extraValues, false);
-+}
-+
-+void ImageFilterModel::ImageFilterModelPrivate::setupWorkers()
-+{
-+ preparer = new ImageFilterModelPreparer(this);
-+ filterer = new ImageFilterModelFilterer(this);
-+
-+ // A package in constructed in infosToProcess.
-+ // Normal flow is infosToProcess -> preparer::process -> filterer::process -> packageFinished.
-+ // If no preparation is needed, the first step is skipped.
-+ // If filter version changes, both will discard old package and send them to packageDiscarded.
-+
-+ connect(this, SIGNAL(packageToPrepare(ImageFilterModelTodoPackage)),
-+ preparer, SLOT(process(ImageFilterModelTodoPackage)));
-+
-+ connect(this, SIGNAL(packageToFilter(ImageFilterModelTodoPackage)),
-+ filterer, SLOT(process(ImageFilterModelTodoPackage)));
-+
-+ connect(preparer, SIGNAL(processed(ImageFilterModelTodoPackage)),
-+ filterer, SLOT(process(ImageFilterModelTodoPackage)));
-+
-+ connect(filterer, SIGNAL(processed(ImageFilterModelTodoPackage)),
-+ this, SLOT(packageFinished(ImageFilterModelTodoPackage)));
-+
-+ connect(preparer, SIGNAL(discarded(ImageFilterModelTodoPackage)),
-+ this, SLOT(packageDiscarded(ImageFilterModelTodoPackage)));
-+
-+ connect(filterer, SIGNAL(discarded(ImageFilterModelTodoPackage)),
-+ this, SLOT(packageDiscarded(ImageFilterModelTodoPackage)));
-+}
-+
-+void ImageFilterModel::ImageFilterModelPrivate::infosToProcess(const QList<ImageInfo>& infos)
-+{
-+ infosToProcess(infos, QList<QVariant>(), false);
-+}
-+
-+void ImageFilterModel::ImageFilterModelPrivate::infosToProcess(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues, bool forReAdd)
-+{
-+ if (infos.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ filterer->schedule();
-+
-+ if (needPrepare)
-+ {
-+ preparer->schedule();
-+ }
-+
-+ Q_ASSERT(extraValues.isEmpty() || infos.size() == extraValues.size());
-+
-+ // prepare and filter in chunks
-+ const int size = infos.size();
-+ const int maxChunkSize = needPrepare ? PrepareChunkSize : FilterChunkSize;
-+ const bool hasExtraValues = !extraValues.isEmpty();
-+ QList<ImageInfo>::const_iterator it = infos.constBegin(), end;
-+ QList<QVariant>::const_iterator xit = extraValues.constBegin(), xend;
-+ int index = 0;
-+ QVector<ImageInfo> infoVector;
-+ QVector<QVariant> extraValueVector;
-+
-+ while (it != infos.constEnd())
-+ {
-+ const int chunkSize = qMin(maxChunkSize, size - index);
-+ infoVector.resize(chunkSize);
-+ end = it + chunkSize;
-+ qCopy(it, end, infoVector.begin());
-+
-+ if (hasExtraValues)
-+ {
-+ extraValueVector.resize(chunkSize);
-+ xend = xit + chunkSize;
-+ qCopy(xit, xend, extraValueVector.begin());
-+ xit = xend;
-+ }
-+
-+ it = end;
-+ index += chunkSize;
-+
-+ ++sentOut;
-+
-+ if (forReAdd)
-+ {
-+ ++sentOutForReAdd;
-+ }
-+
-+ if (needPrepare)
-+ {
-+ emit packageToPrepare(ImageFilterModelTodoPackage(infoVector, extraValueVector, version, forReAdd));
-+ }
-+ else
-+ {
-+ emit packageToFilter(ImageFilterModelTodoPackage(infoVector, extraValueVector, version, forReAdd));
-+ }
-+ }
-+}
-+
-+void ImageFilterModel::ImageFilterModelPrivate::packageFinished(const ImageFilterModelTodoPackage& package)
-+{
-+ // check if it got discarded on the journey
-+ if (package.version != version)
-+ {
-+ packageDiscarded(package);
-+ return;
-+ }
-+
-+ // incorporate result
-+ QHash<qlonglong, bool>::const_iterator it = package.filterResults.constBegin();
-+
-+ for (; it != package.filterResults.constEnd(); ++it)
-+ {
-+ filterResults.insert(it.key(), it.value());
-+ }
-+
-+ // re-add if necessary
-+ if (package.isForReAdd)
-+ {
-+ emit reAddImageInfos(package.infos.toList(), package.extraValues.toList());
-+
-+ if (sentOutForReAdd == 1) // last package
-+ {
-+ emit reAddingFinished();
-+ }
-+ }
-+
-+ // decrement counters
-+ --sentOut;
-+
-+ if (package.isForReAdd)
-+ {
-+ --sentOutForReAdd;
-+ }
-+
-+ // If all packages have returned, filtered and readded, and no more are expected,
-+ // and there is need to tell the filter result to the view, do that
-+ if (sentOut == 0 && sentOutForReAdd == 0 && !imageModel->isRefreshing())
-+ {
-+ q->invalidate(); // use invalidate, not invalidateFilter only. Sorting may have changed as well.
-+ emit (q->filterMatches(hasOneMatch));
-+ emit (q->filterMatchesForText(hasOneMatchForText));
-+ filterer->deactivate();
-+ preparer->deactivate();
-+ }
-+}
-+
-+void ImageFilterModel::ImageFilterModelPrivate::packageDiscarded(const ImageFilterModelTodoPackage& package)
-+{
-+ // Either, the model was reset, or the filter changed
-+ // In the former case throw all away, in the latter case, recycle
-+ if (package.version > lastDiscardVersion)
-+ {
-+ // Recycle packages: Send again with current version
-+ // Do not increment sentOut or sentOutForReAdd here: it was not decremented!
-+
-+ if (needPrepare)
-+ {
-+ emit packageToPrepare(ImageFilterModelTodoPackage(package.infos, package.extraValues, version, package.isForReAdd));
-+ }
-+ else
-+ {
-+ emit packageToFilter(ImageFilterModelTodoPackage(package.infos, package.extraValues, version, package.isForReAdd));
-+ }
-+ }
-+}
-+
-+} // namespace Digikam
-diff --git a/libs/database/models/imagefiltermodelpriv.h b/libs/database/models/imagefiltermodelpriv.h
-new file mode 100644
-index 0000000..a9e3f22
---- /dev/null
-+++ b/libs/database/models/imagefiltermodelpriv.h
-@@ -0,0 +1,159 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-11
-+ * Description : Qt item model for database entries - private shared header
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ *
-+ * 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 IMAGEFILTERMODELPRIV_H
-+#define IMAGEFILTERMODELPRIV_H
-+
-+// Qt includes
-+
-+#include <QHash>
-+#include <QMutex>
-+#include <QMutexLocker>
-+#include <QSet>
-+#include <QThread>
-+#include <QTimer>
-+#include <QWaitCondition>
-+
-+// Local includes
-+
-+#include "imageinfo.h"
-+#include "imagefiltermodel.h"
-+
-+#include "digikam_export.h"
-+// Yes, we need the EXPORT macro in a private header because
-+// this private header is shared across binary objects.
-+// This does NOT make this classes here any more public!
-+
-+namespace Digikam
-+{
-+
-+const int PrepareChunkSize = 101;
-+const int FilterChunkSize = 2001;
-+
-+class ImageFilterModelTodoPackage
-+{
-+public:
-+
-+ ImageFilterModelTodoPackage()
-+ : version(0), isForReAdd(false)
-+ {
-+ }
-+
-+ ImageFilterModelTodoPackage(const QVector<ImageInfo>& infos, const QVector<QVariant>& extraValues, int version, bool isForReAdd)
-+ : infos(infos), extraValues(extraValues), version(version), isForReAdd(isForReAdd)
-+ {
-+ }
-+
-+ QVector<ImageInfo> infos;
-+ QVector<QVariant> extraValues;
-+ unsigned int version;
-+ bool isForReAdd;
-+ QHash<qlonglong, bool> filterResults;
-+};
-+
-+// ------------------------------------------------------------------------------------------------
-+
-+class ImageFilterModelPreparer;
-+class ImageFilterModelFilterer;
-+
-+class DIGIKAM_DATABASE_EXPORT ImageFilterModel::ImageFilterModelPrivate : public QObject
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ ImageFilterModelPrivate();
-+ ~ImageFilterModelPrivate();
-+
-+ void init(ImageFilterModel* q);
-+ void setupWorkers();
-+ void infosToProcess(const QList<ImageInfo>& infos);
-+ void infosToProcess(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues, bool forReAdd = true);
-+
-+public:
-+
-+ ImageFilterModel* q;
-+
-+ ImageModel* imageModel;
-+
-+ ImageFilterSettings filter;
-+ ImageSortSettings sorter;
-+ VersionImageFilterSettings versionFilter;
-+ GroupImageFilterSettings groupFilter;
-+
-+ volatile unsigned int version;
-+ unsigned int lastDiscardVersion;
-+ unsigned int lastFilteredVersion;
-+ int sentOut;
-+ int sentOutForReAdd;
-+
-+ QTimer* updateFilterTimer;
-+
-+ bool needPrepare;
-+ bool needPrepareComments;
-+ bool needPrepareTags;
-+ bool needPrepareGroups;
-+
-+ QMutex mutex;
-+ ImageFilterSettings filterCopy;
-+ VersionImageFilterSettings versionFilterCopy;
-+ GroupImageFilterSettings groupFilterCopy;
-+ ImageFilterModelPreparer* preparer;
-+ ImageFilterModelFilterer* filterer;
-+
-+ QHash<qlonglong, bool> filterResults;
-+ bool hasOneMatch;
-+ bool hasOneMatchForText;
-+
-+ QList<ImageFilterModelPrepareHook*> prepareHooks;
-+
-+/*
-+ QHash<int, QSet<qlonglong> > categoryCountHashInt;
-+ QHash<QString, QSet<qlonglong> > categoryCountHashString;
-+
-+public:
-+
-+ void cacheCategoryCount(int id, qlonglong imageid) const
-+ { const_cast<ImageFilterModelPrivate*>(this)->categoryCountHashInt[id].insert(imageid); }
-+ void cacheCategoryCount(const QString& id, qlonglong imageid) const
-+ { const_cast<ImageFilterModelPrivate*>(this)->categoryCountHashString[id].insert(imageid); }
-+*/
-+
-+public Q_SLOTS:
-+
-+ void preprocessInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+ void processAddedInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+ void packageFinished(const ImageFilterModelTodoPackage& package);
-+ void packageDiscarded(const ImageFilterModelTodoPackage& package);
-+
-+Q_SIGNALS:
-+
-+ void packageToPrepare(const ImageFilterModelTodoPackage& package);
-+ void packageToFilter(const ImageFilterModelTodoPackage& package);
-+ void reAddImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+ void reAddingFinished();
-+};
-+
-+} // namespace Digikam
-+
-+#endif // IMAGEFILTERMODELPRIV_H
-diff --git a/libs/database/models/imagefiltermodelthreads.cpp b/libs/database/models/imagefiltermodelthreads.cpp
-new file mode 100644
-index 0000000..aa5c462
---- /dev/null
-+++ b/libs/database/models/imagefiltermodelthreads.cpp
-@@ -0,0 +1,40 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Qt item model for database entries
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-+ * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-+ * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-+ * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagefiltermodel.h"
-+#include "imagefiltermodelpriv.h"
-+#include "imagefiltermodelthreads.h"
-+
-+namespace Digikam
-+{
-+
-+ImageFilterModelWorker::ImageFilterModelWorker(ImageFilterModel::ImageFilterModelPrivate* const d)
-+ : d(d)
-+{
-+}
-+
-+} // namespace Digikam
-diff --git a/libs/database/models/imagefiltermodelthreads.h b/libs/database/models/imagefiltermodelthreads.h
-new file mode 100644
-index 0000000..83fa987
---- /dev/null
-+++ b/libs/database/models/imagefiltermodelthreads.h
-@@ -0,0 +1,100 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-11
-+ * Description : Qt item model for database entries - private header
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ *
-+ * 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 IMAGEFILTERMODELTHREADS_H
-+#define IMAGEFILTERMODELTHREADS_H
-+
-+// Qt includes
-+
-+#include <QThread>
-+
-+// Local includes
-+
-+#include "digikam_export.h"
-+#include "workerobject.h"
-+
-+namespace Digikam
-+{
-+
-+class DIGIKAM_DATABASE_EXPORT ImageFilterModelWorker : public WorkerObject
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ explicit ImageFilterModelWorker(ImageFilterModel::ImageFilterModelPrivate* const d);
-+
-+ bool checkVersion(const ImageFilterModelTodoPackage& package)
-+ {
-+ return d->version == package.version;
-+ }
-+
-+public Q_SLOTS:
-+
-+ virtual void process(ImageFilterModelTodoPackage package) = 0;
-+
-+Q_SIGNALS:
-+
-+ void processed(const ImageFilterModelTodoPackage& package);
-+ void discarded(const ImageFilterModelTodoPackage& package);
-+
-+protected:
-+
-+ ImageFilterModel::ImageFilterModelPrivate* d;
-+};
-+
-+// -----------------------------------------------------------------------------------------
-+
-+class DIGIKAM_DATABASE_EXPORT ImageFilterModelPreparer : public ImageFilterModelWorker
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ explicit ImageFilterModelPreparer(ImageFilterModel::ImageFilterModelPrivate* const d)
-+ : ImageFilterModelWorker(d)
-+ {
-+ }
-+
-+ void process(ImageFilterModelTodoPackage package);
-+};
-+
-+// ----------------------------------------------------------------------------------------
-+
-+class DIGIKAM_DATABASE_EXPORT ImageFilterModelFilterer : public ImageFilterModelWorker
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ explicit ImageFilterModelFilterer(ImageFilterModel::ImageFilterModelPrivate* const d)
-+ : ImageFilterModelWorker(d)
-+ {
-+ }
-+
-+ void process(ImageFilterModelTodoPackage package);
-+};
-+
-+} // namespace Digikam
-+
-+#endif // IMAGEFILTERMODELTHREADS_H
-diff --git a/libs/database/models/imagefiltersettings.cpp b/libs/database/models/imagefiltersettings.cpp
-new file mode 100644
-index 0000000..b61e7f9
---- /dev/null
-+++ b/libs/database/models/imagefiltersettings.cpp
-@@ -0,0 +1,952 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Filter values for use with ImageFilterModel
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-+ * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-+ * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-+ * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagefiltersettings.h"
-+
-+// C++ includes
-+
-+#include <cmath>
-+
-+// Qt includes
-+
-+#include <QDateTime>
-+
-+// Local includes
-+
-+#include "digikam_debug.h"
-+#include "coredbfields.h"
-+#include "digikam_globals.h"
-+#include "imageinfo.h"
-+#include "tagscache.h"
-+#include "versionmanagersettings.h"
-+
-+namespace Digikam
-+{
-+
-+ImageFilterSettings::ImageFilterSettings()
-+{
-+ m_untaggedFilter = false;
-+ m_isUnratedExcluded = false;
-+ m_ratingFilter = 0;
-+ m_mimeTypeFilter = MimeFilter::AllFiles;
-+ m_ratingCond = GreaterEqualCondition;
-+ m_matchingCond = OrCondition;
-+ m_geolocationCondition = GeolocationNoFilter;
-+}
-+
-+DatabaseFields::Set ImageFilterSettings::watchFlags() const
-+{
-+ DatabaseFields::Set set;
-+
-+ if (isFilteringByDay())
-+ {
-+ set |= DatabaseFields::CreationDate;
-+ }
-+
-+ if (isFilteringByText())
-+ {
-+ set |= DatabaseFields::Name;
-+ set |= DatabaseFields::Comment;
-+ }
-+
-+ if (isFilteringByRating())
-+ {
-+ set |= DatabaseFields::Rating;
-+ }
-+
-+ if (isFilteringByTypeMime())
-+ {
-+ set |= DatabaseFields::Category;
-+ set |= DatabaseFields::Format;
-+ }
-+
-+ if (isFilteringByGeolocation())
-+ {
-+ set |= DatabaseFields::ImagePositionsAll;
-+ }
-+
-+ if (isFilteringByColorLabels())
-+ {
-+ set |= DatabaseFields::ColorLabel;
-+ }
-+
-+ if (isFilteringByPickLabels())
-+ {
-+ set |= DatabaseFields::PickLabel;
-+ }
-+
-+ return set;
-+}
-+
-+bool ImageFilterSettings::isFilteringByDay() const
-+{
-+ if (!m_dayFilter.isEmpty())
-+ {
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+bool ImageFilterSettings::isFilteringByTags() const
-+{
-+ if (!m_includeTagFilter.isEmpty() || !m_excludeTagFilter.isEmpty() || m_untaggedFilter)
-+ {
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+bool ImageFilterSettings::isFilteringByColorLabels() const
-+{
-+ if (!m_colorLabelTagFilter.isEmpty())
-+ {
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+bool ImageFilterSettings::isFilteringByPickLabels() const
-+{
-+ if (!m_pickLabelTagFilter.isEmpty())
-+ {
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+bool ImageFilterSettings::isFilteringByText() const
-+{
-+ if (!m_textFilterSettings.text.isEmpty())
-+ {
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+bool ImageFilterSettings::isFilteringByTypeMime() const
-+{
-+ if (m_mimeTypeFilter != MimeFilter::AllFiles)
-+ {
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+bool ImageFilterSettings::isFilteringByGeolocation() const
-+{
-+ return (m_geolocationCondition != GeolocationNoFilter);
-+}
-+
-+bool ImageFilterSettings::isFilteringByRating() const
-+{
-+ if (m_ratingFilter != 0 || m_ratingCond != GreaterEqualCondition || m_isUnratedExcluded)
-+ {
-+ return true;
-+ }
-+
-+ return false;
-+}
-+
-+bool ImageFilterSettings::isFilteringInternally() const
-+{
-+ return (isFiltering() || !m_urlWhitelists.isEmpty() || !m_idWhitelists.isEmpty());
-+}
-+
-+bool ImageFilterSettings::isFiltering() const
-+{
-+ return isFilteringByDay() ||
-+ isFilteringByTags() ||
-+ isFilteringByText() ||
-+ isFilteringByRating() ||
-+ isFilteringByTypeMime() ||
-+ isFilteringByColorLabels() ||
-+ isFilteringByPickLabels() ||
-+ isFilteringByGeolocation();
-+}
-+
-+void ImageFilterSettings::setDayFilter(const QList<QDateTime>& days)
-+{
-+ m_dayFilter.clear();
-+
-+ for (QList<QDateTime>::const_iterator it = days.constBegin(); it != days.constEnd(); ++it)
-+ {
-+ m_dayFilter.insert(*it, true);
-+ }
-+}
-+
-+void ImageFilterSettings::setTagFilter(const QList<int>& includedTags,
-+ const QList<int>& excludedTags,
-+ MatchingCondition matchingCondition,
-+ bool showUnTagged,
-+ const QList<int>& clTagIds,
-+ const QList<int>& plTagIds)
-+{
-+ m_includeTagFilter = includedTags;
-+ m_excludeTagFilter = excludedTags;
-+ m_matchingCond = matchingCondition;
-+ m_untaggedFilter = showUnTagged;
-+ m_colorLabelTagFilter = clTagIds;
-+ m_pickLabelTagFilter = plTagIds;
-+}
-+
-+void ImageFilterSettings::setRatingFilter(int rating, RatingCondition ratingCondition, bool isUnratedExcluded)
-+{
-+ m_ratingFilter = rating;
-+ m_ratingCond = ratingCondition;
-+ m_isUnratedExcluded = isUnratedExcluded;
-+}
-+
-+void ImageFilterSettings::setMimeTypeFilter(int mime)
-+{
-+ m_mimeTypeFilter = (MimeFilter::TypeMimeFilter)mime;
-+}
-+
-+void ImageFilterSettings::setGeolocationFilter(const GeolocationCondition& condition)
-+{
-+ m_geolocationCondition = condition;
-+}
-+
-+void ImageFilterSettings::setTextFilter(const SearchTextFilterSettings& settings)
-+{
-+ m_textFilterSettings = settings;
-+}
-+
-+void ImageFilterSettings::setTagNames(const QHash<int, QString>& hash)
-+{
-+ m_tagNameHash = hash;
-+}
-+
-+void ImageFilterSettings::setAlbumNames(const QHash<int, QString>& hash)
-+{
-+ m_albumNameHash = hash;
-+}
-+
-+void ImageFilterSettings::setUrlWhitelist(const QList<QUrl>& urlList, const QString& id)
-+{
-+ if (urlList.isEmpty())
-+ {
-+ m_urlWhitelists.remove(id);
-+ }
-+ else
-+ {
-+ m_urlWhitelists.insert(id, urlList);
-+ }
-+}
-+
-+void ImageFilterSettings::setIdWhitelist(const QList<qlonglong>& idList, const QString& id)
-+{
-+ if (idList.isEmpty())
-+ {
-+ m_idWhitelists.remove(id);
-+ }
-+ else
-+ {
-+ m_idWhitelists.insert(id, idList);
-+ }
-+}
-+
-+template <class ContainerA, class ContainerB>
-+bool containsAnyOf(const ContainerA& listA, const ContainerB& listB)
-+{
-+ foreach (const typename ContainerA::value_type& a, listA)
-+ {
-+ if (listB.contains(a))
-+ {
-+ return true;
-+ }
-+ }
-+ return false;
-+}
-+
-+template <class ContainerA, typename Value, class ContainerB>
-+bool containsNoneOfExcept(const ContainerA& list, const ContainerB& noneOfList, const Value& exception)
-+{
-+ foreach (const typename ContainerB::value_type& n, noneOfList)
-+ {
-+ if (n != exception && list.contains(n))
-+ {
-+ return false;
-+ }
-+ }
-+ return true;
-+}
-+
-+bool ImageFilterSettings::matches(const ImageInfo& info, bool* const foundText) const
-+{
-+ if (foundText)
-+ {
-+ *foundText = false;
-+ }
-+
-+ if (!isFilteringInternally())
-+ {
-+ return true;
-+ }
-+
-+ bool match = false;
-+
-+ if (!m_includeTagFilter.isEmpty() || !m_excludeTagFilter.isEmpty())
-+ {
-+ QList<int> tagIds = info.tagIds();
-+ QList<int>::const_iterator it;
-+
-+ match = m_includeTagFilter.isEmpty();
-+
-+ if (m_matchingCond == OrCondition)
-+ {
-+ for (it = m_includeTagFilter.begin(); it != m_includeTagFilter.end(); ++it)
-+ {
-+ if (tagIds.contains(*it))
-+ {
-+ match = true;
-+ break;
-+ }
-+ }
-+
-+ match |= (m_untaggedFilter && tagIds.isEmpty());
-+ }
-+ else // AND matching condition...
-+ {
-+ // m_untaggedFilter and non-empty tag filter, combined with AND, is logically no match
-+ if (!m_untaggedFilter)
-+ {
-+ for (it = m_includeTagFilter.begin(); it != m_includeTagFilter.end(); ++it)
-+ {
-+ if (!tagIds.contains(*it))
-+ {
-+ break;
-+ }
-+ }
-+
-+ if (it == m_includeTagFilter.end())
-+ {
-+ match = true;
-+ }
-+ }
-+ }
-+
-+ for (it = m_excludeTagFilter.begin(); it != m_excludeTagFilter.end(); ++it)
-+ {
-+ if (tagIds.contains(*it))
-+ {
-+ match = false;
-+ break;
-+ }
-+ }
-+ }
-+ else if (m_untaggedFilter)
-+ {
-+ match = !TagsCache::instance()->containsPublicTags(info.tagIds());
-+ }
-+ else
-+ {
-+ match = true;
-+ }
-+
-+ //-- Filter by pick labels ------------------------------------------------
-+
-+ if (!m_pickLabelTagFilter.isEmpty())
-+ {
-+ QList<int> tagIds = info.tagIds();
-+ bool matchPL = false;
-+
-+ if (containsAnyOf(m_pickLabelTagFilter, tagIds))
-+ {
-+ matchPL = true;
-+ }
-+ else if (!matchPL)
-+ {
-+ int noPickLabelTagId = TagsCache::instance()->tagForPickLabel(NoPickLabel);
-+
-+ if (m_pickLabelTagFilter.contains(noPickLabelTagId))
-+ {
-+ // Searching for "has no ColorLabel" requires special handling:
-+ // Scan that the tag ids contains none of the ColorLabel tags, except maybe the NoColorLabel tag
-+ matchPL = containsNoneOfExcept(tagIds, TagsCache::instance()->pickLabelTags(), noPickLabelTagId);
-+ }
-+ }
-+
-+ match &= matchPL;
-+ }
-+
-+ //-- Filter by color labels ------------------------------------------------
-+
-+ if (!m_colorLabelTagFilter.isEmpty())
-+ {
-+ QList<int> tagIds = info.tagIds();
-+ bool matchCL = false;
-+
-+ if (containsAnyOf(m_colorLabelTagFilter, tagIds))
-+ {
-+ matchCL = true;
-+ }
-+ else if (!matchCL)
-+ {
-+ int noColorLabelTagId = TagsCache::instance()->tagForColorLabel(NoColorLabel);
-+
-+ if (m_colorLabelTagFilter.contains(noColorLabelTagId))
-+ {
-+ // Searching for "has no ColorLabel" requires special handling:
-+ // Scan that the tag ids contains none of the ColorLabel tags, except maybe the NoColorLabel tag
-+ matchCL = containsNoneOfExcept(tagIds, TagsCache::instance()->colorLabelTags(), noColorLabelTagId);
-+ }
-+ }
-+
-+ match &= matchCL;
-+ }
-+
-+ //-- Filter by date -----------------------------------------------------------
-+
-+ if (!m_dayFilter.isEmpty())
-+ {
-+ match &= m_dayFilter.contains(QDateTime(info.dateTime().date(), QTime()));
-+ }
-+
-+ //-- Filter by rating ---------------------------------------------------------
-+
-+ if (m_ratingFilter >= 0)
-+ {
-+ // for now we treat -1 (no rating) just like a rating of 0.
-+ int rating = info.rating();
-+
-+ if (rating == -1)
-+ {
-+ rating = 0;
-+ }
-+
-+ if(m_isUnratedExcluded && rating == 0)
-+ {
-+ match = false;
-+ }
-+ else
-+ {
-+ if (m_ratingCond == GreaterEqualCondition)
-+ {
-+ // If the rating is not >=, i.e it is <, then it does not match.
-+ if (rating < m_ratingFilter)
-+ {
-+ match = false;
-+ }
-+ }
-+ else if (m_ratingCond == EqualCondition)
-+ {
-+ // If the rating is not =, i.e it is !=, then it does not match.
-+ if (rating != m_ratingFilter)
-+ {
-+ match = false;
-+ }
-+ }
-+ else
-+ {
-+ // If the rating is not <=, i.e it is >, then it does not match.
-+ if (rating > m_ratingFilter)
-+ {
-+ match = false;
-+ }
-+ }
-+ }
-+ }
-+
-+ // -- Filter by mime type -----------------------------------------------------
-+
-+ switch (m_mimeTypeFilter)
-+ {
-+ // info.format is a standardized string: Only one possibility per mime type
-+ case MimeFilter::ImageFiles:
-+ {
-+ if (info.category() != DatabaseItem::Image)
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ case MimeFilter::JPGFiles:
-+ {
-+ if (info.format() != QLatin1String("JPG"))
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ case MimeFilter::PNGFiles:
-+ {
-+ if (info.format() != QLatin1String("PNG"))
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ case MimeFilter::TIFFiles:
-+ {
-+ if (info.format() != QLatin1String("TIFF"))
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ case MimeFilter::DNGFiles:
-+ {
-+ if (info.format() != QLatin1String("RAW-DNG"))
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ case MimeFilter::NoRAWFiles:
-+ {
-+ if (info.format().startsWith(QLatin1String("RAW")))
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ case MimeFilter::RAWFiles:
-+ {
-+ if (!info.format().startsWith(QLatin1String("RAW")))
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ case MimeFilter::MoviesFiles:
-+ {
-+ if (info.category() != DatabaseItem::Video)
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ case MimeFilter::AudioFiles:
-+ {
-+ if (info.category() != DatabaseItem::Audio)
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ case MimeFilter::RasterFiles:
-+ {
-+ if (info.format() != QLatin1String("PSD") && // Adobe Photoshop Document
-+ info.format() != QLatin1String("PSB") && // Adobe Photoshop Big
-+ info.format() != QLatin1String("XCF") && // Gimp
-+ info.format() != QLatin1String("KRA") && // Krita
-+ info.format() != QLatin1String("ORA") // Open Raster
-+ )
-+ {
-+ match = false;
-+ }
-+
-+ break;
-+ }
-+ default:
-+ {
-+ // All Files: do nothing...
-+ break;
-+ }
-+ }
-+
-+ //-- Filter by geolocation ----------------------------------------------------
-+
-+ if (m_geolocationCondition!=GeolocationNoFilter)
-+ {
-+ if (m_geolocationCondition==GeolocationNoCoordinates)
-+ {
-+ if (info.hasCoordinates())
-+ {
-+ match = false;
-+ }
-+ }
-+ else if (m_geolocationCondition==GeolocationHasCoordinates)
-+ {
-+ if (!info.hasCoordinates())
-+ {
-+ match = false;
-+ }
-+ }
-+ }
-+
-+ //-- Filter by text -----------------------------------------------------------
-+
-+ if (!m_textFilterSettings.text.isEmpty())
-+ {
-+ bool textMatch = false;
-+
-+ // Image name
-+ if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImageName &&
-+ info.name().contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-+ {
-+ textMatch = true;
-+ }
-+
-+ // Image title
-+ if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImageTitle &&
-+ info.title().contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-+ {
-+ textMatch = true;
-+ }
-+
-+ // Image comment
-+ if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImageComment &&
-+ info.comment().contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-+ {
-+ textMatch = true;
-+ }
-+
-+ // Tag names
-+ foreach(int id, info.tagIds())
-+ {
-+ if (m_textFilterSettings.textFields & SearchTextFilterSettings::TagName &&
-+ m_tagNameHash.value(id).contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-+ {
-+ textMatch = true;
-+ }
-+ }
-+
-+ // Album names
-+ if (m_textFilterSettings.textFields & SearchTextFilterSettings::AlbumName &&
-+ m_albumNameHash.value(info.albumId()).contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-+ {
-+ textMatch = true;
-+ }
-+
-+ // Image Aspect Ratio
-+ if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImageAspectRatio)
-+ {
-+ QRegExp expRatio (QLatin1String("^\\d+:\\d+$"));
-+ QRegExp expFloat (QLatin1String("^\\d+(.\\d+)?$"));
-+
-+ if (expRatio.indexIn(m_textFilterSettings.text) > -1 && m_textFilterSettings.text.contains(QRegExp(QLatin1String(":\\d+"))))
-+ {
-+ QString trimmedTextFilterSettingsText = m_textFilterSettings.text;
-+ QStringList numberStringList = trimmedTextFilterSettingsText.split(QLatin1String(":"), QString::SkipEmptyParts);
-+
-+ if (numberStringList.length() == 2)
-+ {
-+ QString numString = (QString)numberStringList.at(0), denomString = (QString)numberStringList.at(1);
-+ bool canConverseNum = false;
-+ bool canConverseDenom = false;
-+ int num = numString.toInt(&canConverseNum, 10), denom = denomString.toInt(&canConverseDenom, 10);
-+
-+ if (canConverseNum && canConverseDenom)
-+ {
-+ if (fabs(info.aspectRatio() - (double)num / denom) < 0.1)
-+ textMatch = true;
-+ }
-+ }
-+ }
-+ else if (expFloat.indexIn(m_textFilterSettings.text) > -1)
-+ {
-+ QString trimmedTextFilterSettingsText = m_textFilterSettings.text;
-+ bool canConverse = false;
-+ double ratio = trimmedTextFilterSettingsText.toDouble(&canConverse);
-+
-+ if (canConverse)
-+ {
-+ if (fabs(info.aspectRatio() - ratio) < 0.1)
-+ textMatch = true;
-+ }
-+ }
-+ }
-+
-+ // Image Pixel Size
-+ // See bug #341053 for details.
-+
-+ if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImagePixelSize)
-+ {
-+ QSize size = info.dimensions();
-+ int pixelSize = size.height()*size.width();
-+ QString text = m_textFilterSettings.text;
-+
-+ if(text.contains(QRegExp(QLatin1String("^>\\d{1,15}$"))) && pixelSize > (text.remove(0,1)).toInt())
-+ {
-+ textMatch = true;
-+ }
-+ else if(text.contains(QRegExp(QLatin1String("^<\\d{1,15}$"))) && pixelSize < (text.remove(0,1)).toInt())
-+ {
-+ textMatch = true;
-+ }
-+ else if(text.contains(QRegExp(QLatin1String("^\\d+$"))) && pixelSize == text.toInt())
-+ {
-+ textMatch = true;
-+ }
-+ }
-+
-+ match &= textMatch;
-+
-+ if (foundText)
-+ {
-+ *foundText = textMatch;
-+ }
-+ }
-+
-+ // -- filter by URL-whitelists ------------------------------------------------
-+ // NOTE: whitelists are always AND for now.
-+
-+ if (match)
-+ {
-+ const QUrl url = info.fileUrl();
-+
-+ for (QHash<QString, QList<QUrl>>::const_iterator it = m_urlWhitelists.constBegin();
-+ it!=m_urlWhitelists.constEnd(); ++it)
-+ {
-+ match = it->contains(url);
-+
-+ if (!match)
-+ {
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (match)
-+ {
-+ const qlonglong id = info.id();
-+
-+ for (QHash<QString, QList<qlonglong> >::const_iterator it = m_idWhitelists.constBegin();
-+ it!=m_idWhitelists.constEnd(); ++it)
-+ {
-+ match = it->contains(id);
-+
-+ if (!match)
-+ {
-+ break;
-+ }
-+ }
-+ }
-+
-+ return match;
-+}
-+
-+// -------------------------------------------------------------------------------------------------
-+
-+VersionImageFilterSettings::VersionImageFilterSettings()
-+{
-+ m_includeTagFilter = 0;
-+ m_exceptionTagFilter = 0;
-+}
-+
-+VersionImageFilterSettings::VersionImageFilterSettings(const VersionManagerSettings& settings)
-+{
-+ setVersionManagerSettings(settings);
-+}
-+
-+bool VersionImageFilterSettings::operator==(const VersionImageFilterSettings& other) const
-+{
-+ return m_excludeTagFilter == other.m_excludeTagFilter &&
-+ m_exceptionLists == other.m_exceptionLists;
-+}
-+
-+bool VersionImageFilterSettings::matches(const ImageInfo& info) const
-+{
-+ if (!isFiltering())
-+ {
-+ return true;
-+ }
-+
-+ const qlonglong id = info.id();
-+
-+ for (QHash<QString, QList<qlonglong> >::const_iterator it = m_exceptionLists.constBegin();
-+ it != m_exceptionLists.constEnd(); ++it)
-+ {
-+ if (it->contains(id))
-+ {
-+ return true;
-+ }
-+ }
-+
-+ bool match = true;
-+ QList<int> tagIds = info.tagIds();
-+
-+ if (!tagIds.contains(m_includeTagFilter))
-+ {
-+ for (QList<int>::const_iterator it = m_excludeTagFilter.begin();
-+ it != m_excludeTagFilter.end(); ++it)
-+ {
-+ if (tagIds.contains(*it))
-+ {
-+ match = false;
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (!match)
-+ {
-+ if (tagIds.contains(m_exceptionTagFilter))
-+ {
-+ match = true;
-+ }
-+ }
-+
-+ return match;
-+}
-+
-+bool VersionImageFilterSettings::isHiddenBySettings(const ImageInfo& info) const
-+{
-+ QList<int> tagIds = info.tagIds();
-+
-+ foreach(int tagId, m_excludeTagFilter)
-+ {
-+ if (tagIds.contains(tagId))
-+ {
-+ return true;
-+ }
-+ }
-+
-+ return false;
-+}
-+
-+bool VersionImageFilterSettings::isExemptedBySettings(const ImageInfo& info) const
-+{
-+ return info.tagIds().contains(m_exceptionTagFilter);
-+}
-+
-+void VersionImageFilterSettings::setVersionManagerSettings(const VersionManagerSettings& settings)
-+{
-+ m_excludeTagFilter.clear();
-+
-+ if (!settings.enabled)
-+ {
-+ return;
-+ }
-+
-+ if (!(settings.showInViewFlags & VersionManagerSettings::ShowOriginal))
-+ {
-+ m_excludeTagFilter << TagsCache::instance()->getOrCreateInternalTag(InternalTagName::originalVersion());
-+ }
-+
-+ if (!(settings.showInViewFlags & VersionManagerSettings::ShowIntermediates))
-+ {
-+ m_excludeTagFilter << TagsCache::instance()->getOrCreateInternalTag(InternalTagName::intermediateVersion());
-+ }
-+
-+ m_includeTagFilter = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::currentVersion());
-+ m_exceptionTagFilter = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::versionAlwaysVisible());
-+}
-+
-+void VersionImageFilterSettings::setExceptionList(const QList<qlonglong>& idList, const QString& id)
-+{
-+ if (idList.isEmpty())
-+ {
-+ m_exceptionLists.remove(id);
-+ }
-+ else
-+ {
-+ m_exceptionLists.insert(id, idList);
-+ }
-+}
-+
-+bool VersionImageFilterSettings::isFiltering() const
-+{
-+ return !m_excludeTagFilter.isEmpty();
-+}
-+
-+bool VersionImageFilterSettings::isFilteringByTags() const
-+{
-+ return isFiltering();
-+}
-+
-+// -------------------------------------------------------------------------------------------------
-+
-+GroupImageFilterSettings::GroupImageFilterSettings()
-+ : m_allOpen(false)
-+{
-+}
-+
-+bool GroupImageFilterSettings::operator==(const GroupImageFilterSettings& other) const
-+{
-+ return (m_allOpen == other.m_allOpen &&
-+ m_openGroups == other.m_openGroups);
-+}
-+
-+bool GroupImageFilterSettings::matches(const ImageInfo& info) const
-+{
-+ if (m_allOpen)
-+ {
-+ return true;
-+ }
-+
-+ if (info.isGrouped())
-+ {
-+ return m_openGroups.contains(info.groupImage().id());
-+ }
-+ return true;
-+}
-+
-+void GroupImageFilterSettings::setOpen(qlonglong group, bool open)
-+{
-+ if (open)
-+ {
-+ m_openGroups << group;
-+ }
-+ else
-+ {
-+ m_openGroups.remove(group);
-+ }
-+}
-+
-+bool GroupImageFilterSettings::isOpen(qlonglong group) const
-+{
-+ return m_openGroups.contains(group);
-+}
-+
-+void GroupImageFilterSettings::setAllOpen(bool open)
-+{
-+ m_allOpen = open;
-+}
-+
-+bool GroupImageFilterSettings::isAllOpen() const
-+{
-+ return m_allOpen;
-+}
-+
-+bool GroupImageFilterSettings::isFiltering() const
-+{
-+ return !m_allOpen;
-+}
-+
-+DatabaseFields::Set GroupImageFilterSettings::watchFlags() const
-+{
-+ return DatabaseFields::ImageRelations;
-+}
-+
-+} // namespace Digikam
-diff --git a/libs/database/models/imagefiltersettings.h b/libs/database/models/imagefiltersettings.h
-new file mode 100644
-index 0000000..0e7beae
---- /dev/null
-+++ b/libs/database/models/imagefiltersettings.h
-@@ -0,0 +1,349 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Filter values for use with ImageFilterModel
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-+ * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-+ * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-+ * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 IMAGEFILTERSETTINGS_H
-+#define IMAGEFILTERSETTINGS_H
-+
-+// Qt includes
-+
-+#include <QHash>
-+#include <QList>
-+#include <QMap>
-+#include <QString>
-+#include <QSet>
-+#include <QUrl>
-+
-+// Local includes
-+
-+#include "searchtextbar.h"
-+#include "mimefilter.h"
-+#include "digikam_export.h"
-+
-+namespace Digikam
-+{
-+
-+class ImageInfo;
-+class VersionManagerSettings;
-+
-+namespace DatabaseFields
-+{
-+ class Set;
-+}
-+
-+// ---------------------------------------------------------------------------------------
-+
-+class DIGIKAM_DATABASE_EXPORT SearchTextFilterSettings : public SearchTextSettings
-+{
-+
-+public:
-+
-+ enum TextFilterFields
-+ {
-+ None = 0x00,
-+ ImageName = 0x01,
-+ ImageTitle = 0x02,
-+ ImageComment = 0x04,
-+ TagName = 0x08,
-+ AlbumName = 0x10,
-+ ImageAspectRatio = 0x20,
-+ ImagePixelSize = 0x40,
-+ All = ImageName | ImageTitle | ImageComment | TagName | AlbumName | ImageAspectRatio | ImagePixelSize
-+ };
-+
-+public:
-+
-+ SearchTextFilterSettings()
-+ {
-+ textFields = None;
-+ }
-+
-+ explicit SearchTextFilterSettings(const SearchTextSettings& settings)
-+ {
-+ caseSensitive = settings.caseSensitive;
-+ text = settings.text;
-+ textFields = None;
-+ }
-+
-+ TextFilterFields textFields;
-+};
-+
-+// ---------------------------------------------------------------------------------------
-+
-+class DIGIKAM_DATABASE_EXPORT ImageFilterSettings
-+{
-+public:
-+
-+ ImageFilterSettings();
-+
-+ /**
-+ * Returns true if the given ImageInfo matches the filter criteria.
-+ * Optionally, foundText is set to true if it matched by text search.
-+ */
-+ bool matches(const ImageInfo& info, bool* const foundText = 0) const;
-+
-+public:
-+
-+ /// --- Tags filter ---
-+
-+ /// Possible logical matching condition used to sort tags id.
-+ enum MatchingCondition
-+ {
-+ OrCondition,
-+ AndCondition
-+ };
-+
-+ void setTagFilter(const QList<int>& includedTags,
-+ const QList<int>& excludedTags,
-+ MatchingCondition matchingCond,
-+ bool showUnTagged,
-+ const QList<int>& clTagIds,
-+ const QList<int>& plTagIds);
-+
-+public:
-+
-+ /// --- Rating filter ---
-+
-+ /// Possible conditions used to filter rating: >=, =, <=
-+ enum RatingCondition
-+ {
-+ GreaterEqualCondition,
-+ EqualCondition,
-+ LessEqualCondition
-+ };
-+
-+ void setRatingFilter(int rating, RatingCondition ratingCond, bool isUnratedExcluded);
-+
-+public:
-+
-+ /// --- Date filter ---
-+ void setDayFilter(const QList<QDateTime>& days);
-+
-+public:
-+
-+ /// --- Text filter ---
-+ void setTextFilter(const SearchTextFilterSettings& settings);
-+ void setTagNames(const QHash<int, QString>& tagNameHash);
-+ void setAlbumNames(const QHash<int, QString>& albumNameHash);
-+
-+public:
-+
-+ /// --- Mime filter ---
-+ void setMimeTypeFilter(int mimeTypeFilter);
-+
-+public:
-+
-+ /// --- Geolocation filter
-+ enum GeolocationCondition
-+ {
-+ GeolocationNoFilter = 0,
-+ GeolocationNoCoordinates = 1 << 1,
-+ GeolocationHasCoordinates = 1 << 2
-+ };
-+
-+ void setGeolocationFilter(const GeolocationCondition& condition);
-+
-+public:
-+
-+ /// Returns if the day is a filter criteria
-+ bool isFilteringByDay() const;
-+
-+ /// Returns if the type mime is a filter criteria
-+ bool isFilteringByTypeMime() const;
-+
-+ /// Returns whether geolocation is a filter criteria
-+ bool isFilteringByGeolocation() const;
-+
-+ /// Returns if the rating is a filter criteria
-+ bool isFilteringByRating() const;
-+
-+ /// Returns if the pick labels is a filter criteria
-+ bool isFilteringByPickLabels() const;
-+
-+ /// Returns if the color labels is a filter criteria
-+ bool isFilteringByColorLabels() const;
-+
-+ /// Returns if the tag is a filter criteria
-+ bool isFilteringByTags() const;
-+
-+ /// Returns if the text (including comment) is a filter criteria
-+ bool isFilteringByText() const;
-+
-+ /// Returns if images will be filtered by these criteria at all
-+ bool isFiltering() const;
-+
-+public:
-+
-+ /// --- URL whitelist filter
-+ void setUrlWhitelist(const QList<QUrl>& urlList, const QString& id);
-+
-+public:
-+
-+ /// --- ID whitelist filter
-+ void setIdWhitelist(const QList<qlonglong>& idList, const QString& id);
-+
-+public:
-+
-+ /// --- Change notification ---
-+
-+ /** Returns database fields a change in which would affect the current filtering.
-+ * To find out if an image tag change affects filtering, test isFilteringByTags().
-+ * The text filter will also be affected by changes in tags and album names.
-+ */
-+ DatabaseFields::Set watchFlags() const;
-+
-+private:
-+
-+ /**
-+ * @brief Returns whether some internal filtering (whitelist by id or URL) or normal filtering is going on
-+ */
-+ bool isFilteringInternally() const;
-+
-+private:
-+
-+ /// --- Tags filter ---
-+ bool m_untaggedFilter;
-+ QList<int> m_includeTagFilter;
-+ QList<int> m_excludeTagFilter;
-+ MatchingCondition m_matchingCond;
-+ QList<int> m_colorLabelTagFilter;
-+ QList<int> m_pickLabelTagFilter;
-+
-+ /// --- Rating filter ---
-+ int m_ratingFilter;
-+ RatingCondition m_ratingCond;
-+ bool m_isUnratedExcluded;
-+
-+ /// --- Date filter ---
-+ QMap<QDateTime, bool> m_dayFilter;
-+
-+ /// --- Text filter ---
-+ SearchTextFilterSettings m_textFilterSettings;
-+
-+ /// Helpers for text search: Set these if you want to search album or tag names with text search
-+ QHash<int, QString> m_tagNameHash;
-+ QHash<int, QString> m_albumNameHash;
-+
-+ /// --- Mime filter ---
-+ MimeFilter::TypeMimeFilter m_mimeTypeFilter;
-+
-+ /// --- Geolocation filter
-+ GeolocationCondition m_geolocationCondition;
-+
-+ /// --- URL whitelist filter
-+ QHash<QString,QList<QUrl>> m_urlWhitelists;
-+
-+ /// --- ID whitelist filter
-+ QHash<QString,QList<qlonglong> > m_idWhitelists;
-+};
-+
-+// ---------------------------------------------------------------------------------------
-+
-+class DIGIKAM_DATABASE_EXPORT VersionImageFilterSettings
-+{
-+public:
-+
-+ VersionImageFilterSettings();
-+ explicit VersionImageFilterSettings(const VersionManagerSettings& settings);
-+
-+ bool operator==(const VersionImageFilterSettings& other) const;
-+
-+ /**
-+ * Returns true if the given ImageInfo matches the filter criteria.
-+ */
-+ bool matches(const ImageInfo& info) const;
-+
-+ bool isHiddenBySettings(const ImageInfo& info) const;
-+ bool isExemptedBySettings(const ImageInfo& info) const;
-+
-+ /// --- Tags filter ---
-+
-+ void setVersionManagerSettings(const VersionManagerSettings& settings);
-+
-+ /**
-+ * Add list with exceptions: These images will be exempted from filtering by this filter
-+ */
-+ void setExceptionList(const QList<qlonglong>& idlist, const QString& id);
-+
-+ /// Returns if images will be filtered by these criteria at all
-+ bool isFiltering() const;
-+
-+ /// Returns if the tag is a filter criteria
-+ bool isFilteringByTags() const;
-+
-+ /// DatabaseFields::Set watchFlags() const: Would return 0
-+
-+protected:
-+
-+ QList<int> m_excludeTagFilter;
-+ int m_includeTagFilter;
-+ int m_exceptionTagFilter;
-+ QHash<QString,QList<qlonglong> > m_exceptionLists;
-+};
-+
-+// ---------------------------------------------------------------------------------------
-+
-+class DIGIKAM_DATABASE_EXPORT GroupImageFilterSettings
-+{
-+public:
-+
-+ GroupImageFilterSettings();
-+
-+ bool operator==(const GroupImageFilterSettings& other) const;
-+
-+ /**
-+ * Returns true if the given ImageInfo matches the filter criteria.
-+ */
-+ bool matches(const ImageInfo& info) const;
-+
-+ /**
-+ * Open or close a group.
-+ */
-+ void setOpen(qlonglong group, bool open);
-+ bool isOpen(qlonglong group) const;
-+
-+ /**
-+ * Open all groups
-+ */
-+ void setAllOpen(bool open);
-+ bool isAllOpen() const;
-+
-+ /// Returns if images will be filtered by these criteria at all
-+ bool isFiltering() const;
-+
-+ DatabaseFields::Set watchFlags() const;
-+
-+protected:
-+
-+ bool m_allOpen;
-+ QSet<qlonglong> m_openGroups;
-+};
-+
-+} // namespace Digikam
-+
-+Q_DECLARE_METATYPE(Digikam::ImageFilterSettings::GeolocationCondition)
-+
-+#endif // IMAGEFILTERSETTINGS_H
-diff --git a/libs/database/models/imagelistmodel.cpp b/libs/database/models/imagelistmodel.cpp
-new file mode 100644
-index 0000000..fafce34
---- /dev/null
-+++ b/libs/database/models/imagelistmodel.cpp
-@@ -0,0 +1,70 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2010-12-06
-+ * Description : An image model based on a static list
-+ *
-+ * Copyright (C) 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ *
-+ * 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 "imagelistmodel.h"
-+
-+// Local includes
-+
-+#include "digikam_debug.h"
-+#include "coredbaccess.h"
-+#include "coredbchangesets.h"
-+#include "coredbwatch.h"
-+#include "imageinfo.h"
-+#include "imageinfolist.h"
-+
-+namespace Digikam
-+{
-+
-+ImageListModel::ImageListModel(QObject* parent)
-+ : ImageThumbnailModel(parent)
-+{
-+ connect(CoreDbAccess::databaseWatch(), SIGNAL(collectionImageChange(CollectionImageChangeset)),
-+ this, SLOT(slotCollectionImageChange(CollectionImageChangeset)));
-+}
-+
-+ImageListModel::~ImageListModel()
-+{
-+}
-+
-+void ImageListModel::slotCollectionImageChange(const CollectionImageChangeset& changeset)
-+{
-+ if (isEmpty())
-+ {
-+ return;
-+ }
-+
-+ switch (changeset.operation())
-+ {
-+ case CollectionImageChangeset::Added:
-+ break;
-+ case CollectionImageChangeset::Removed:
-+ case CollectionImageChangeset::RemovedAll:
-+ removeImageInfos(ImageInfoList(changeset.ids()));
-+ break;
-+
-+ default:
-+ break;
-+ }
-+}
-+
-+} // namespace Digikam
-diff --git a/libs/database/models/imagelistmodel.h b/libs/database/models/imagelistmodel.h
-new file mode 100644
-index 0000000..a225b1b
---- /dev/null
-+++ b/libs/database/models/imagelistmodel.h
-@@ -0,0 +1,63 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2010-12-06
-+ * Description : An image model based on a static list
-+ *
-+ * Copyright (C) 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ *
-+ * 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 IMAGELISTMODEL_H
-+#define IMAGELISTMODEL_H
-+
-+// Local includes
-+
-+#include "imagethumbnailmodel.h"
-+#include "digikam_export.h"
-+
-+namespace Digikam
-+{
-+
-+class ImageChangeset;
-+class CollectionImageChangeset;
-+
-+class DIGIKAM_DATABASE_EXPORT ImageListModel : public ImageThumbnailModel
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ explicit ImageListModel(QObject* parent = 0);
-+ ~ImageListModel();
-+
-+ // NOTE: necessary methods to add and remove ImageInfos to the model are inherited from ImageModel
-+
-+Q_SIGNALS:
-+
-+ /**
-+ * Emitted when images are removed from the model because they are removed in the database
-+ */
-+ void imageInfosRemoved(const QList<ImageInfo>& infos);
-+
-+protected Q_SLOTS:
-+
-+ void slotCollectionImageChange(const CollectionImageChangeset& changeset);
-+};
-+
-+} // namespace Digikam
-+
-+#endif // IMAGELISTMODEL_H
-diff --git a/libs/database/models/imagemodel.cpp b/libs/database/models/imagemodel.cpp
-new file mode 100644
-index 0000000..41b43cf
---- /dev/null
-+++ b/libs/database/models/imagemodel.cpp
-@@ -0,0 +1,1368 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Qt item model for database entries
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ *
-+ * 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 "imagemodel.h"
-+
-+// Qt includes
-+
-+#include <QHash>
-+#include <QItemSelection>
-+
-+// Local includes
-+
-+#include "digikam_debug.h"
-+#include "coredbchangesets.h"
-+#include "coredbfields.h"
-+#include "coredbwatch.h"
-+#include "imageinfo.h"
-+#include "imageinfolist.h"
-+#include "abstractitemdragdrophandler.h"
-+
-+namespace Digikam
-+{
-+
-+class ImageModel::Private
-+{
-+public:
-+
-+ Private()
-+ {
-+ preprocessor = 0;
-+ keepFilePathCache = false;
-+ sendRemovalSignals = false;
-+ incrementalUpdater = 0;
-+ refreshing = false;
-+ reAdding = false;
-+ incrementalRefreshRequested = false;
-+ }
-+
-+ ImageInfoList infos;
-+ QList<QVariant> extraValues;
-+ QHash<qlonglong, int> idHash;
-+
-+ bool keepFilePathCache;
-+ QHash<QString, qlonglong> filePathHash;
-+
-+ bool sendRemovalSignals;
-+
-+ QObject* preprocessor;
-+ bool refreshing;
-+ bool reAdding;
-+ bool incrementalRefreshRequested;
-+
-+ DatabaseFields::Set watchFlags;
-+
-+ class ImageModelIncrementalUpdater* incrementalUpdater;
-+
-+ ImageInfoList pendingInfos;
-+ QList<QVariant> pendingExtraValues;
-+
-+ inline bool isValid(const QModelIndex& index)
-+ {
-+ if (!index.isValid())
-+ {
-+ return false;
-+ }
-+
-+ if (index.row() < 0 || index.row() >= infos.size())
-+ {
-+ qCDebug(DIGIKAM_GENERAL_LOG) << "Invalid index" << index;
-+ return false;
-+ }
-+
-+ return true;
-+ }
-+ inline bool extraValueValid(const QModelIndex& index)
-+ {
-+ // we assume isValid() being called before, no duplicate checks
-+ if (index.row() >= extraValues.size())
-+ {
-+ qCDebug(DIGIKAM_GENERAL_LOG) << "Invalid index for extraData" << index;
-+ return false;
-+ }
-+
-+ return true;
-+ }
-+};
-+
-+typedef QPair<int, int> IntPair; // to make foreach macro happy
-+typedef QList<IntPair> IntPairList;
-+
-+class ImageModelIncrementalUpdater
-+{
-+public:
-+
-+ explicit ImageModelIncrementalUpdater(ImageModel::Private* d);
-+
-+ void appendInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+ void aboutToBeRemovedInModel(const IntPairList& aboutToBeRemoved);
-+ QList<IntPair> oldIndexes();
-+
-+ static QList<IntPair> toContiguousPairs(const QList<int>& ids);
-+
-+public:
-+
-+ QHash<qlonglong, int> oldIds;
-+ QList<QVariant> oldExtraValues;
-+ QList<ImageInfo> newInfos;
-+ QList<QVariant> newExtraValues;
-+ QList<IntPairList> modelRemovals;
-+};
-+
-+ImageModel::ImageModel(QObject* parent)
-+ : QAbstractListModel(parent),
-+ d(new Private)
-+{
-+ connect(CoreDbAccess::databaseWatch(), SIGNAL(imageChange(ImageChangeset)),
-+ this, SLOT(slotImageChange(ImageChangeset)));
-+
-+ connect(CoreDbAccess::databaseWatch(), SIGNAL(imageTagChange(ImageTagChangeset)),
-+ this, SLOT(slotImageTagChange(ImageTagChangeset)));
-+}
-+
-+ImageModel::~ImageModel()
-+{
-+ delete d->incrementalUpdater;
-+ delete d;
-+}
-+
-+// ------------ Access methods -------------
-+
-+void ImageModel::setKeepsFilePathCache(bool keepCache)
-+{
-+ d->keepFilePathCache = keepCache;
-+}
-+
-+bool ImageModel::keepsFilePathCache() const
-+{
-+ return d->keepFilePathCache;
-+}
-+
-+bool ImageModel::isEmpty() const
-+{
-+ return d->infos.isEmpty();
-+}
-+
-+void ImageModel::setWatchFlags(const DatabaseFields::Set& set)
-+{
-+ d->watchFlags = set;
-+}
-+
-+ImageInfo ImageModel::imageInfo(const QModelIndex& index) const
-+{
-+ if (!d->isValid(index))
-+ {
-+ return ImageInfo();
-+ }
-+
-+ return d->infos.at(index.row());
-+}
-+
-+ImageInfo& ImageModel::imageInfoRef(const QModelIndex& index) const
-+{
-+ return d->infos[index.row()];
-+}
-+
-+qlonglong ImageModel::imageId(const QModelIndex& index) const
-+{
-+ if (!d->isValid(index))
-+ {
-+ return 0;
-+ }
-+
-+ return d->infos.at(index.row()).id();
-+}
-+
-+QList<ImageInfo> ImageModel::imageInfos(const QList<QModelIndex>& indexes) const
-+{
-+ QList<ImageInfo> infos;
-+
-+ foreach(const QModelIndex& index, indexes)
-+ {
-+ infos << imageInfo(index);
-+ }
-+
-+ return infos;
-+}
-+
-+QList<qlonglong> ImageModel::imageIds(const QList<QModelIndex>& indexes) const
-+{
-+ QList<qlonglong> ids;
-+
-+ foreach(const QModelIndex& index, indexes)
-+ {
-+ ids << imageId(index);
-+ }
-+
-+ return ids;
-+}
-+
-+ImageInfo ImageModel::imageInfo(int row) const
-+{
-+ if (row >= d->infos.size())
-+ {
-+ return ImageInfo();
-+ }
-+
-+ return d->infos.at(row);
-+}
-+
-+ImageInfo& ImageModel::imageInfoRef(int row) const
-+{
-+ return d->infos[row];
-+}
-+
-+qlonglong ImageModel::imageId(int row) const
-+{
-+ if (row < 0 || row >= d->infos.size())
-+ {
-+ return -1;
-+ }
-+
-+ return d->infos.at(row).id();
-+}
-+
-+QModelIndex ImageModel::indexForImageInfo(const ImageInfo& info) const
-+{
-+ return indexForImageId(info.id());
-+}
-+
-+QModelIndex ImageModel::indexForImageInfo(const ImageInfo& info, const QVariant& extraValue) const
-+{
-+ return indexForImageId(info.id(), extraValue);
-+}
-+
-+QList<QModelIndex> ImageModel::indexesForImageInfo(const ImageInfo& info) const
-+{
-+ return indexesForImageId(info.id());
-+}
-+
-+QModelIndex ImageModel::indexForImageId(qlonglong id) const
-+{
-+ int index = d->idHash.value(id, -1);
-+
-+ if (index != -1)
-+ {
-+ return createIndex(index, 0);
-+ }
-+
-+ return QModelIndex();
-+}
-+
-+QModelIndex ImageModel::indexForImageId(qlonglong id, const QVariant& extraValue) const
-+{
-+ if (d->extraValues.isEmpty())
-+ return indexForImageId(id);
-+
-+ QHash<qlonglong, int>::const_iterator it;
-+
-+ for (it = d->idHash.constFind(id); it != d->idHash.constEnd() && it.key() == id; ++it)
-+ {
-+ if (d->extraValues.at(it.value()) == extraValue)
-+ return createIndex(it.value(), 0);
-+ }
-+
-+ return QModelIndex();
-+}
-+
-+QList<QModelIndex> ImageModel::indexesForImageId(qlonglong id) const
-+{
-+ QList<QModelIndex> indexes;
-+ QHash<qlonglong, int>::const_iterator it;
-+
-+ for (it = d->idHash.constFind(id); it != d->idHash.constEnd() && it.key() == id; ++it)
-+ {
-+ indexes << createIndex(it.value(), 0);
-+ }
-+
-+ return indexes;
-+}
-+
-+int ImageModel::numberOfIndexesForImageInfo(const ImageInfo& info) const
-+{
-+ return numberOfIndexesForImageId(info.id());
-+}
-+
-+int ImageModel::numberOfIndexesForImageId(qlonglong id) const
-+{
-+ if (d->extraValues.isEmpty())
-+ {
-+ return 0;
-+ }
-+
-+ int count = 0;
-+ QHash<qlonglong,int>::const_iterator it;
-+
-+ for (it = d->idHash.constFind(id); it != d->idHash.constEnd() && it.key() == id; ++it)
-+ {
-+ ++count;
-+ }
-+
-+ return count;
-+}
-+
-+// static method
-+ImageInfo ImageModel::retrieveImageInfo(const QModelIndex& index)
-+{
-+ if (!index.isValid())
-+ {
-+ return ImageInfo();
-+ }
-+
-+ ImageModel* const model = index.data(ImageModelPointerRole).value<ImageModel*>();
-+ int row = index.data(ImageModelInternalId).toInt();
-+
-+ if (!model)
-+ {
-+ return ImageInfo();
-+ }
-+
-+ return model->imageInfo(row);
-+}
-+
-+// static method
-+qlonglong ImageModel::retrieveImageId(const QModelIndex& index)
-+{
-+ if (!index.isValid())
-+ {
-+ return 0;
-+ }
-+
-+ ImageModel* const model = index.data(ImageModelPointerRole).value<ImageModel*>();
-+ int row = index.data(ImageModelInternalId).toInt();
-+
-+ if (!model)
-+ {
-+ return 0;
-+ }
-+
-+ return model->imageId(row);
-+}
-+
-+QModelIndex ImageModel::indexForPath(const QString& filePath) const
-+{
-+ if (d->keepFilePathCache)
-+ {
-+ return indexForImageId(d->filePathHash.value(filePath));
-+ }
-+ else
-+ {
-+ const int size = d->infos.size();
-+
-+ for (int i=0; i<size; ++i)
-+ {
-+ if (d->infos.at(i).filePath() == filePath)
-+ {
-+ return createIndex(i, 0);
-+ }
-+ }
-+ }
-+
-+ return QModelIndex();
-+}
-+
-+QList<QModelIndex> ImageModel::indexesForPath(const QString& filePath) const
-+{
-+ if (d->keepFilePathCache)
-+ {
-+ return indexesForImageId(d->filePathHash.value(filePath));
-+ }
-+ else
-+ {
-+ QList<QModelIndex> indexes;
-+ const int size = d->infos.size();
-+
-+ for (int i=0; i<size; ++i)
-+ {
-+ if (d->infos.at(i).filePath() == filePath)
-+ {
-+ indexes << createIndex(i, 0);
-+ }
-+ }
-+
-+ return indexes;
-+ }
-+}
-+
-+ImageInfo ImageModel::imageInfo(const QString& filePath) const
-+{
-+ if (d->keepFilePathCache)
-+ {
-+ qlonglong id = d->filePathHash.value(filePath);
-+
-+ if (id)
-+ {
-+ int index = d->idHash.value(id, -1);
-+
-+ if (index != -1)
-+ {
-+ return d->infos.at(index);
-+ }
-+ }
-+ }
-+ else
-+ {
-+ foreach(const ImageInfo& info, d->infos)
-+ {
-+ if (info.filePath() == filePath)
-+ {
-+ return info;
-+ }
-+ }
-+ }
-+
-+ return ImageInfo();
-+}
-+
-+QList<ImageInfo> ImageModel::imageInfos(const QString& filePath) const
-+{
-+ QList<ImageInfo> infos;
-+
-+ if (d->keepFilePathCache)
-+ {
-+ qlonglong id = d->filePathHash.value(filePath);
-+
-+ if (id)
-+ {
-+ foreach(int index, d->idHash.values(id))
-+ {
-+ infos << d->infos.at(index);
-+ }
-+ }
-+ }
-+ else
-+ {
-+ foreach(const ImageInfo& info, d->infos)
-+ {
-+ if (info.filePath() == filePath)
-+ {
-+ infos << info;
-+ }
-+ }
-+ }
-+
-+ return infos;
-+}
-+
-+void ImageModel::addImageInfo(const ImageInfo& info)
-+{
-+ addImageInfos(QList<ImageInfo>() << info, QList<QVariant>());
-+}
-+
-+void ImageModel::addImageInfos(const QList<ImageInfo>& infos)
-+{
-+ addImageInfos(infos, QList<QVariant>());
-+}
-+
-+void ImageModel::addImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ if (infos.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ if (d->incrementalUpdater)
-+ {
-+ d->incrementalUpdater->appendInfos(infos, extraValues);
-+ }
-+ else
-+ {
-+ appendInfos(infos, extraValues);
-+ }
-+}
-+
-+void ImageModel::addImageInfoSynchronously(const ImageInfo& info)
-+{
-+ addImageInfosSynchronously(QList<ImageInfo>() << info, QList<QVariant>());
-+}
-+
-+void ImageModel::addImageInfosSynchronously(const QList<ImageInfo>& infos)
-+{
-+ addImageInfos(infos, QList<QVariant>());
-+}
-+
-+void ImageModel::addImageInfosSynchronously(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ if (infos.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ publiciseInfos(infos, extraValues);
-+ emit processAdded(infos, extraValues);
-+}
-+
-+void ImageModel::ensureHasImageInfo(const ImageInfo& info)
-+{
-+ ensureHasImageInfos(QList<ImageInfo>() << info, QList<QVariant>());
-+}
-+
-+void ImageModel::ensureHasImageInfos(const QList<ImageInfo>& infos)
-+{
-+ ensureHasImageInfos(infos, QList<QVariant>());
-+}
-+
-+void ImageModel::ensureHasImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ if (extraValues.isEmpty())
-+ {
-+ if (!d->pendingExtraValues.isEmpty())
-+ {
-+ qCDebug(DIGIKAM_GENERAL_LOG) << "ExtraValue / No Extra Value mismatch. Ignoring added infos.";
-+ return;
-+ }
-+ }
-+ else
-+ {
-+ if (d->pendingInfos.size() != d->pendingExtraValues.size())
-+ {
-+ qCDebug(DIGIKAM_GENERAL_LOG) << "ExtraValue / No Extra Value mismatch. Ignoring added infos.";
-+ return;
-+ }
-+ }
-+
-+ d->pendingInfos << infos;
-+ d->pendingExtraValues << extraValues;
-+ cleanSituationChecks();
-+}
-+
-+void ImageModel::clearImageInfos()
-+{
-+ d->infos.clear();
-+ d->extraValues.clear();
-+ d->idHash.clear();
-+ d->filePathHash.clear();
-+ delete d->incrementalUpdater;
-+ d->incrementalUpdater = 0;
-+ d->pendingInfos.clear();
-+ d->pendingExtraValues.clear();
-+ d->refreshing = false;
-+ d->reAdding = false;
-+ d->incrementalRefreshRequested = false;
-+
-+ beginResetModel();
-+ endResetModel();
-+
-+ imageInfosCleared();
-+}
-+
-+void ImageModel::setImageInfos(const QList<ImageInfo>& infos)
-+{
-+ clearImageInfos();
-+ addImageInfos(infos);
-+}
-+
-+QList<ImageInfo> ImageModel::imageInfos() const
-+{
-+ return d->infos;
-+}
-+
-+QList<qlonglong> ImageModel::imageIds() const
-+{
-+ return d->idHash.keys();
-+}
-+
-+bool ImageModel::hasImage(qlonglong id) const
-+{
-+ return d->idHash.contains(id);
-+}
-+
-+bool ImageModel::hasImage(const ImageInfo& info) const
-+{
-+ return d->idHash.contains(info.id());
-+}
-+
-+bool ImageModel::hasImage(const ImageInfo& info, const QVariant& extraValue) const
-+{
-+ return hasImage(info.id(), extraValue);
-+}
-+
-+bool ImageModel::hasImage(qlonglong id, const QVariant& extraValue) const
-+{
-+ if (d->extraValues.isEmpty())
-+ return hasImage(id);
-+
-+ QHash<qlonglong, int>::const_iterator it;
-+
-+ for (it = d->idHash.constFind(id); it != d->idHash.constEnd() && it.key() == id; ++it)
-+ {
-+ if (d->extraValues.at(it.value()) == extraValue)
-+ return true;
-+ }
-+
-+ return false;;
-+}
-+
-+QList<ImageInfo> ImageModel::uniqueImageInfos() const
-+{
-+ if (d->extraValues.isEmpty())
-+ {
-+ return d->infos;
-+ }
-+
-+ QList<ImageInfo> uniqueInfos;
-+ const int size = d->infos.size();
-+
-+ for (int i=0; i<size; ++i)
-+ {
-+ const ImageInfo& info = d->infos.at(i);
-+
-+ if (d->idHash.value(info.id()) == i)
-+ {
-+ uniqueInfos << info;
-+ }
-+ }
-+
-+ return uniqueInfos;
-+}
-+
-+void ImageModel::emitDataChangedForAll()
-+{
-+ if (d->infos.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ QModelIndex first = createIndex(0, 0);
-+ QModelIndex last = createIndex(d->infos.size() - 1, 0);
-+ emit dataChanged(first, last);
-+}
-+
-+void ImageModel::emitDataChangedForSelection(const QItemSelection& selection)
-+{
-+ if (!selection.isEmpty())
-+ {
-+ foreach(const QItemSelectionRange& range, selection)
-+ {
-+ emit dataChanged(range.topLeft(), range.bottomRight());
-+ }
-+ }
-+}
-+
-+void ImageModel::ensureHasGroupedImages(const ImageInfo& groupLeader)
-+{
-+ ensureHasImageInfos(groupLeader.groupedImages());
-+}
-+
-+// ------------ Preprocessing -------------
-+
-+void ImageModel::setPreprocessor(QObject* preprocessor)
-+{
-+ unsetPreprocessor(d->preprocessor);
-+ d->preprocessor = preprocessor;
-+}
-+
-+void ImageModel::unsetPreprocessor(QObject* preprocessor)
-+{
-+ if (preprocessor && d->preprocessor == preprocessor)
-+ {
-+ disconnect(this, SIGNAL(preprocess(QList<ImageInfo>,QList<QVariant>)), 0, 0);
-+ disconnect(d->preprocessor, 0, this, SLOT(reAddImageInfos(QList<ImageInfo>,QList<QVariant>)));
-+ disconnect(d->preprocessor, 0, this, SLOT(reAddingFinished()));
-+ }
-+}
-+
-+void ImageModel::appendInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ if (infos.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ if (d->preprocessor)
-+ {
-+ d->reAdding = true;
-+ emit preprocess(infos, extraValues);
-+ }
-+ else
-+ {
-+ publiciseInfos(infos, extraValues);
-+ }
-+}
-+
-+void ImageModel::appendInfosChecked(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ // This method does deduplication. It is private because in context of readding or refreshing it is of no use.
-+
-+ if (extraValues.isEmpty())
-+ {
-+ QList<ImageInfo> checkedInfos;
-+
-+ foreach (const ImageInfo& info, infos)
-+ {
-+ if (!hasImage(info))
-+ {
-+ checkedInfos << info;
-+ }
-+ }
-+
-+ appendInfos(checkedInfos, QList<QVariant>());
-+ }
-+ else
-+ {
-+ QList<ImageInfo> checkedInfos;
-+ QList<QVariant> checkedExtraValues;
-+ const int size = infos.size();
-+
-+ for (int i=0; i<size; i++)
-+ {
-+ if (!hasImage(infos[i], extraValues[i]))
-+ {
-+ checkedInfos << infos[i];
-+ checkedExtraValues << extraValues[i];
-+ }
-+ }
-+
-+ appendInfos(checkedInfos, checkedExtraValues);
-+ }
-+}
-+
-+void ImageModel::reAddImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ // addImageInfos -> appendInfos -> preprocessor -> reAddImageInfos
-+ publiciseInfos(infos, extraValues);
-+}
-+
-+void ImageModel::reAddingFinished()
-+{
-+ d->reAdding = false;
-+ cleanSituationChecks();
-+}
-+
-+void ImageModel::startRefresh()
-+{
-+ d->refreshing = true;
-+}
-+
-+void ImageModel::finishRefresh()
-+{
-+ d->refreshing = false;
-+ cleanSituationChecks();
-+}
-+
-+bool ImageModel::isRefreshing() const
-+{
-+ return d->refreshing;
-+}
-+
-+void ImageModel::cleanSituationChecks()
-+{
-+ // For starting an incremental refresh we want a clear situation:
-+ // Any remaining batches from non-incremental refreshing subclasses have been received in appendInfos(),
-+ // any batches sent to preprocessor for re-adding have been re-added.
-+ if (d->refreshing || d->reAdding)
-+ {
-+ return;
-+ }
-+
-+ if (!d->pendingInfos.isEmpty())
-+ {
-+ appendInfosChecked(d->pendingInfos, d->pendingExtraValues);
-+ d->pendingInfos.clear();
-+ d->pendingExtraValues.clear();
-+ cleanSituationChecks();
-+ return;
-+ }
-+
-+ if (d->incrementalRefreshRequested)
-+ {
-+ d->incrementalRefreshRequested = false;
-+ emit readyForIncrementalRefresh();
-+ }
-+ else
-+ {
-+ emit allRefreshingFinished();
-+ }
-+}
-+
-+void ImageModel::publiciseInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ if (infos.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ Q_ASSERT(infos.size() == extraValues.size() || (extraValues.isEmpty() && d->extraValues.isEmpty()));
-+
-+ emit imageInfosAboutToBeAdded(infos);
-+ const int firstNewIndex = d->infos.size();
-+ const int lastNewIndex = d->infos.size() + infos.size() - 1;
-+ beginInsertRows(QModelIndex(), firstNewIndex, lastNewIndex);
-+ d->infos << infos;
-+ d->extraValues << extraValues;
-+
-+ for (int i=firstNewIndex; i<=lastNewIndex; ++i)
-+ {
-+ const ImageInfo& info = d->infos.at(i);
-+ qlonglong id = info.id();
-+ d->idHash.insertMulti(id, i);
-+
-+ if (d->keepFilePathCache)
-+ {
-+ d->filePathHash[info.filePath()] = id;
-+ }
-+ }
-+
-+ endInsertRows();
-+ emit imageInfosAdded(infos);
-+}
-+
-+void ImageModel::requestIncrementalRefresh()
-+{
-+ if (d->reAdding)
-+ {
-+ d->incrementalRefreshRequested = true;
-+ }
-+ else
-+ {
-+ emit readyForIncrementalRefresh();
-+ }
-+}
-+
-+bool ImageModel::hasIncrementalRefreshPending() const
-+{
-+ return d->incrementalRefreshRequested;
-+}
-+
-+void ImageModel::startIncrementalRefresh()
-+{
-+ delete d->incrementalUpdater;
-+
-+ d->incrementalUpdater = new ImageModelIncrementalUpdater(d);
-+}
-+
-+void ImageModel::finishIncrementalRefresh()
-+{
-+ if (!d->incrementalUpdater)
-+ {
-+ return;
-+ }
-+
-+ // remove old entries
-+ QList<QPair<int, int> > pairs = d->incrementalUpdater->oldIndexes();
-+ removeRowPairs(pairs);
-+
-+ // add new indexes
-+ appendInfos(d->incrementalUpdater->newInfos, d->incrementalUpdater->newExtraValues);
-+
-+ delete d->incrementalUpdater;
-+ d->incrementalUpdater = 0;
-+}
-+
-+void ImageModel::removeIndex(const QModelIndex& index)
-+{
-+ removeIndexes(QList<QModelIndex>() << index);
-+}
-+
-+void ImageModel::removeIndexes(const QList<QModelIndex>& indexes)
-+{
-+ QList<int> listIndexes;
-+
-+ foreach(const QModelIndex& index, indexes)
-+ {
-+ if (d->isValid(index))
-+ {
-+ listIndexes << index.row();
-+ }
-+ }
-+
-+ if (listIndexes.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ removeRowPairsWithCheck(ImageModelIncrementalUpdater::toContiguousPairs(listIndexes));
-+}
-+
-+void ImageModel::removeImageInfo(const ImageInfo& info)
-+{
-+ removeImageInfos(QList<ImageInfo>() << info);
-+}
-+
-+void ImageModel::removeImageInfos(const QList<ImageInfo>& infos)
-+{
-+ QList<int> listIndexes;
-+
-+ foreach(const ImageInfo& info, infos)
-+ {
-+ QModelIndex index = indexForImageId(info.id());
-+
-+ if (index.isValid())
-+ {
-+ listIndexes << index.row();
-+ }
-+ }
-+ removeRowPairsWithCheck(ImageModelIncrementalUpdater::toContiguousPairs(listIndexes));
-+}
-+
-+void ImageModel::removeImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ if (extraValues.isEmpty())
-+ {
-+ removeImageInfos(infos);
-+ return;
-+ }
-+
-+ QList<int> listIndexes;
-+
-+ for (int i=0; i<infos.size(); ++i)
-+ {
-+ QModelIndex index = indexForImageId(infos.at(i).id(), extraValues.at(i));
-+
-+ if (index.isValid())
-+ {
-+ listIndexes << index.row();
-+ }
-+ }
-+
-+ removeRowPairsWithCheck(ImageModelIncrementalUpdater::toContiguousPairs(listIndexes));
-+}
-+
-+void ImageModel::setSendRemovalSignals(bool send)
-+{
-+ d->sendRemovalSignals = send;
-+}
-+
-+template <class List, typename T>
-+static bool pairsContain(const List& list, T value)
-+{
-+ typename List::const_iterator middle;
-+ typename List::const_iterator begin = list.begin();
-+ typename List::const_iterator end = list.end();
-+ int n = int(end - begin);
-+ int half;
-+
-+ while (n > 0)
-+ {
-+ half = n >> 1;
-+ middle = begin + half;
-+
-+ if (middle->first <= value && middle->second >= value)
-+ {
-+ return true;
-+ }
-+ else if (middle->second < value)
-+ {
-+ begin = middle + 1;
-+ n -= half + 1;
-+ }
-+ else
-+ {
-+ n = half;
-+ }
-+ }
-+
-+ return false;
-+}
-+
-+void ImageModel::removeRowPairsWithCheck(const QList<QPair<int, int> >& toRemove)
-+{
-+ if (d->incrementalUpdater)
-+ {
-+ d->incrementalUpdater->aboutToBeRemovedInModel(toRemove);
-+ }
-+
-+ removeRowPairs(toRemove);
-+}
-+
-+void ImageModel::removeRowPairs(const QList<QPair<int, int> >& toRemove)
-+{
-+ if (toRemove.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ // Remove old indexes
-+ // Keep in mind that when calling beginRemoveRows all structures announced to be removed
-+ // must still be valid, and this includes our hashes as well, which limits what we can optimize
-+
-+ int removedRows = 0, offset = 0;
-+ typedef QPair<int, int> IntPair; // to make foreach macro happy
-+
-+ foreach(const IntPair& pair, toRemove)
-+ {
-+ const int begin = pair.first - offset;
-+ const int end = pair.second - offset; // inclusive
-+ removedRows = end - begin + 1;
-+
-+ // when removing from the list, all subsequent indexes are affected
-+ offset += removedRows;
-+
-+ QList<ImageInfo> removedInfos;
-+
-+ if (d->sendRemovalSignals)
-+ {
-+ qCopy(d->infos.begin() + begin, d->infos.begin() + end, removedInfos.begin());
-+ emit imageInfosAboutToBeRemoved(removedInfos);
-+ }
-+
-+ imageInfosAboutToBeRemoved(begin, end);
-+ beginRemoveRows(QModelIndex(), begin, end);
-+
-+ // update idHash - which points to indexes of d->infos, and these change now!
-+ QHash<qlonglong, int>::iterator it;
-+
-+ for (it = d->idHash.begin(); it != d->idHash.end(); )
-+ {
-+ if (it.value() >= begin)
-+ {
-+ if (it.value() > end)
-+ {
-+ // after the removed interval: adjust index
-+ it.value() -= removedRows;
-+ }
-+ else
-+ {
-+ // in the removed interval
-+ it = d->idHash.erase(it);
-+ continue;
-+ }
-+ }
-+
-+ ++it;
-+ }
-+
-+ // remove from list
-+ d->infos.erase(d->infos.begin() + begin, d->infos.begin() + (end + 1));
-+
-+ if (!d->extraValues.isEmpty())
-+ {
-+ d->extraValues.erase(d->extraValues.begin() + begin, d->extraValues.begin() + (end + 1));
-+ }
-+
-+ endRemoveRows();
-+
-+ if (d->sendRemovalSignals)
-+ {
-+ emit imageInfosRemoved(removedInfos);
-+ }
-+ }
-+
-+ // tidy up: remove old indexes from file path hash now
-+ if (d->keepFilePathCache)
-+ {
-+ QHash<QString, qlonglong>::iterator it;
-+
-+ for (it = d->filePathHash.begin(); it != d->filePathHash.end(); )
-+ {
-+ if (pairsContain(toRemove, it.value()))
-+ {
-+ it = d->filePathHash.erase(it);
-+ }
-+ else
-+ {
-+ ++it;
-+ }
-+ }
-+ }
-+}
-+
-+ImageModelIncrementalUpdater::ImageModelIncrementalUpdater(ImageModel::Private* d)
-+{
-+ oldIds = d->idHash;
-+ oldExtraValues = d->extraValues;
-+}
-+
-+void ImageModelIncrementalUpdater::appendInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
-+{
-+ if (extraValues.isEmpty())
-+ {
-+ foreach(const ImageInfo& info, infos)
-+ {
-+ QHash<qlonglong,int>::iterator it = oldIds.find(info.id());
-+
-+ if (it != oldIds.end())
-+ {
-+ oldIds.erase(it);
-+ }
-+ else
-+ {
-+ newInfos << info;
-+ }
-+ }
-+ }
-+ else
-+ {
-+ for (int i=0; i<infos.size(); ++i)
-+ {
-+ const ImageInfo& info = infos.at(i);
-+ bool found = false;
-+ QHash<qlonglong,int>::iterator it;
-+
-+ for (it = oldIds.find(info.id()); it != oldIds.end() && it.key() == info.id(); ++it)
-+ {
-+ // first check is for bug #262596. Not sure if needed.
-+ if (it.value() < oldExtraValues.size() && extraValues.at(i) == oldExtraValues.at(it.value()))
-+ {
-+ found = true;
-+ break;
-+ }
-+ }
-+
-+ if (found)
-+ {
-+ oldIds.erase(it);
-+ // do not erase from oldExtraValues - oldIds is a hash id -> index.
-+ }
-+ else
-+ {
-+ newInfos << info;
-+ newExtraValues << extraValues.at(i);
-+ }
-+ }
-+ }
-+}
-+
-+void ImageModelIncrementalUpdater::aboutToBeRemovedInModel(const IntPairList& toRemove)
-+{
-+ modelRemovals << toRemove;
-+}
-+
-+QList<QPair<int, int> > ImageModelIncrementalUpdater::oldIndexes()
-+{
-+ // first, apply all changes to indexes by direct removal in model
-+ // while the updater was active
-+ foreach(const IntPairList& list, modelRemovals)
-+ {
-+ int removedRows = 0, offset = 0;
-+
-+ foreach(const IntPair& pair, list)
-+ {
-+ const int begin = pair.first - offset;
-+ const int end = pair.second - offset; // inclusive
-+ removedRows = end - begin + 1;
-+
-+ // when removing from the list, all subsequent indexes are affected
-+ offset += removedRows;
-+
-+ // update idHash - which points to indexes of d->infos, and these change now!
-+ QHash<qlonglong, int>::iterator it;
-+
-+ for (it = oldIds.begin(); it != oldIds.end(); )
-+ {
-+ if (it.value() >= begin)
-+ {
-+ if (it.value() > end)
-+ {
-+ // after the removed interval: adjust index
-+ it.value() -= removedRows;
-+ }
-+ else
-+ {
-+ // in the removed interval
-+ it = oldIds.erase(it);
-+ continue;
-+ }
-+ }
-+
-+ ++it;
-+ }
-+ }
-+ }
-+
-+ modelRemovals.clear();
-+
-+ return toContiguousPairs(oldIds.values());
-+}
-+
-+QList<QPair<int, int> > ImageModelIncrementalUpdater::toContiguousPairs(const QList<int>& unsorted)
-+{
-+ // Take the given indices and return them as contiguous pairs [begin, end]
-+
-+ QList<QPair<int, int> > pairs;
-+
-+ if (unsorted.isEmpty())
-+ {
-+ return pairs;
-+ }
-+
-+ QList<int> indices(unsorted);
-+ qSort(indices);
-+
-+ QPair<int, int> pair(indices.first(), indices.first());
-+
-+ for (int i=1; i<indices.size(); ++i)
-+ {
-+ const int &index = indices.at(i);
-+
-+ if (index == pair.second + 1)
-+ {
-+ pair.second = index;
-+ continue;
-+ }
-+
-+ pairs << pair; // insert last pair
-+ pair.first = index;
-+ pair.second = index;
-+ }
-+
-+ pairs << pair;
-+
-+ return pairs;
-+}
-+
-+// ------------ QAbstractItemModel implementation -------------
-+
-+QVariant ImageModel::data(const QModelIndex& index, int role) const
-+{
-+ if (!d->isValid(index))
-+ {
-+ return QVariant();
-+ }
-+
-+ switch (role)
-+ {
-+ case Qt::DisplayRole:
-+ case Qt::ToolTipRole:
-+ return d->infos.at(index.row()).name();
-+
-+ case ImageModelPointerRole:
-+ return QVariant::fromValue(const_cast<ImageModel*>(this));
-+
-+ case ImageModelInternalId:
-+ return index.row();
-+
-+ case CreationDateRole:
-+ return d->infos.at(index.row()).dateTime();
-+
-+ case ExtraDataRole:
-+
-+ if (d->extraValueValid(index))
-+ {
-+ return d->extraValues.at(index.row());
-+ }
-+ else
-+ {
-+ return QVariant();
-+ }
-+
-+ case ExtraDataDuplicateCount:
-+ {
-+ qlonglong id = d->infos.at(index.row()).id();
-+ return numberOfIndexesForImageId(id);
-+ }
-+ }
-+
-+ return QVariant();
-+}
-+
-+QVariant ImageModel::headerData(int section, Qt::Orientation orientation, int role) const
-+{
-+ Q_UNUSED(section)
-+ Q_UNUSED(orientation)
-+ Q_UNUSED(role)
-+ return QVariant();
-+}
-+
-+int ImageModel::rowCount(const QModelIndex& parent) const
-+{
-+ if (parent.isValid())
-+ {
-+ return 0;
-+ }
-+
-+ return d->infos.size();
-+}
-+
-+Qt::ItemFlags ImageModel::flags(const QModelIndex& index) const
-+{
-+ if (!d->isValid(index))
-+ {
-+ return 0;
-+ }
-+
-+ Qt::ItemFlags f = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
-+
-+ f |= dragDropFlags(index);
-+
-+ return f;
-+}
-+
-+QModelIndex ImageModel::index(int row, int column, const QModelIndex& parent) const
-+{
-+ if (column != 0 || row < 0 || parent.isValid() || row >= d->infos.size())
-+ {
-+ return QModelIndex();
-+ }
-+
-+ return createIndex(row, 0);
-+}
-+
-+// ------------ Database watch -------------
-+
-+void ImageModel::slotImageChange(const ImageChangeset& changeset)
-+{
-+ if (d->infos.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ if (d->watchFlags & changeset.changes())
-+ {
-+ QItemSelection items;
-+
-+ foreach(const qlonglong& id, changeset.ids())
-+ {
-+ QModelIndex index = indexForImageId(id);
-+
-+ if (index.isValid())
-+ {
-+ items.select(index, index);
-+ }
-+ }
-+
-+ if (!items.isEmpty())
-+ {
-+ emitDataChangedForSelection(items);
-+ emit imageChange(changeset, items);
-+ }
-+ }
-+}
-+
-+void ImageModel::slotImageTagChange(const ImageTagChangeset& changeset)
-+{
-+ if (d->infos.isEmpty())
-+ {
-+ return;
-+ }
-+
-+ QItemSelection items;
-+
-+ foreach(const qlonglong& id, changeset.ids())
-+ {
-+ QModelIndex index = indexForImageId(id);
-+
-+ if (index.isValid())
-+ {
-+ items.select(index, index);
-+ }
-+ }
-+
-+ if (!items.isEmpty())
-+ {
-+ emitDataChangedForSelection(items);
-+ emit imageTagChange(changeset, items);
-+ }
-+}
-+
-+} // namespace Digikam
-diff --git a/libs/database/models/imagemodel.h b/libs/database/models/imagemodel.h
-new file mode 100644
-index 0000000..dcf94c2
---- /dev/null
-+++ b/libs/database/models/imagemodel.h
-@@ -0,0 +1,364 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Qt item model for database entries
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ *
-+ * 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 IMAGEMODEL_H
-+#define IMAGEMODEL_H
-+
-+// Qt includes
-+
-+#include <QAbstractListModel>
-+
-+// Local includes
-+
-+#include "dragdropimplementations.h"
-+#include "imageinfo.h"
-+#include "digikam_export.h"
-+
-+class QItemSelection;
-+
-+namespace Digikam
-+{
-+
-+class ImageChangeset;
-+class ImageTagChangeset;
-+
-+namespace DatabaseFields
-+{
-+class Set;
-+}
-+
-+class DIGIKAM_DATABASE_EXPORT ImageModel : public QAbstractListModel, public DragDropModelImplementation
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ enum ImageModelRoles
-+ {
-+ /// An ImageModel* pointer to this model
-+ ImageModelPointerRole = Qt::UserRole,
-+ ImageModelInternalId = Qt::UserRole + 1,
-+ /// Returns a thumbnail pixmap. May be implemented by subclasses.
-+ /// Returns either a valid pixmap or a null QVariant.
-+ ThumbnailRole = Qt::UserRole + 2,
-+ /// Returns a QDateTime with the creation date
-+ CreationDateRole = Qt::UserRole + 3,
-+ /// Return (optional) extraData field
-+ ExtraDataRole = Qt::UserRole + 5,
-+ /// Returns the number of duplicate indexes for the same image id
-+ ExtraDataDuplicateCount = Qt::UserRole + 6,
-+
-+ // Roles which are defined here but not implemented by ImageModel
-+ /// Returns position of item in Left Light Table preview.
-+ LTLeftPanelRole = Qt::UserRole + 50,
-+ /// Returns position of item in Right Light Table preview.
-+ LTRightPanelRole = Qt::UserRole + 51,
-+
-+ // For use by subclasses
-+ SubclassRoles = Qt::UserRole + 100,
-+ // For use by filter models
-+ FilterModelRoles = Qt::UserRole + 500
-+ };
-+
-+public:
-+
-+ explicit ImageModel(QObject* parent = 0);
-+ ~ImageModel();
-+
-+ /** If a cache is kept, lookup by file path is fast,
-+ * without a cache it is O(n). Default is false.
-+ */
-+ void setKeepsFilePathCache(bool keepCache);
-+ bool keepsFilePathCache() const;
-+
-+ /** Set a set of database fields to watch.
-+ * If either of these is changed, dataChanged() will be emitted.
-+ * Default is no flag (no signal will be emitted).
-+ */
-+ void setWatchFlags(const DatabaseFields::Set& set);
-+
-+ /** Returns the ImageInfo object, reference or image id from the underlying data
-+ * pointed to by the index.
-+ * If the index is not valid, imageInfo will return a null ImageInfo, imageId will
-+ * return 0, imageInfoRef must not be called with an invalid index.
-+ */
-+ ImageInfo imageInfo(const QModelIndex& index) const;
-+ ImageInfo& imageInfoRef(const QModelIndex& index) const;
-+ qlonglong imageId(const QModelIndex& index) const;
-+ QList<ImageInfo> imageInfos(const QList<QModelIndex>& indexes) const;
-+ QList<qlonglong> imageIds(const QList<QModelIndex>& indexes) const;
-+
-+ /** Returns the ImageInfo object, reference or image id from the underlying data
-+ * of the given row (parent is the invalid QModelIndex, column is 0).
-+ * Note that imageInfoRef will crash if index is invalid.
-+ */
-+ ImageInfo imageInfo(int row) const;
-+ ImageInfo& imageInfoRef(int row) const;
-+ qlonglong imageId(int row) const;
-+
-+ /** Return the index for the given ImageInfo or id, if contained in this model.
-+ */
-+ QModelIndex indexForImageInfo(const ImageInfo& info) const;
-+ QModelIndex indexForImageInfo(const ImageInfo& info, const QVariant& extraValue) const;
-+ QModelIndex indexForImageId(qlonglong id) const;
-+ QModelIndex indexForImageId(qlonglong id, const QVariant& extraValue) const;
-+ QList<QModelIndex> indexesForImageInfo(const ImageInfo& info) const;
-+ QList<QModelIndex> indexesForImageId(qlonglong id) const;
-+
-+ int numberOfIndexesForImageInfo(const ImageInfo& info) const;
-+ int numberOfIndexesForImageId(qlonglong id) const;
-+
-+ /** Returns the index or ImageInfo object from the underlying data
-+ * for the given file path. This is fast if keepsFilePathCache is enabled.
-+ * The file path is as returned by ImageInfo.filePath().
-+ * In case of multiple occurrences of the same file, the simpler variants return
-+ * any one found first, use the QList methods to retrieve all occurrences.
-+ */
-+ QModelIndex indexForPath(const QString& filePath) const;
-+ ImageInfo imageInfo(const QString& filePath) const;
-+ QList<QModelIndex> indexesForPath(const QString& filePath) const;
-+ QList<ImageInfo> imageInfos(const QString& filePath) const;
-+
-+ /** Main entry point for subclasses adding image infos to the model.
-+ * If you list entries not unique per image id, you must add an extraValue
-+ * so that every entry is unique by imageId and extraValues.
-+ * Please note that these methods do not prevent addition of duplicate entries.
-+ */
-+ void addImageInfo(const ImageInfo& info);
-+ void addImageInfos(const QList<ImageInfo>& infos);
-+ void addImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+
-+ /** Clears image infos and resets model.
-+ */
-+ void clearImageInfos();
-+
-+ /** Clears and adds the infos.
-+ */
-+ void setImageInfos(const QList<ImageInfo>& infos);
-+
-+ /**
-+ * Directly remove the given indexes or infos from the model.
-+ */
-+ void removeIndex(const QModelIndex& indexes);
-+ void removeIndexes(const QList<QModelIndex>& indexes);
-+ void removeImageInfo(const ImageInfo& info);
-+ void removeImageInfos(const QList<ImageInfo>& infos);
-+ void removeImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+
-+ /**
-+ * addImageInfo() is asynchronous if a prepocessor is set.
-+ * This method first adds the info, synchronously.
-+ * Only afterwards, the preprocessor will have the opportunity to process it.
-+ * This method also bypasses any incremental updates.
-+ * Please note that these methods do not prevent addition of duplicate entries.
-+ */
-+ void addImageInfoSynchronously(const ImageInfo& info);
-+ void addImageInfosSynchronously(const QList<ImageInfo>& infos);
-+ void addImageInfosSynchronously(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+
-+ /**
-+ * Add the given entries. Method returns immediately, the
-+ * addition may happen later asynchronously.
-+ * These methods prevent the addition of duplicate entries.
-+ */
-+ void ensureHasImageInfo(const ImageInfo& info);
-+ void ensureHasImageInfos(const QList<ImageInfo>& infos);
-+ void ensureHasImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+
-+ /**
-+ * Ensure that all images grouped on the given leader are contained in the model.
-+ */
-+ void ensureHasGroupedImages(const ImageInfo& groupLeader);
-+
-+ QList<ImageInfo> imageInfos() const;
-+ QList<qlonglong> imageIds() const;
-+ QList<ImageInfo> uniqueImageInfos() const;
-+
-+ bool hasImage(qlonglong id) const;
-+ bool hasImage(const ImageInfo& info) const;
-+ bool hasImage(const ImageInfo& info, const QVariant& extraValue) const;
-+ bool hasImage(qlonglong id, const QVariant& extraValue) const;
-+
-+ bool isEmpty() const;
-+
-+ // Drag and Drop
-+ DECLARE_MODEL_DRAG_DROP_METHODS
-+
-+ /**
-+ * Install an object as a preprocessor for ImageInfos added to this model.
-+ * For every QList of ImageInfos added to addImageInfo, the signal preprocess()
-+ * will be emitted. The preprocessor may process the items and shall then readd
-+ * them by calling reAddImageInfos(). It may take some time to process.
-+ * It shall discard any held infos when the modelReset() signal is sent.
-+ * It shall call readdFinished() when no reset occurred and all infos on the way have been readded.
-+ * This means that only after calling this method, you shall make three connections
-+ * (preprocess -> your slot, your signal -> reAddImageInfos, your signal -> reAddingFinished)
-+ * and make or already hold a connection modelReset() -> your slot.
-+ * There is only one preprocessor at a time, a previously set object will be disconnected.
-+ */
-+ void setPreprocessor(QObject* processor);
-+ void unsetPreprocessor(QObject* processor);
-+
-+ /**
-+ * Returns true if this model is currently refreshing.
-+ * For a preprocessor this means that, although the preprocessor may currently have
-+ * processed all it got, more batches are to be expected.
-+ */
-+ bool isRefreshing() const;
-+
-+ /**
-+ * Enable sending of imageInfosAboutToBeRemoved and imageInfosRemoved signals.
-+ * Default: false
-+ */
-+ void setSendRemovalSignals(bool send);
-+
-+ virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
-+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
-+ virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
-+ virtual Qt::ItemFlags flags(const QModelIndex& index) const;
-+ virtual QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const;
-+
-+ /** Retrieves the imageInfo object from the data() method of the given index.
-+ * The index may be from a QSortFilterProxyModel as long as an ImageModel is at the end. */
-+ static ImageInfo retrieveImageInfo(const QModelIndex& index);
-+ static qlonglong retrieveImageId(const QModelIndex& index);
-+
-+Q_SIGNALS:
-+
-+ /** Informs that ImageInfos will be added to the model.
-+ * This signal is sent before the model data is changed and views are informed.
-+ */
-+ void imageInfosAboutToBeAdded(const QList<ImageInfo>& infos);
-+
-+ /** Informs that ImageInfos have been added to the model.
-+ * This signal is sent after the model data is changed and views are informed.
-+ */
-+ void imageInfosAdded(const QList<ImageInfo>& infos);
-+
-+ /** Informs that ImageInfos will be removed from the model.
-+ * This signal is sent before the model data is changed and views are informed.
-+ * Note: You need to explicitly enable sending of this signal. It is not sent
-+ * in clearImageInfos().
-+ */
-+ void imageInfosAboutToBeRemoved(const QList<ImageInfo>& infos);
-+
-+ /** Informs that ImageInfos have been removed from the model.
-+ * This signal is sent after the model data is changed and views are informed. *
-+ * Note: You need to explicitly enable sending of this signal. It is not sent
-+ * in clearImageInfos().
-+ */
-+ void imageInfosRemoved(const QList<ImageInfo>& infos);
-+
-+ /** Connect to this signal only if you are the current preprocessor.
-+ */
-+ void preprocess(const QList<ImageInfo>& infos, const QList<QVariant>&);
-+ void processAdded(const QList<ImageInfo>& infos, const QList<QVariant>&);
-+
-+ /** If an ImageChangeset affected indexes of this model with changes as set in watchFlags(),
-+ * this signal contains the changeset and the affected indexes.
-+ */
-+ void imageChange(const ImageChangeset&, const QItemSelection&);
-+
-+ /** If an ImageTagChangeset affected indexes of this model,
-+ * this signal contains the changeset and the affected indexes.
-+ */
-+ void imageTagChange(const ImageTagChangeset&, const QItemSelection&);
-+
-+ /** Signals that the model is right now ready to start an incremental refresh.
-+ * This is guaranteed only for the scope of emitting this signal.
-+ */
-+ void readyForIncrementalRefresh();
-+
-+ /** Signals that the model has finished currently with all scheduled
-+ * refreshing, full or incremental, and all preprocessing.
-+ * The model is in polished, clean situation right now.
-+ */
-+ void allRefreshingFinished();
-+
-+public Q_SLOTS:
-+
-+ void reAddImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+ void reAddingFinished();
-+
-+protected:
-+
-+ /** Subclasses that add ImageInfos in batches shall call startRefresh()
-+ * when they start sending batches and finishRefresh() when they have finished.
-+ * No incremental refreshes will be started while listing.
-+ * A clearImageInfos() always stops listing, calling finishRefresh() is then not necessary.
-+ */
-+ void startRefresh();
-+ void finishRefresh();
-+
-+ /** As soon as the model is ready to start an incremental refresh, the signal
-+ * readyForIncrementalRefresh() will be emitted. The signal will be emitted inline
-+ * if the model is ready right now.
-+ */
-+ void requestIncrementalRefresh();
-+ bool hasIncrementalRefreshPending() const;
-+
-+ /** Starts an incremental refresh operation. You shall only call this method from a slot
-+ * connected to readyForIncrementalRefresh(). To initiate an incremental refresh,
-+ * call requestIncrementalRefresh().
-+ */
-+ void startIncrementalRefresh();
-+ void finishIncrementalRefresh();
-+
-+ void emitDataChangedForAll();
-+ void emitDataChangedForSelection(const QItemSelection& selection);
-+
-+ // Called when the internal storage is cleared
-+ virtual void imageInfosCleared() {};
-+
-+ // Called before rowsAboutToBeRemoved
-+ virtual void imageInfosAboutToBeRemoved(int /*begin*/, int /*end*/) {};
-+
-+protected Q_SLOTS:
-+
-+ virtual void slotImageChange(const ImageChangeset& changeset);
-+ virtual void slotImageTagChange(const ImageTagChangeset& changeset);
-+
-+private:
-+
-+ void appendInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+ void appendInfosChecked(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+ void publiciseInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-+ void cleanSituationChecks();
-+ void removeRowPairsWithCheck(const QList<QPair<int, int> >& toRemove);
-+ void removeRowPairs(const QList<QPair<int, int> >& toRemove);
-+
-+public:
-+
-+ // Declared public because it's used in ImageModelIncrementalUpdater class
-+ class Private;
-+
-+private:
-+
-+ Private* const d;
-+};
-+
-+} // namespace Digikam
-+
-+Q_DECLARE_METATYPE(Digikam::ImageModel*)
-+
-+#endif // IMAGEMODEL_H
-diff --git a/libs/database/models/imagesortsettings.cpp b/libs/database/models/imagesortsettings.cpp
-new file mode 100644
-index 0000000..39ee6e1
---- /dev/null
-+++ b/libs/database/models/imagesortsettings.cpp
-@@ -0,0 +1,400 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Filter values for use with ImageFilterModel
-+ *
-+ * Copyright (C) 2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagesortsettings.h"
-+
-+// Qt includes
-+
-+#include <QDateTime>
-+#include <QRectF>
-+
-+// Local includes
-+
-+#include "coredbfields.h"
-+#include "imageinfo.h"
-+
-+namespace Digikam
-+{
-+
-+ImageSortSettings::ImageSortSettings()
-+{
-+ categorizationMode = NoCategories;
-+ categorizationSortOrder = DefaultOrder;
-+ categorizationCaseSensitivity = Qt::CaseSensitive;
-+ sortRole = SortByFileName;
-+ sortOrder = DefaultOrder;
-+ strTypeNatural = true;
-+ sortCaseSensitivity = Qt::CaseSensitive;
-+ currentCategorizationSortOrder = Qt::AscendingOrder;
-+ currentSortOrder = Qt::AscendingOrder;
-+}
-+
-+bool ImageSortSettings::operator==(const ImageSortSettings& other) const
-+{
-+ return
-+ categorizationMode == other.categorizationMode &&
-+ categorizationSortOrder == other.categorizationSortOrder &&
-+ categorizationCaseSensitivity == other.categorizationCaseSensitivity &&
-+ sortRole == other.sortRole &&
-+ sortOrder == other.sortOrder &&
-+ sortCaseSensitivity == other.sortCaseSensitivity;
-+}
-+
-+void ImageSortSettings::setCategorizationMode(CategorizationMode mode)
-+{
-+ categorizationMode = mode;
-+
-+ if (categorizationSortOrder == DefaultOrder)
-+ {
-+ currentCategorizationSortOrder = defaultSortOrderForCategorizationMode(categorizationMode);
-+ }
-+}
-+
-+void ImageSortSettings::setCategorizationSortOrder(SortOrder order)
-+{
-+ categorizationSortOrder = order;
-+
-+ if (categorizationSortOrder == DefaultOrder)
-+ {
-+ currentCategorizationSortOrder = defaultSortOrderForCategorizationMode(categorizationMode);
-+ }
-+ else
-+ {
-+ currentCategorizationSortOrder = (Qt::SortOrder)categorizationSortOrder;
-+ }
-+}
-+
-+void ImageSortSettings::setSortRole(SortRole role)
-+{
-+ sortRole = role;
-+
-+ if (sortOrder == DefaultOrder)
-+ {
-+ currentSortOrder = defaultSortOrderForSortRole(sortRole);
-+ }
-+}
-+
-+void ImageSortSettings::setSortOrder(SortOrder order)
-+{
-+ sortOrder = order;
-+
-+ if (sortOrder == DefaultOrder)
-+ {
-+ currentSortOrder = defaultSortOrderForSortRole(sortRole);
-+ }
-+ else
-+ {
-+ currentSortOrder = (Qt::SortOrder)order;
-+ }
-+}
-+
-+void ImageSortSettings::setStringTypeNatural(bool natural)
-+{
-+ strTypeNatural = natural;
-+}
-+
-+Qt::SortOrder ImageSortSettings::defaultSortOrderForCategorizationMode(CategorizationMode mode)
-+{
-+ switch (mode)
-+ {
-+ case NoCategories:
-+ case OneCategory:
-+ case CategoryByAlbum:
-+ case CategoryByFormat:
-+ default:
-+ return Qt::AscendingOrder;
-+ }
-+}
-+
-+Qt::SortOrder ImageSortSettings::defaultSortOrderForSortRole(SortRole role)
-+{
-+ switch (role)
-+ {
-+ case SortByFileName:
-+ case SortByFilePath:
-+ return Qt::AscendingOrder;
-+ case SortByFileSize:
-+ return Qt::DescendingOrder;
-+ case SortByModificationDate:
-+ case SortByCreationDate:
-+ return Qt::AscendingOrder;
-+ case SortByRating:
-+ case SortByImageSize:
-+ return Qt::DescendingOrder;
-+ case SortByAspectRatio:
-+ return Qt::DescendingOrder;
-+ case SortBySimilarity:
-+ return Qt::DescendingOrder;
-+ default:
-+ return Qt::AscendingOrder;
-+ }
-+}
-+
-+int ImageSortSettings::compareCategories(const ImageInfo& left, const ImageInfo& right) const
-+{
-+ switch (categorizationMode)
-+ {
-+ case NoCategories:
-+ case OneCategory:
-+ return 0;
-+ case CategoryByAlbum:
-+ {
-+ int leftAlbum = left.albumId();
-+ int rightAlbum = right.albumId();
-+
-+ // return comparation result
-+ if (leftAlbum == rightAlbum)
-+ {
-+ return 0;
-+ }
-+ else if (lessThanByOrder(leftAlbum, rightAlbum, currentCategorizationSortOrder))
-+ {
-+ return -1;
-+ }
-+ else
-+ {
-+ return 1;
-+ }
-+ }
-+ case CategoryByFormat:
-+ {
-+ return naturalCompare(left.format(), right.format(),
-+ currentCategorizationSortOrder, categorizationCaseSensitivity, strTypeNatural);
-+ }
-+ default:
-+ return 0;
-+ }
-+}
-+
-+bool ImageSortSettings::lessThan(const ImageInfo& left, const ImageInfo& right) const
-+{
-+ int result = compare(left, right, sortRole);
-+
-+ if (result != 0)
-+ {
-+ return result < 0;
-+ }
-+
-+ // are they identical?
-+ if (left == right)
-+ {
-+ return false;
-+ }
-+
-+ // If left and right equal for first sort order, use a hierarchy of all sort orders
-+ if ( (result = compare(left, right, SortByFileName)) != 0)
-+ {
-+ return result < 0;
-+ }
-+
-+ if ( (result = compare(left, right, SortByCreationDate)) != 0)
-+ {
-+ return result < 0;
-+ }
-+
-+ if ( (result = compare(left, right, SortByModificationDate)) != 0)
-+ {
-+ return result < 0;
-+ }
-+
-+ if ( (result = compare(left, right, SortByFilePath)) != 0)
-+ {
-+ return result < 0;
-+ }
-+
-+ if ( (result = compare(left, right, SortByFileSize)) != 0)
-+ {
-+ return result < 0;
-+ }
-+
-+ if ( (result = compare(left, right, SortBySimilarity)) != 0)
-+ {
-+ return result < 0;
-+ }
-+
-+ return false;
-+}
-+
-+int ImageSortSettings::compare(const ImageInfo& left, const ImageInfo& right) const
-+{
-+ return compare(left, right, sortRole);
-+}
-+
-+int ImageSortSettings::compare(const ImageInfo& left, const ImageInfo& right, SortRole role) const
-+{
-+ switch (role)
-+ {
-+ case SortByFileName:
-+ {
-+ bool versioning = (left.name().contains(QLatin1String("_v"), Qt::CaseInsensitive) ||
-+ right.name().contains(QLatin1String("_v"), Qt::CaseInsensitive));
-+ return naturalCompare(left.name(), right.name(), currentSortOrder, sortCaseSensitivity, strTypeNatural, versioning);
-+ }
-+ case SortByFilePath:
-+ return naturalCompare(left.filePath(), right.filePath(), currentSortOrder, sortCaseSensitivity, strTypeNatural);
-+ case SortByFileSize:
-+ return compareByOrder(left.fileSize(), right.fileSize(), currentSortOrder);
-+ case SortByModificationDate:
-+ return compareByOrder(left.modDateTime(), right.modDateTime(), currentSortOrder);
-+ case SortByCreationDate:
-+ return compareByOrder(left.dateTime(), right.dateTime(), currentSortOrder);
-+ case SortByRating:
-+ // I have the feeling that inverting the sort order for rating is the natural order
-+ return - compareByOrder(left.rating(), right.rating(), currentSortOrder);
-+ case SortByImageSize:
-+ {
-+ QSize leftSize = left.dimensions();
-+ QSize rightSize = right.dimensions();
-+ int leftPixels = leftSize.width() * leftSize.height();
-+ int rightPixels = rightSize.width() * rightSize.height();
-+ return compareByOrder(leftPixels, rightPixels, currentSortOrder);
-+ }
-+ case SortByAspectRatio:
-+ {
-+ QSize leftSize = left.dimensions();
-+ QSize rightSize = right.dimensions();
-+ int leftAR = (double(leftSize.width()) / double(leftSize.height())) * 1000000;
-+ int rightAR = (double(rightSize.width()) / double(rightSize.height())) * 1000000;
-+ return compareByOrder(leftAR, rightAR, currentSortOrder);
-+ }
-+ case SortBySimilarity:
-+ {
-+ qlonglong leftReferenceImageId = left.currentReferenceImage();
-+ qlonglong rightReferenceImageId = right.currentReferenceImage();
-+ // make sure that the original image has always the highest similarity.
-+ double leftSimilarity = left.id() == leftReferenceImageId ? 1.1 : left.currentSimilarity();
-+ double rightSimilarity = right.id() == rightReferenceImageId ? 1.1 : right.currentSimilarity();
-+ return compareByOrder(leftSimilarity, rightSimilarity, currentSortOrder);
-+ }
-+ default:
-+ return 1;
-+ }
-+}
-+
-+bool ImageSortSettings::lessThan(const QVariant& left, const QVariant& right) const
-+{
-+ if (left.type() != right.type())
-+ {
-+ return false;
-+ }
-+
-+ switch (left.type())
-+ {
-+ case QVariant::Int:
-+ return compareByOrder(left.toInt(), right.toInt(), currentSortOrder);
-+ case QVariant::UInt:
-+ return compareByOrder(left.toUInt(), right.toUInt(), currentSortOrder);
-+ case QVariant::LongLong:
-+ return compareByOrder(left.toLongLong(), right.toLongLong(), currentSortOrder);
-+ case QVariant::ULongLong:
-+ return compareByOrder(left.toULongLong(), right.toULongLong(), currentSortOrder);
-+ case QVariant::Double:
-+ return compareByOrder(left.toDouble(), right.toDouble(), currentSortOrder);
-+ case QVariant::Date:
-+ return compareByOrder(left.toDate(), right.toDate(), currentSortOrder);
-+ case QVariant::DateTime:
-+ return compareByOrder(left.toDateTime(), right.toDateTime(), currentSortOrder);
-+ case QVariant::Time:
-+ return compareByOrder(left.toTime(), right.toTime(), currentSortOrder);
-+ case QVariant::Rect:
-+ case QVariant::RectF:
-+ {
-+ QRectF rectLeft = left.toRectF();
-+ QRectF rectRight = right.toRectF();
-+ int result;
-+
-+ if ((result = compareByOrder(rectLeft.top(), rectRight.top(), currentSortOrder)) != 0)
-+ {
-+ return result < 0;
-+ }
-+
-+ if ((result = compareByOrder(rectLeft.left(), rectRight.left(), currentSortOrder)) != 0)
-+ {
-+ return result < 0;
-+ }
-+
-+ QSizeF sizeLeft = rectLeft.size(), sizeRight = rectRight.size();
-+
-+ if ((result = compareByOrder(sizeLeft.width()*sizeLeft.height(), sizeRight.width()*sizeRight.height(), currentSortOrder)) != 0)
-+ {
-+ return result < 0;
-+ }
-+ // FIXME: fall through?? If not, add "break" here
-+ }
-+ default:
-+ return naturalCompare(left.toString(), right.toString(), currentSortOrder, sortCaseSensitivity, strTypeNatural);
-+ }
-+}
-+
-+DatabaseFields::Set ImageSortSettings::watchFlags() const
-+{
-+ DatabaseFields::Set set;
-+
-+ switch (sortRole)
-+ {
-+ case SortByFileName:
-+ set |= DatabaseFields::Name;
-+ break;
-+ case SortByFilePath:
-+ set |= DatabaseFields::Name;
-+ break;
-+ case SortByFileSize:
-+ set |= DatabaseFields::FileSize;
-+ break;
-+ case SortByModificationDate:
-+ set |= DatabaseFields::ModificationDate;
-+ break;
-+ case SortByCreationDate:
-+ set |= DatabaseFields::CreationDate;
-+ break;
-+ case SortByRating:
-+ set |= DatabaseFields::Rating;
-+ break;
-+ case SortByImageSize:
-+ set |= DatabaseFields::Width | DatabaseFields::Height;
-+ break;
-+ case SortByAspectRatio:
-+ set |= DatabaseFields::Width | DatabaseFields::Height;
-+ break;
-+ case SortBySimilarity:
-+ // TODO: Not sure what to do here....
-+ set |= DatabaseFields::Name;
-+ break;
-+ }
-+
-+ switch (categorizationMode)
-+ {
-+ case NoCategories:
-+ case OneCategory:
-+ case CategoryByAlbum:
-+ break;
-+ case CategoryByFormat:
-+ set |= DatabaseFields::Format;
-+ break;
-+ }
-+
-+ return set;
-+}
-+
-+} // namespace Digikam
-diff --git a/libs/database/models/imagesortsettings.h b/libs/database/models/imagesortsettings.h
-new file mode 100644
-index 0000000..2a5fd8c
---- /dev/null
-+++ b/libs/database/models/imagesortsettings.h
-@@ -0,0 +1,225 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-05-31
-+ * Description : Sort settings for use with ImageFilterModel
-+ *
-+ * Copyright (C) 2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ *
-+ * 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 IMAGESORTSETTINGS_H
-+#define IMAGESORTSETTINGS_H
-+
-+// Qt includes
-+
-+#include <QHash>
-+#include <QList>
-+#include <QMap>
-+#include <QString>
-+#include <QCollator>
-+
-+// Local includes
-+
-+#include "digikam_export.h"
-+
-+namespace Digikam
-+{
-+
-+class ImageInfo;
-+
-+namespace DatabaseFields
-+{
-+ class Set;
-+}
-+
-+class DIGIKAM_DATABASE_EXPORT ImageSortSettings
-+{
-+public:
-+
-+ ImageSortSettings();
-+
-+ bool operator==(const ImageSortSettings& other) const;
-+
-+ /** Compares the categories of left and right.
-+ * Return -1 if left is less than right, 0 if both fall in the same category,
-+ * and 1 if left is greater than right.
-+ * Adheres to set categorization mode and current category sort order.
-+ */
-+ int compareCategories(const ImageInfo& left, const ImageInfo& right) const;
-+
-+ /** Returns true if left is less than right.
-+ * Adheres to current sort role and sort order.
-+ */
-+ bool lessThan(const ImageInfo& left, const ImageInfo& right) const;
-+
-+ /** Compares the ImageInfos left and right.
-+ * Return -1 if left is less than right, 1 if left is greater than right,
-+ * and 0 if left equals right comparing the current sort role's value.
-+ * Adheres to set sort role and sort order.
-+ */
-+ int compare(const ImageInfo& left, const ImageInfo& right) const;
-+
-+ /** Returns true if left QVariant is less than right.
-+ * Adheres to current sort role and sort order.
-+ * Use for extraValue, if necessary.
-+ */
-+ bool lessThan(const QVariant& left, const QVariant& right) const;
-+
-+ enum SortOrder
-+ {
-+ AscendingOrder = Qt::AscendingOrder,
-+ DescendingOrder = Qt::DescendingOrder,
-+ DefaultOrder /// sort order depends on the chosen sort role
-+ };
-+
-+ /// --- Categories ---
-+
-+ enum CategorizationMode
-+ {
-+ NoCategories, /// categorization switched off
-+ OneCategory, /// all items in one global category
-+ CategoryByAlbum,
-+ CategoryByFormat
-+ };
-+
-+ CategorizationMode categorizationMode;
-+ SortOrder categorizationSortOrder;
-+
-+ void setCategorizationMode(CategorizationMode mode);
-+ void setCategorizationSortOrder(SortOrder order);
-+
-+ /// Only Ascending or Descending, never DefaultOrder
-+ Qt::SortOrder currentCategorizationSortOrder;
-+ Qt::CaseSensitivity categorizationCaseSensitivity;
-+
-+ bool isCategorized() const { return categorizationMode >= CategoryByAlbum; }
-+
-+ /// --- Image Sorting ---
-+
-+ enum SortRole
-+ {
-+ // Note: For legacy reasons, the order of the first five entries must remain unchanged
-+ SortByFileName,
-+ SortByFilePath,
-+ SortByCreationDate,
-+ SortByFileSize,
-+ SortByRating,
-+ SortByModificationDate,
-+ SortByImageSize, // pixel number
-+ SortByAspectRatio, // width / height * 100000
-+ SortBySimilarity
-+ };
-+
-+ SortRole sortRole;
-+ SortOrder sortOrder;
-+ bool strTypeNatural;
-+
-+ void setSortRole(SortRole role);
-+ void setSortOrder(SortOrder order);
-+ void setStringTypeNatural(bool natural);
-+
-+ Qt::SortOrder currentSortOrder;
-+ Qt::CaseSensitivity sortCaseSensitivity;
-+
-+ int compare(const ImageInfo& left, const ImageInfo& right, SortRole sortRole) const;
-+
-+ // --- ---
-+
-+ static Qt::SortOrder defaultSortOrderForCategorizationMode(CategorizationMode mode);
-+ static Qt::SortOrder defaultSortOrderForSortRole(SortRole role);
-+
-+ /// --- Change notification ---
-+
-+ /** Returns database fields a change in which would affect the current sorting.
-+ */
-+ DatabaseFields::Set watchFlags() const;
-+
-+ /// --- Utilities ---
-+
-+ /** Returns a < b if sortOrder is Ascending, or b < a if order is descending.
-+ */
-+ template <typename T>
-+ static inline bool lessThanByOrder(const T& a, const T& b, Qt::SortOrder sortOrder)
-+ {
-+ if (sortOrder == Qt::AscendingOrder)
-+ {
-+ return a < b;
-+ }
-+ else
-+ {
-+ return b < a;
-+ }
-+ }
-+
-+ /** Returns the usual compare result of -1, 0, or 1 for lessThan, equals and greaterThan.
-+ */
-+ template <typename T>
-+ static inline int compareValue(const T& a, const T& b)
-+ {
-+ if (a == b)
-+ {
-+ return 0;
-+ }
-+
-+ if (a < b)
-+ {
-+ return -1;
-+ }
-+ else
-+ {
-+ return 1;
-+ }
-+ }
-+
-+ /** Takes a typical result from a compare method (0 is equal, -1 is less than, 1 is greater than)
-+ * and applies the given sort order to it.
-+ */
-+ static inline int compareByOrder(int compareResult, Qt::SortOrder sortOrder)
-+ {
-+ if (sortOrder == Qt::AscendingOrder)
-+ {
-+ return compareResult;
-+ }
-+ else
-+ {
-+ return - compareResult;
-+ }
-+ }
-+
-+ template <typename T>
-+ static inline int compareByOrder(const T& a, const T& b, Qt::SortOrder sortOrder)
-+ {
-+ return compareByOrder(compareValue(a, b), sortOrder);
-+ }
-+
-+ /** Compares the two string by natural comparison and adheres to given sort order
-+ */
-+ static inline int naturalCompare(const QString& a, const QString& b, Qt::SortOrder sortOrder,
-+ Qt::CaseSensitivity caseSensitive = Qt::CaseSensitive,
-+ bool natural = true, bool versioning = false)
-+ {
-+ QCollator collator;
-+ collator.setNumericMode(natural);
-+ collator.setIgnorePunctuation(versioning);
-+ collator.setCaseSensitivity(caseSensitive);
-+ return (compareByOrder(collator.compare(a, b), sortOrder));
-+ }
-+};
-+
-+} // namespace Digikam
-+
-+#endif // IMAGESORTSETTINGS_H
-diff --git a/libs/database/models/imagethumbnailmodel.cpp b/libs/database/models/imagethumbnailmodel.cpp
-new file mode 100644
-index 0000000..b7f5661
---- /dev/null
-+++ b/libs/database/models/imagethumbnailmodel.cpp
-@@ -0,0 +1,323 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Qt item model for database entries with support for thumbnail loading
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles 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 "imagethumbnailmodel.h"
-+
-+// Qt includes
-+
-+#include <QHash>
-+
-+// Local includes
-+
-+#include "digikam_debug.h"
-+#include "thumbnailloadthread.h"
-+#include "digikam_export.h"
-+#include "digikam_globals.h"
-+
-+namespace Digikam
-+{
-+
-+class ImageThumbnailModel::ImageThumbnailModelPriv
-+{
-+public:
-+
-+ ImageThumbnailModelPriv() :
-+ thread(0),
-+ preloadThread(0),
-+ thumbSize(0),
-+ lastGlobalThumbSize(0),
-+ preloadThumbSize(0),
-+ emitDataChanged(true)
-+ {
-+ staticListContainingThumbnailRole << ImageModel::ThumbnailRole;
-+ }
-+
-+ ThumbnailLoadThread* thread;
-+ ThumbnailLoadThread* preloadThread;
-+ ThumbnailSize thumbSize;
-+ ThumbnailSize lastGlobalThumbSize;
-+ ThumbnailSize preloadThumbSize;
-+ QRect detailRect;
-+ QVector<int> staticListContainingThumbnailRole;
-+
-+ bool emitDataChanged;
-+
-+ int preloadThumbnailSize() const
-+ {
-+ if (preloadThumbSize.size())
-+ {
-+ return preloadThumbSize.size();
-+ }
-+
-+ return thumbSize.size();
-+ }
-+};
-+
-+ImageThumbnailModel::ImageThumbnailModel(QObject* parent)
-+ : ImageModel(parent), d(new ImageThumbnailModelPriv)
-+{
-+ setKeepsFilePathCache(true);
-+}
-+
-+ImageThumbnailModel::~ImageThumbnailModel()
-+{
-+ delete d->preloadThread;
-+ delete d;
-+}
-+
-+void ImageThumbnailModel::setThumbnailLoadThread(ThumbnailLoadThread* thread)
-+{
-+ d->thread = thread;
-+
-+ connect(d->thread, SIGNAL(signalThumbnailLoaded(LoadingDescription,QPixmap)),
-+ this, SLOT(slotThumbnailLoaded(LoadingDescription,QPixmap)));
-+}
-+
-+ThumbnailLoadThread* ImageThumbnailModel::thumbnailLoadThread() const
-+{
-+ return d->thread;
-+}
-+
-+ThumbnailSize ImageThumbnailModel::thumbnailSize() const
-+{
-+ return d->thumbSize;
-+}
-+
-+void ImageThumbnailModel::setThumbnailSize(const ThumbnailSize& size)
-+{
-+ d->lastGlobalThumbSize = size;
-+ d->thumbSize = size;
-+}
-+
-+void ImageThumbnailModel::setPreloadThumbnailSize(const ThumbnailSize& size)
-+{
-+ d->preloadThumbSize = size;
-+}
-+
-+void ImageThumbnailModel::setEmitDataChanged(bool emitSignal)
-+{
-+ d->emitDataChanged = emitSignal;
-+}
-+
-+void ImageThumbnailModel::setPreloadThumbnails(bool preload)
-+{
-+ if (preload)
-+ {
-+ if (!d->preloadThread)
-+ {
-+ d->preloadThread = new ThumbnailLoadThread;
-+ d->preloadThread->setPixmapRequested(false);
-+ d->preloadThread->setPriority(QThread::LowestPriority);
-+ }
-+
-+ connect(this, SIGNAL(allRefreshingFinished()),
-+ this, SLOT(preloadAllThumbnails()));
-+ }
-+ else
-+ {
-+ delete d->preloadThread;
-+ d->preloadThread = 0;
-+ disconnect(this, SIGNAL(allRefreshingFinished()),
-+ this, SLOT(preloadAllThumbnails()));
-+ }
-+}
-+
-+void ImageThumbnailModel::prepareThumbnails(const QList<QModelIndex>& indexesToPrepare)
-+{
-+ prepareThumbnails(indexesToPrepare, d->thumbSize);
-+}
-+
-+void ImageThumbnailModel::prepareThumbnails(const QList<QModelIndex>& indexesToPrepare, const ThumbnailSize& thumbSize)
-+{
-+ if (!d->thread)
-+ {
-+ return;
-+ }
-+
-+ QList<ThumbnailIdentifier> ids;
-+ foreach(const QModelIndex& index, indexesToPrepare)
-+ {
-+ ids << imageInfoRef(index).thumbnailIdentifier();
-+ }
-+ d->thread->findGroup(ids, thumbSize.size());
-+}
-+
-+void ImageThumbnailModel::preloadThumbnails(const QList<ImageInfo>& infos)
-+{
-+ if (!d->preloadThread)
-+ {
-+ return;
-+ }
-+
-+ QList<ThumbnailIdentifier> ids;
-+ foreach(const ImageInfo& info, infos)
-+ {
-+ ids << info.thumbnailIdentifier();
-+ }
-+ d->preloadThread->pregenerateGroup(ids, d->preloadThumbnailSize());
-+}
-+
-+void ImageThumbnailModel::preloadThumbnails(const QList<QModelIndex>& indexesToPreload)
-+{
-+ if (!d->preloadThread)
-+ {
-+ return;
-+ }
-+
-+ QList<ThumbnailIdentifier> ids;
-+ foreach(const QModelIndex& index, indexesToPreload)
-+ {
-+ ids << imageInfoRef(index).thumbnailIdentifier();
-+ }
-+ d->preloadThread->stopAllTasks();
-+ d->preloadThread->pregenerateGroup(ids, d->preloadThumbnailSize());
-+}
-+
-+void ImageThumbnailModel::preloadAllThumbnails()
-+{
-+ preloadThumbnails(imageInfos());
-+}
-+
-+void ImageThumbnailModel::imageInfosCleared()
-+{
-+ if (d->preloadThread)
-+ {
-+ d->preloadThread->stopAllTasks();
-+ }
-+}
-+
-+QVariant ImageThumbnailModel::data(const QModelIndex& index, int role) const
-+{
-+ if (role == ThumbnailRole && d->thread && index.isValid())
-+ {
-+ QPixmap thumbnail;
-+ ImageInfo info = imageInfo(index);
-+ QString path = info.filePath();
-+
-+ if (info.isNull())
-+ {
-+ return QVariant(QVariant::Pixmap);
-+ }
-+
-+ if (!d->detailRect.isNull())
-+ {
-+ if (d->thread->find(info.thumbnailIdentifier(), d->detailRect, thumbnail, d->thumbSize.size()))
-+ {
-+ return thumbnail;
-+ }
-+ }
-+ else
-+ {
-+ if (d->thread->find(info.thumbnailIdentifier(), thumbnail, d->thumbSize.size()))
-+ {
-+ return thumbnail;
-+ }
-+ }
-+
-+ return QVariant(QVariant::Pixmap);
-+ }
-+
-+ return ImageModel::data(index, role);
-+}
-+
-+bool ImageThumbnailModel::setData(const QModelIndex& index, const QVariant& value, int role)
-+{
-+ if (role == ThumbnailRole)
-+ {
-+ switch (value.type())
-+ {
-+ case QVariant::Invalid:
-+ d->thumbSize = d->lastGlobalThumbSize;
-+ d->detailRect = QRect();
-+ break;
-+
-+ case QVariant::Int:
-+
-+ if (value.isNull())
-+ {
-+ d->thumbSize = d->lastGlobalThumbSize;
-+ }
-+ else
-+ {
-+ d->thumbSize = value.toInt();
-+ }
-+ break;
-+
-+ case QVariant::Rect:
-+
-+ if (value.isNull())
-+ {
-+ d->detailRect = QRect();
-+ }
-+ else
-+ {
-+ d->detailRect = value.toRect();
-+ }
-+ break;
-+
-+ default:
-+ break;
-+ }
-+ }
-+
-+ return ImageModel::setData(index, value, role);
-+}
-+
-+void ImageThumbnailModel::slotThumbnailLoaded(const LoadingDescription& loadingDescription, const QPixmap& thumb)
-+{
-+ if (thumb.isNull())
-+ {
-+ return;
-+ }
-+
-+ // In case of multiple occurrence, we currently do not know which thumbnail is this. Signal change on all.
-+ QModelIndexList indexes;
-+ ThumbnailIdentifier thumbId = loadingDescription.thumbnailIdentifier();
-+ if (thumbId.filePath.isEmpty())
-+ {
-+ indexes = indexesForImageId(thumbId.id);
-+ }
-+ else
-+ {
-+ indexes = indexesForPath(thumbId.filePath);
-+ }
-+ foreach(const QModelIndex& index, indexes)
-+ {
-+ if (thumb.isNull())
-+ {
-+ emit thumbnailFailed(index, loadingDescription.previewParameters.size);
-+ }
-+ else
-+ {
-+ emit thumbnailAvailable(index, loadingDescription.previewParameters.size);
-+
-+ if (d->emitDataChanged)
-+ {
-+ emit dataChanged(index, index, d->staticListContainingThumbnailRole);
-+ }
-+ }
-+ }
-+}
-+
-+} // namespace Digikam
-diff --git a/libs/database/models/imagethumbnailmodel.h b/libs/database/models/imagethumbnailmodel.h
-new file mode 100644
-index 0000000..366ca65
---- /dev/null
-+++ b/libs/database/models/imagethumbnailmodel.h
-@@ -0,0 +1,140 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2009-03-05
-+ * Description : Qt item model for database entries with support for thumbnail loading
-+ *
-+ * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-+ * Copyright (C) 2011 by Gilles Caulier <caulier dot gilles 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 IMAGETHUMBNAILMODEL_H
-+#define IMAGETHUMBNAILMODEL_H
-+
-+// Local includes
-+
-+#include "imagemodel.h"
-+#include "thumbnailsize.h"
-+#include "digikam_export.h"
-+
-+namespace Digikam
-+{
-+
-+class LoadingDescription;
-+class ThumbnailLoadThread;
-+
-+class DIGIKAM_DATABASE_EXPORT ImageThumbnailModel : public ImageModel
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ /**
-+ * An ImageModel that supports thumbnail loading.
-+ * You need to set a ThumbnailLoadThread to enable thumbnail loading.
-+ * Adjust the thumbnail size to your needs.
-+ * Note that setKeepsFilePathCache is enabled per default.
-+ */
-+ explicit ImageThumbnailModel(QObject* parent);
-+ ~ImageThumbnailModel();
-+
-+ /** Enable thumbnail loading and set the thread that shall be used.
-+ * The thumbnail size of this thread will be adjusted.
-+ */
-+ void setThumbnailLoadThread(ThumbnailLoadThread* thread);
-+ ThumbnailLoadThread* thumbnailLoadThread() const;
-+
-+ /// Set the thumbnail size to use
-+ void setThumbnailSize(const ThumbnailSize& thumbSize);
-+
-+ /// If you want to fix a size for preloading, do it here.
-+ void setPreloadThumbnailSize(const ThumbnailSize& thumbSize);
-+
-+ void setExifRotate(bool rotate);
-+
-+ /**
-+ * Enable emitting dataChanged() when a thumbnail becomes available.
-+ * The thumbnailAvailable() signal will be emitted in any case.
-+ * Default is true.
-+ */
-+ void setEmitDataChanged(bool emitSignal);
-+
-+ /**
-+ * Enable preloading of thumbnails:
-+ * If preloading is enabled, for every entry in the model a thumbnail generation is started.
-+ * Default: false.
-+ */
-+ void setPreloadThumbnails(bool preload);
-+
-+ ThumbnailSize thumbnailSize() const;
-+
-+ /**
-+ * Handles the ThumbnailRole.
-+ * If the pixmap is available, returns it in the QVariant.
-+ * If it still needs to be loaded, returns a null QVariant and emits
-+ * thumbnailAvailable() as soon as it is available.
-+ */
-+ virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
-+
-+ /**
-+ * You can override the current thumbnail size by giving an integer value for ThumbnailRole.
-+ * Set a null QVariant to use the thumbnail size set by setThumbnailSize() again.
-+ * The index given here is ignored for this purpose.
-+ */
-+ virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::DisplayRole);
-+
-+public Q_SLOTS:
-+
-+ /** Prepare the thumbnail loading for the given indexes
-+ */
-+ void prepareThumbnails(const QList<QModelIndex>& indexesToPrepare);
-+ void prepareThumbnails(const QList<QModelIndex>& indexesToPrepare, const ThumbnailSize& thumbSize);
-+
-+ /**
-+ * Preload thumbnail for the given infos resp. indexes.
-+ * Note: Use setPreloadThumbnails to automatically preload all entries in the model.
-+ * Note: This only ensures thumbnail generation. It is not guaranteed that pixmaps
-+ * are stored in the cache. For thumbnails that are expect to be drawn immediately,
-+ * include them in prepareThumbnails().
-+ * Note: Stops preloading of previously added thumbnails.
-+ */
-+ void preloadThumbnails(const QList<ImageInfo>&);
-+ void preloadThumbnails(const QList<QModelIndex>&);
-+ void preloadAllThumbnails();
-+
-+Q_SIGNALS:
-+
-+ void thumbnailAvailable(const QModelIndex& index, int requestedSize);
-+ void thumbnailFailed(const QModelIndex& index, int requestedSize);
-+
-+protected:
-+
-+ virtual void imageInfosCleared();
-+
-+protected Q_SLOTS:
-+
-+ void slotThumbnailLoaded(const LoadingDescription& loadingDescription, const QPixmap& thumb);
-+
-+private:
-+
-+ class ImageThumbnailModelPriv;
-+ ImageThumbnailModelPriv* const d;
-+};
-+
-+} // namespace Digikam
-+
-+#endif /* IMAGETHUMBNAILMODEL_H */
-diff --git a/libs/database/models/imageversionsmodel.cpp b/libs/database/models/imageversionsmodel.cpp
-new file mode 100644
-index 0000000..e6ba582
---- /dev/null
-+++ b/libs/database/models/imageversionsmodel.cpp
-@@ -0,0 +1,183 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2010-07-13
-+ * Description : Model for image versions
-+ *
-+ * Copyright (C) 2010 by Martin Klapetek <martin dot klapetek 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 "imageversionsmodel.h"
-+
-+// KDE includes
-+
-+#include <klocalizedstring.h>
-+
-+// Local includes
-+
-+#include "digikam_debug.h"
-+#include "workingwidget.h"
-+
-+namespace Digikam
-+{
-+
-+class ImageVersionsModel::Private
-+{
-+public:
-+
-+ Private()
-+ {
-+ data = 0;
-+ paintTree = false;
-+ }
-+
-+ ///Complete paths with filenames and tree level
-+ QList<QPair<QString, int> >* data;
-+ ///This is for delegate to paint it as selected
-+ QString currentSelectedImage;
-+ ///If true, the delegate will paint items as a tree
-+ ///if false, it will be painted as a list
-+ bool paintTree;
-+};
-+
-+ImageVersionsModel::ImageVersionsModel(QObject* parent)
-+ : QAbstractListModel(parent),
-+ d(new Private)
-+{
-+ d->data = new QList<QPair<QString, int> >;
-+}
-+
-+ImageVersionsModel::~ImageVersionsModel()
-+{
-+ //qDeleteAll(d->data);
-+ delete d;
-+}
-+
-+Qt::ItemFlags ImageVersionsModel::flags(const QModelIndex& index) const
-+{
-+ if (!index.isValid())
-+ {
-+ return 0;
-+ }
-+
-+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
-+}
-+
-+QVariant ImageVersionsModel::data(const QModelIndex& index, int role) const
-+{
-+ if (!index.isValid())
-+ {
-+ return QVariant();
-+ }
-+
-+ if (role == Qt::DisplayRole && !d->data->isEmpty())
-+ {
-+ return d->data->at(index.row()).first;
-+ }
-+ else if (role == Qt::UserRole && !d->data->isEmpty())
-+ {
-+ return d->data->at(index.row()).second;
-+ }
-+ else if (role == Qt::DisplayRole && d->data->isEmpty())
-+ {
-+ //TODO: make this text Italic
-+ return QVariant(QString(i18n("No image selected")));
-+ }
-+
-+ return QVariant();
-+}
-+
-+int ImageVersionsModel::rowCount(const QModelIndex& parent) const
-+{
-+ Q_UNUSED(parent)
-+ return d->data->count();
-+}
-+
-+void ImageVersionsModel::setupModelData(QList<QPair<QString, int> >& data)
-+{
-+ beginResetModel();
-+
-+ d->data->clear();
-+
-+ if (!data.isEmpty())
-+ {
-+ d->data->append(data);
-+ }
-+ else
-+ {
-+ d->data->append(qMakePair(QString(i18n("This is the original image")), 0));
-+ }
-+
-+ endResetModel();
-+}
-+
-+void ImageVersionsModel::clearModelData()
-+{
-+ beginResetModel();
-+
-+ if (!d->data->isEmpty())
-+ {
-+ d->data->clear();
-+ }
-+
-+ endResetModel();
-+}
-+
-+void ImageVersionsModel::slotAnimationStep()
-+{
-+ emit dataChanged(createIndex(0, 0), createIndex(rowCount()-1, 1));
-+}
-+
-+QString ImageVersionsModel::currentSelectedImage() const
-+{
-+ return d->currentSelectedImage;
-+}
-+
-+void ImageVersionsModel::setCurrentSelectedImage(const QString& path)
-+{
-+ d->currentSelectedImage = path;
-+}
-+
-+QModelIndex ImageVersionsModel::currentSelectedImageIndex() const
-+{
-+ return index(listIndexOf(d->currentSelectedImage), 0);
-+}
-+
-+bool ImageVersionsModel::paintTree() const
-+{
-+ return d->paintTree;
-+}
-+
-+void ImageVersionsModel::setPaintTree(bool paint)
-+{
-+ d->paintTree = paint;
-+}
-+
-+int ImageVersionsModel::listIndexOf(const QString& item) const
-+{
-+ for (int i = 0; i < d->data->size(); ++i)
-+ {
-+ if (d->data->at(i).first == item)
-+ {
-+ return i;
-+ }
-+ }
-+
-+ return -1;
-+}
-+
-+} // namespace Digikam
-diff --git a/libs/database/models/imageversionsmodel.h b/libs/database/models/imageversionsmodel.h
-new file mode 100644
-index 0000000..ed08529
---- /dev/null
-+++ b/libs/database/models/imageversionsmodel.h
-@@ -0,0 +1,75 @@
-+/* ============================================================
-+ *
-+ * This file is a part of digiKam project
-+ * http://www.digikam.org
-+ *
-+ * Date : 2010-07-13
-+ * Description : Model for image versions
-+ *
-+ * Copyright (C) 2010 by Martin Klapetek <martin dot klapetek 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 IMAGEVERSIONSMODEL_H
-+#define IMAGEVERSIONSMODEL_H
-+
-+// Qt includes
-+
-+#include <QModelIndex>
-+#include <QPixmap>
-+
-+// Local includes
-+
-+#include "digikam_export.h"
-+
-+namespace Digikam
-+{
-+
-+class DIGIKAM_DATABASE_EXPORT ImageVersionsModel : public QAbstractListModel
-+{
-+ Q_OBJECT
-+
-+public:
-+
-+ explicit ImageVersionsModel(QObject* parent = 0);
-+ ~ImageVersionsModel();
-+
-+ Qt::ItemFlags flags(const QModelIndex& index) const;
-+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
-+ int rowCount(const QModelIndex& parent = QModelIndex()) const;
-+
-+ void setupModelData(QList<QPair<QString, int> >& data);
-+ void clearModelData();
-+
-+ QString currentSelectedImage() const;
-+ void setCurrentSelectedImage(const QString& path);
-+ QModelIndex currentSelectedImageIndex() const;
-+
-+ bool paintTree() const;
-+ int listIndexOf(const QString& item) const;
-+
-+public Q_SLOTS:
-+
-+ void slotAnimationStep();
-+ void setPaintTree(bool paint);
-+
-+private:
-+
-+ class Private;
-+ Private* const d;
-+};
-+
-+} // namespace Digikam
-+
-+#endif // IMAGEVERSIONSMODEL_H
-diff --git a/libs/models/CMakeLists.txt b/libs/models/CMakeLists.txt
-index cbabfaa..804456b 100644
---- a/libs/models/CMakeLists.txt
-+++ b/libs/models/CMakeLists.txt
-@@ -9,18 +9,6 @@ if (POLICY CMP0063)
- cmake_policy(SET CMP0063 NEW)
- endif (POLICY CMP0063)
-
--set(libdatabasemodels_SRCS
-- imagemodel.cpp
-- imagefiltermodel.cpp
-- imagefiltermodelpriv.cpp
-- imagefiltermodelthreads.cpp
-- imagefiltersettings.cpp
-- imagelistmodel.cpp
-- imagesortsettings.cpp
-- imagethumbnailmodel.cpp
-- imageversionsmodel.cpp
--)
--
- set(libalbummodels_SRCS
- imagealbummodel.cpp
- imagealbumfiltermodel.cpp
-@@ -52,5 +40,4 @@ endif()
- #for digikam core lib
- add_library(digikamgenericmodels_src OBJECT ${libgenericmodels_SRCS})
-
--add_library(digikamdatabasemodels_src OBJECT ${libdatabasemodels_SRCS})
--add_library(digikammodels_src OBJECT ${libalbummodels_SRCS} ${libgenericmodels_SRCS})
-+add_library(digikammodels_src OBJECT ${libalbummodels_SRCS} ${libgenericmodels_SRCS})
-diff --git a/libs/models/imagefiltermodel.cpp b/libs/models/imagefiltermodel.cpp
-deleted file mode 100644
-index 3d57e05..0000000
---- a/libs/models/imagefiltermodel.cpp
-+++ /dev/null
-@@ -1,1116 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Qt item model for database entries
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-- * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-- * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-- * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagefiltermodel.h"
--#include "imagefiltermodelpriv.h"
--#include "imagefiltermodelthreads.h"
--
--// Local includes
--
--#include "digikam_debug.h"
--#include "coredbaccess.h"
--#include "coredbchangesets.h"
--#include "coredbwatch.h"
--#include "imageinfolist.h"
--#include "imagemodel.h"
--
--namespace Digikam
--{
--
--ImageSortFilterModel::ImageSortFilterModel(QObject* parent)
-- : DCategorizedSortFilterProxyModel(parent), m_chainedModel(0)
--{
--}
--
--void ImageSortFilterModel::setSourceImageModel(ImageModel* source)
--{
-- if (m_chainedModel)
-- {
-- m_chainedModel->setSourceImageModel(source);
-- }
-- else
-- {
-- setDirectSourceImageModel(source);
-- }
--}
--
--void ImageSortFilterModel::setSourceFilterModel(ImageSortFilterModel* source)
--{
-- if (source)
-- {
-- ImageModel* const model = sourceImageModel();
--
-- if (model)
-- {
-- source->setSourceImageModel(model);
-- }
-- }
--
-- m_chainedModel = source;
-- setSourceModel(source);
--}
--
--void ImageSortFilterModel::setDirectSourceImageModel(ImageModel* model)
--{
-- setSourceModel(model);
--}
--
--void ImageSortFilterModel::setSourceModel(QAbstractItemModel* model)
--{
-- // made it protected, only setSourceImageModel is public
-- DCategorizedSortFilterProxyModel::setSourceModel(model);
--}
--
--ImageModel* ImageSortFilterModel::sourceImageModel() const
--{
-- if (m_chainedModel)
-- {
-- return m_chainedModel->sourceImageModel();
-- }
--
-- return static_cast<ImageModel*>(sourceModel());
--}
--
--ImageSortFilterModel* ImageSortFilterModel::sourceFilterModel() const
--{
-- return m_chainedModel;
--}
--
--ImageFilterModel* ImageSortFilterModel::imageFilterModel() const
--{
-- // reimplemented in ImageFilterModel
-- if (m_chainedModel)
-- {
-- return m_chainedModel->imageFilterModel();
-- }
--
-- return 0;
--}
--
--QModelIndex ImageSortFilterModel::mapToSourceImageModel(const QModelIndex& index) const
--{
-- if (m_chainedModel)
-- {
-- return m_chainedModel->mapToSourceImageModel(mapToSource(index));
-- }
--
-- return mapToSource(index);
--}
--
--QModelIndex ImageSortFilterModel::mapFromSourceImageModel(const QModelIndex& albummodel_index) const
--{
-- if (m_chainedModel)
-- {
-- return mapFromSource(m_chainedModel->mapFromSourceImageModel(albummodel_index));
-- }
--
-- return mapFromSource(albummodel_index);
--}
--
--
--QModelIndex ImageSortFilterModel::mapFromDirectSourceToSourceImageModel(const QModelIndex& sourceModel_index) const
--{
-- if (m_chainedModel)
-- {
-- return m_chainedModel->mapToSourceImageModel(sourceModel_index);
-- }
-- return sourceModel_index;
--}
--
--// -------------- Convenience mappers -------------------------------------------------------------------
--
--QList<QModelIndex> ImageSortFilterModel::mapListToSource(const QList<QModelIndex>& indexes) const
--{
-- QList<QModelIndex> sourceIndexes;
-- foreach(const QModelIndex& index, indexes)
-- {
-- sourceIndexes << mapToSourceImageModel(index);
-- }
-- return sourceIndexes;
--}
--
--QList<QModelIndex> ImageSortFilterModel::mapListFromSource(const QList<QModelIndex>& sourceIndexes) const
--{
-- QList<QModelIndex> indexes;
-- foreach(const QModelIndex& index, sourceIndexes)
-- {
-- indexes << mapFromSourceImageModel(index);
-- }
-- return indexes;
--}
--
--ImageInfo ImageSortFilterModel::imageInfo(const QModelIndex& index) const
--{
-- return sourceImageModel()->imageInfo(mapToSourceImageModel(index));
--}
--
--qlonglong ImageSortFilterModel::imageId(const QModelIndex& index) const
--{
-- return sourceImageModel()->imageId(mapToSourceImageModel(index));
--}
--
--QList<ImageInfo> ImageSortFilterModel::imageInfos(const QList<QModelIndex>& indexes) const
--{
-- QList<ImageInfo> infos;
-- ImageModel* const model = sourceImageModel();
--
-- foreach(const QModelIndex& index, indexes)
-- {
-- infos << model->imageInfo(mapToSourceImageModel(index));
-- }
--
-- return infos;
--}
--
--QList<qlonglong> ImageSortFilterModel::imageIds(const QList<QModelIndex>& indexes) const
--{
-- QList<qlonglong> ids;
-- ImageModel* const model = sourceImageModel();
--
-- foreach(const QModelIndex& index, indexes)
-- {
-- ids << model->imageId(mapToSourceImageModel(index));
-- }
--
-- return ids;
--}
--
--QModelIndex ImageSortFilterModel::indexForPath(const QString& filePath) const
--{
-- return mapFromSourceImageModel(sourceImageModel()->indexForPath(filePath));
--}
--
--QModelIndex ImageSortFilterModel::indexForImageInfo(const ImageInfo& info) const
--{
-- return mapFromSourceImageModel(sourceImageModel()->indexForImageInfo(info));
--}
--
--QModelIndex ImageSortFilterModel::indexForImageId(qlonglong id) const
--{
-- return mapFromSourceImageModel(sourceImageModel()->indexForImageId(id));
--}
--
--QList<ImageInfo> ImageSortFilterModel::imageInfosSorted() const
--{
-- QList<ImageInfo> infos;
-- const int size = rowCount();
-- ImageModel* const model = sourceImageModel();
--
-- for (int i=0; i<size; ++i)
-- {
-- infos << model->imageInfo(mapToSourceImageModel(index(i, 0)));
-- }
--
-- return infos;
--}
--
--// --------------------------------------------------------------------------------------------
--
--ImageFilterModel::ImageFilterModel(QObject* parent)
-- : ImageSortFilterModel(parent),
-- d_ptr(new ImageFilterModelPrivate)
--{
-- d_ptr->init(this);
--}
--
--ImageFilterModel::ImageFilterModel(ImageFilterModelPrivate& dd, QObject* parent)
-- : ImageSortFilterModel(parent),
-- d_ptr(&dd)
--{
-- d_ptr->init(this);
--}
--
--ImageFilterModel::~ImageFilterModel()
--{
-- Q_D(ImageFilterModel);
-- delete d;
--}
--
--void ImageFilterModel::setDirectSourceImageModel(ImageModel* sourceModel)
--{
-- Q_D(ImageFilterModel);
--
-- if (d->imageModel)
-- {
-- d->imageModel->unsetPreprocessor(d);
-- disconnect(d->imageModel, SIGNAL(modelReset()),
-- this, SLOT(slotModelReset()));
-- slotModelReset();
-- }
--
-- d->imageModel = sourceModel;
--
-- if (d->imageModel)
-- {
-- d->imageModel->setPreprocessor(d);
--
-- connect(d->imageModel, SIGNAL(preprocess(QList<ImageInfo>,QList<QVariant>)),
-- d, SLOT(preprocessInfos(QList<ImageInfo>,QList<QVariant>)));
--
-- connect(d->imageModel, SIGNAL(processAdded(QList<ImageInfo>,QList<QVariant>)),
-- d, SLOT(processAddedInfos(QList<ImageInfo>,QList<QVariant>)));
--
-- connect(d, SIGNAL(reAddImageInfos(QList<ImageInfo>,QList<QVariant>)),
-- d->imageModel, SLOT(reAddImageInfos(QList<ImageInfo>,QList<QVariant>)));
--
-- connect(d, SIGNAL(reAddingFinished()),
-- d->imageModel, SLOT(reAddingFinished()));
--
-- connect(d->imageModel, SIGNAL(modelReset()),
-- this, SLOT(slotModelReset()));
--
-- connect(d->imageModel, SIGNAL(imageChange(ImageChangeset,QItemSelection)),
-- this, SLOT(slotImageChange(ImageChangeset)));
--
-- connect(d->imageModel, SIGNAL(imageTagChange(ImageTagChangeset,QItemSelection)),
-- this, SLOT(slotImageTagChange(ImageTagChangeset)));
-- }
--
-- setSourceModel(d->imageModel);
--}
--
--QVariant ImageFilterModel::data(const QModelIndex& index, int role) const
--{
-- Q_D(const ImageFilterModel);
--
-- if (!index.isValid())
-- {
-- return QVariant();
-- }
--
-- switch (role)
-- {
-- // Attention: This breaks should there ever be another filter model between this and the ImageModel
--
-- case DCategorizedSortFilterProxyModel::CategoryDisplayRole:
-- return categoryIdentifier(d->imageModel->imageInfoRef(mapToSource(index)));
-- case CategorizationModeRole:
-- return d->sorter.categorizationMode;
-- case SortOrderRole:
-- return d->sorter.sortRole;
-- //case CategoryCountRole:
-- // return categoryCount(d->imageModel->imageInfoRef(mapToSource(index)));
-- case CategoryAlbumIdRole:
-- return d->imageModel->imageInfoRef(mapToSource(index)).albumId();
-- case CategoryFormatRole:
-- return d->imageModel->imageInfoRef(mapToSource(index)).format();
-- case GroupIsOpenRole:
-- return d->groupFilter.isAllOpen() ||
-- d->groupFilter.isOpen(d->imageModel->imageInfoRef(mapToSource(index)).id());
-- case ImageFilterModelPointerRole:
-- return QVariant::fromValue(const_cast<ImageFilterModel*>(this));
-- }
--
-- return DCategorizedSortFilterProxyModel::data(index, role);
--}
--
--ImageFilterModel* ImageFilterModel::imageFilterModel() const
--{
-- return const_cast<ImageFilterModel*>(this);
--}
--
--DatabaseFields::Set ImageFilterModel::suggestedWatchFlags() const
--{
-- DatabaseFields::Set watchFlags;
-- watchFlags |= DatabaseFields::Name | DatabaseFields::FileSize | DatabaseFields::ModificationDate;
-- watchFlags |= DatabaseFields::Rating | DatabaseFields::CreationDate | DatabaseFields::Orientation |
-- DatabaseFields::Width | DatabaseFields::Height;
-- watchFlags |= DatabaseFields::Comment;
-- watchFlags |= DatabaseFields::ImageRelations;
-- return watchFlags;
--}
--
--// -------------- Filter settings --------------
--
--void ImageFilterModel::setDayFilter(const QList<QDateTime>& days)
--{
-- Q_D(ImageFilterModel);
-- d->filter.setDayFilter(days);
-- setImageFilterSettings(d->filter);
--}
--
--void ImageFilterModel::setTagFilter(const QList<int>& includedTags, const QList<int>& excludedTags,
-- ImageFilterSettings::MatchingCondition matchingCond,
-- bool showUnTagged, const QList<int>& clTagIds, const QList<int>& plTagIds)
--{
-- Q_D(ImageFilterModel);
-- d->filter.setTagFilter(includedTags, excludedTags, matchingCond, showUnTagged, clTagIds, plTagIds);
-- setImageFilterSettings(d->filter);
--}
--
--void ImageFilterModel::setRatingFilter(int rating, ImageFilterSettings::RatingCondition ratingCond, bool isUnratedExcluded)
--{
-- Q_D(ImageFilterModel);
-- d->filter.setRatingFilter(rating, ratingCond, isUnratedExcluded);
-- setImageFilterSettings(d->filter);
--}
--
--void ImageFilterModel::setUrlWhitelist(const QList<QUrl> urlList, const QString& id)
--{
-- Q_D(ImageFilterModel);
-- d->filter.setUrlWhitelist(urlList, id);
-- setImageFilterSettings(d->filter);
--}
--
--void ImageFilterModel::setIdWhitelist(const QList<qlonglong>& idList, const QString& id)
--{
-- Q_D(ImageFilterModel);
-- d->filter.setIdWhitelist(idList, id);
-- setImageFilterSettings(d->filter);
--}
--
--void ImageFilterModel::setMimeTypeFilter(int mimeTypeFilter)
--{
-- Q_D(ImageFilterModel);
-- d->filter.setMimeTypeFilter(mimeTypeFilter);
-- setImageFilterSettings(d->filter);
--}
--
--void ImageFilterModel::setGeolocationFilter(const ImageFilterSettings::GeolocationCondition& condition)
--{
-- Q_D(ImageFilterModel);
-- d->filter.setGeolocationFilter(condition);
-- setImageFilterSettings(d->filter);
--}
--
--void ImageFilterModel::setTextFilter(const SearchTextFilterSettings& settings)
--{
-- Q_D(ImageFilterModel);
-- d->filter.setTextFilter(settings);
-- setImageFilterSettings(d->filter);
--}
--
--void ImageFilterModel::setImageFilterSettings(const ImageFilterSettings& settings)
--{
-- Q_D(ImageFilterModel);
--
-- {
-- QMutexLocker lock(&d->mutex);
-- d->version++;
-- d->filter = settings;
-- d->filterCopy = settings;
-- d->versionFilterCopy = d->versionFilter;
-- d->groupFilterCopy = d->groupFilter;
--
-- d->needPrepareComments = settings.isFilteringByText();
-- d->needPrepareTags = settings.isFilteringByTags();
-- d->needPrepareGroups = true;
-- d->needPrepare = d->needPrepareComments || d->needPrepareTags || d->needPrepareGroups;
--
-- d->hasOneMatch = false;
-- d->hasOneMatchForText = false;
-- }
--
-- d->filterResults.clear();
--
-- //d->categoryCountHashInt.clear();
-- //d->categoryCountHashString.clear();
-- if (d->imageModel)
-- {
-- d->infosToProcess(d->imageModel->imageInfos());
-- }
--
-- emit filterSettingsChanged(settings);
--}
--
--void ImageFilterModel::setVersionManagerSettings(const VersionManagerSettings& settings)
--{
-- Q_D(ImageFilterModel);
-- d->versionFilter.setVersionManagerSettings(settings);
-- setVersionImageFilterSettings(d->versionFilter);
--}
--
--void ImageFilterModel::setExceptionList(const QList<qlonglong>& idList, const QString& id)
--{
-- Q_D(ImageFilterModel);
-- d->versionFilter.setExceptionList(idList, id);
-- setVersionImageFilterSettings(d->versionFilter);
--}
--
--void ImageFilterModel::setVersionImageFilterSettings(const VersionImageFilterSettings& settings)
--{
-- Q_D(ImageFilterModel);
-- d->versionFilter = settings;
-- slotUpdateFilter();
--}
--
--bool ImageFilterModel::isGroupOpen(qlonglong group) const
--{
-- Q_D(const ImageFilterModel);
-- return d->groupFilter.isOpen(group);
--}
--
--bool ImageFilterModel::isAllGroupsOpen() const
--{
-- Q_D(const ImageFilterModel);
-- return d->groupFilter.isAllOpen();
--}
--
--void ImageFilterModel::setGroupOpen(qlonglong group, bool open)
--{
-- Q_D(ImageFilterModel);
-- d->groupFilter.setOpen(group, open);
-- setGroupImageFilterSettings(d->groupFilter);
--}
--
--void ImageFilterModel::toggleGroupOpen(qlonglong group)
--{
-- setGroupOpen(group, !isGroupOpen(group));
--}
--
--void ImageFilterModel::setAllGroupsOpen(bool open)
--{
-- Q_D(ImageFilterModel);
-- d->groupFilter.setAllOpen(open);
-- setGroupImageFilterSettings(d->groupFilter);
--}
--
--void ImageFilterModel::setGroupImageFilterSettings(const GroupImageFilterSettings& settings)
--{
-- Q_D(ImageFilterModel);
-- d->groupFilter = settings;
-- slotUpdateFilter();
--}
--
--void ImageFilterModel::slotUpdateFilter()
--{
-- Q_D(ImageFilterModel);
-- setImageFilterSettings(d->filter);
--}
--
--ImageFilterSettings ImageFilterModel::imageFilterSettings() const
--{
-- Q_D(const ImageFilterModel);
-- return d->filter;
--}
--
--ImageSortSettings ImageFilterModel::imageSortSettings() const
--{
-- Q_D(const ImageFilterModel);
-- return d->sorter;
--}
--
--VersionImageFilterSettings ImageFilterModel::versionImageFilterSettings() const
--{
-- Q_D(const ImageFilterModel);
-- return d->versionFilter;
--}
--
--GroupImageFilterSettings ImageFilterModel::groupImageFilterSettings() const
--{
-- Q_D(const ImageFilterModel);
-- return d->groupFilter;
--}
--
--void ImageFilterModel::slotModelReset()
--{
-- Q_D(ImageFilterModel);
-- {
-- QMutexLocker lock(&d->mutex);
-- // discard all packages on the way that are marked as send out for re-add
-- d->lastDiscardVersion = d->version;
-- d->sentOutForReAdd = 0;
-- // discard all packages on the way
-- d->version++;
-- d->sentOut = 0;
--
-- d->hasOneMatch = false;
-- d->hasOneMatchForText = false;
-- }
-- d->filterResults.clear();
--}
--
--bool ImageFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
--{
-- Q_D(const ImageFilterModel);
--
-- if (source_parent.isValid())
-- {
-- return false;
-- }
--
-- qlonglong id = d->imageModel->imageId(source_row);
-- QHash<qlonglong, bool>::const_iterator it = d->filterResults.constFind(id);
--
-- if (it != d->filterResults.constEnd())
-- {
-- return it.value();
-- }
--
-- // usually done in thread and cache, unless source model changed
-- ImageInfo info = d->imageModel->imageInfo(source_row);
-- bool match = d->filter.matches(info);
-- match = match ? d->versionFilter.matches(info) : false;
--
-- return match ? d->groupFilter.matches(info) : false;
--}
--
--void ImageFilterModel::setSendImageInfoSignals(bool sendSignals)
--{
-- if (sendSignals)
-- {
-- connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)),
-- this, SLOT(slotRowsInserted(QModelIndex,int,int)));
--
-- connect(this, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
-- this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)));
-- }
-- else
-- {
-- disconnect(this, SIGNAL(rowsInserted(QModelIndex,int,int)),
-- this, SLOT(slotRowsInserted(QModelIndex,int,int)));
--
-- disconnect(this, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
-- this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)));
-- }
--}
--
--void ImageFilterModel::slotRowsInserted(const QModelIndex& /*parent*/, int start, int end)
--{
-- QList<ImageInfo> infos;
--
-- for (int i=start; i<=end; ++i)
-- {
-- infos << imageInfo(index(i, 0));
-- }
--
-- emit imageInfosAdded(infos);
--}
--
--void ImageFilterModel::slotRowsAboutToBeRemoved(const QModelIndex& /*parent*/, int start, int end)
--{
-- QList<ImageInfo> infos;
--
-- for (int i=start; i<=end; ++i)
-- {
-- infos << imageInfo(index(i, 0));
-- }
--
-- emit imageInfosAboutToBeRemoved(infos);
--}
--
--// -------------- Threaded preparation & filtering --------------
--
--void ImageFilterModel::addPrepareHook(ImageFilterModelPrepareHook* hook)
--{
-- Q_D(ImageFilterModel);
-- QMutexLocker lock(&d->mutex);
-- d->prepareHooks << hook;
--}
--
--void ImageFilterModel::removePrepareHook(ImageFilterModelPrepareHook* hook)
--{
-- Q_D(ImageFilterModel);
-- QMutexLocker lock(&d->mutex);
-- d->prepareHooks.removeAll(hook);
--}
--
--void ImageFilterModelPreparer::process(ImageFilterModelTodoPackage package)
--{
-- if (!checkVersion(package))
-- {
-- emit discarded(package);
-- return;
-- }
--
-- // get thread-local copy
-- bool needPrepareTags, needPrepareComments, needPrepareGroups;
-- QList<ImageFilterModelPrepareHook*> prepareHooks;
-- {
-- QMutexLocker lock(&d->mutex);
-- needPrepareTags = d->needPrepareTags;
-- needPrepareComments = d->needPrepareComments;
-- needPrepareGroups = d->needPrepareGroups;
-- prepareHooks = d->prepareHooks;
-- }
--
-- //TODO: Make efficient!!
-- if (needPrepareComments)
-- {
-- foreach(const ImageInfo& info, package.infos)
-- {
-- info.comment();
-- }
-- }
--
-- if (!checkVersion(package))
-- {
-- emit discarded(package);
-- return;
-- }
--
-- // The downside of QVector: At some point, we may need a QList for an API.
-- // Nonetheless, QList and ImageInfo is fast. We could as well
-- // reimplement ImageInfoList to ImageInfoVector (internally with templates?)
-- ImageInfoList infoList;
--
-- if (needPrepareTags || needPrepareGroups)
-- {
-- infoList = package.infos.toList();
-- }
--
-- if (needPrepareTags)
-- {
-- infoList.loadTagIds();
-- }
--
-- if (needPrepareGroups)
-- {
-- infoList.loadGroupImageIds();
-- }
--
-- foreach(ImageFilterModelPrepareHook* hook, prepareHooks)
-- {
-- hook->prepare(package.infos);
-- }
--
-- emit processed(package);
--}
--
--void ImageFilterModelFilterer::process(ImageFilterModelTodoPackage package)
--{
-- if (!checkVersion(package))
-- {
-- emit discarded(package);
-- return;
-- }
--
-- // get thread-local copy
-- ImageFilterSettings localFilter;
-- VersionImageFilterSettings localVersionFilter;
-- GroupImageFilterSettings localGroupFilter;
-- bool hasOneMatch;
-- bool hasOneMatchForText;
-- {
-- QMutexLocker lock(&d->mutex);
-- localFilter = d->filterCopy;
-- localVersionFilter = d->versionFilterCopy;
-- localGroupFilter = d->groupFilterCopy;
-- hasOneMatch = d->hasOneMatch;
-- hasOneMatchForText = d->hasOneMatchForText;
-- }
--
-- // Actual filtering. The variants to spare checking hasOneMatch over and over again.
-- if (hasOneMatch && hasOneMatchForText)
-- {
-- foreach(const ImageInfo& info, package.infos)
-- {
-- package.filterResults[info.id()] = localFilter.matches(info) &&
-- localVersionFilter.matches(info) &&
-- localGroupFilter.matches(info);
-- }
-- }
-- else if (hasOneMatch)
-- {
-- bool matchForText;
--
-- foreach(const ImageInfo& info, package.infos)
-- {
-- package.filterResults[info.id()] = localFilter.matches(info, &matchForText) &&
-- localVersionFilter.matches(info) &&
-- localGroupFilter.matches(info);
--
-- if (matchForText)
-- {
-- hasOneMatchForText = true;
-- }
-- }
-- }
-- else
-- {
-- bool result, matchForText;
--
-- foreach(const ImageInfo& info, package.infos)
-- {
-- result = localFilter.matches(info, &matchForText) &&
-- localVersionFilter.matches(info) &&
-- localGroupFilter.matches(info);
-- package.filterResults[info.id()] = result;
--
-- if (result)
-- {
-- hasOneMatch = true;
-- }
--
-- if (matchForText)
-- {
-- hasOneMatchForText = true;
-- }
-- }
-- }
--
-- if (checkVersion(package))
-- {
-- QMutexLocker lock(&d->mutex);
-- d->hasOneMatch = hasOneMatch;
-- d->hasOneMatchForText = hasOneMatchForText;
-- }
--
-- emit processed(package);
--}
--
--// -------------- Sorting and Categorization -------------------------------------------------------
--
--void ImageFilterModel::setImageSortSettings(const ImageSortSettings& sorter)
--{
-- Q_D(ImageFilterModel);
-- d->sorter = sorter;
-- setCategorizedModel(d->sorter.categorizationMode != ImageSortSettings::NoCategories);
-- invalidate();
--}
--
--void ImageFilterModel::setCategorizationMode(ImageSortSettings::CategorizationMode mode)
--{
-- Q_D(ImageFilterModel);
-- d->sorter.setCategorizationMode(mode);
-- setImageSortSettings(d->sorter);
--}
--
--void ImageFilterModel::setCategorizationSortOrder(ImageSortSettings::SortOrder order)
--{
-- Q_D(ImageFilterModel);
-- d->sorter.setCategorizationSortOrder(order);
-- setImageSortSettings(d->sorter);
--}
--
--void ImageFilterModel::setSortRole(ImageSortSettings::SortRole role)
--{
-- Q_D(ImageFilterModel);
-- d->sorter.setSortRole(role);
-- setImageSortSettings(d->sorter);
--}
--
--void ImageFilterModel::setSortOrder(ImageSortSettings::SortOrder order)
--{
-- Q_D(ImageFilterModel);
-- d->sorter.setSortOrder(order);
-- setImageSortSettings(d->sorter);
--}
--
--void ImageFilterModel::setStringTypeNatural(bool natural)
--{
-- Q_D(ImageFilterModel);
-- d->sorter.setStringTypeNatural(natural);
-- setImageSortSettings(d->sorter);
--}
--
--int ImageFilterModel::compareCategories(const QModelIndex& left, const QModelIndex& right) const
--{
-- // source indexes
-- Q_D(const ImageFilterModel);
--
-- if (!d->sorter.isCategorized())
-- {
-- return 0;
-- }
--
-- if (!left.isValid() || !right.isValid())
-- {
-- return -1;
-- }
--
-- const ImageInfo& leftInfo = d->imageModel->imageInfoRef(left);
-- const ImageInfo& rightInfo = d->imageModel->imageInfoRef(right);
--
-- // Check grouping
-- qlonglong leftGroupImageId = leftInfo.groupImageId();
-- qlonglong rightGroupImageId = rightInfo.groupImageId();
--
-- return compareInfosCategories(leftGroupImageId == -1 ? leftInfo : ImageInfo(leftGroupImageId),
-- rightGroupImageId == -1 ? rightInfo : ImageInfo(rightGroupImageId));
--}
--
--bool ImageFilterModel::subSortLessThan(const QModelIndex& left, const QModelIndex& right) const
--{
-- // source indexes
-- Q_D(const ImageFilterModel);
--
-- if (!left.isValid() || !right.isValid())
-- {
-- return true;
-- }
--
-- if (left == right)
-- {
-- return false;
-- }
--
-- const ImageInfo& leftInfo = d->imageModel->imageInfoRef(left);
-- const ImageInfo& rightInfo = d->imageModel->imageInfoRef(right);
--
-- if (leftInfo == rightInfo)
-- {
-- return d->sorter.lessThan(left.data(ImageModel::ExtraDataRole), right.data(ImageModel::ExtraDataRole));
-- }
--
-- // Check grouping
-- qlonglong leftGroupImageId = leftInfo.groupImageId();
-- qlonglong rightGroupImageId = rightInfo.groupImageId();
--
-- // Either no grouping (-1), or same group image, or same image
-- if (leftGroupImageId == rightGroupImageId)
-- {
-- return infosLessThan(leftInfo, rightInfo);
-- }
--
-- // We have grouping to handle
--
-- // Is one grouped on the other? Sort behind leader.
-- if (leftGroupImageId == rightInfo.id())
-- {
-- return false;
-- }
-- if (rightGroupImageId == leftInfo.id())
-- {
-- return true;
-- }
--
-- // Use the group leader for sorting
-- return infosLessThan(leftGroupImageId == -1 ? leftInfo : ImageInfo(leftGroupImageId),
-- rightGroupImageId == -1 ? rightInfo : ImageInfo(rightGroupImageId));
--}
--
--int ImageFilterModel::compareInfosCategories(const ImageInfo& left, const ImageInfo& right) const
--{
-- // Note: reimplemented in ImageAlbumFilterModel
-- Q_D(const ImageFilterModel);
-- return d->sorter.compareCategories(left, right);
--}
--
--// Feel free to optimize. QString::number is 3x slower.
--static inline QString fastNumberToString(int id)
--{
-- const int size = sizeof(int) * 2;
-- char c[size+1];
-- c[size] = '\0';
-- char* p = c;
-- int number = id;
--
-- for (int i=0; i<size; ++i)
-- {
-- *p = 'a' + (number & 0xF);
-- number >>= 4;
-- ++p;
-- }
--
-- return QString::fromLatin1(c);
--}
--
--QString ImageFilterModel::categoryIdentifier(const ImageInfo& i) const
--{
-- Q_D(const ImageFilterModel);
--
-- if (!d->sorter.isCategorized())
-- {
-- return QString();
-- }
--
-- qlonglong groupedImageId = i.groupImageId();
-- ImageInfo info = groupedImageId == -1 ? i : ImageInfo(groupedImageId);
--
-- switch (d->sorter.categorizationMode)
-- {
-- case ImageSortSettings::NoCategories:
-- return QString();
-- case ImageSortSettings::OneCategory:
-- return QString();
-- case ImageSortSettings::CategoryByAlbum:
-- return fastNumberToString(info.albumId());
-- case ImageSortSettings::CategoryByFormat:
-- return info.format();
-- default:
-- return QString();
-- }
--}
--
--bool ImageFilterModel::infosLessThan(const ImageInfo& left, const ImageInfo& right) const
--{
-- Q_D(const ImageFilterModel);
-- return d->sorter.lessThan(left, right);
--}
--
--// -------------- Watching changes -----------------------------------------------------------------
--
--void ImageFilterModel::slotImageTagChange(const ImageTagChangeset& changeset)
--{
-- Q_D(ImageFilterModel);
--
-- if (!d->imageModel || d->imageModel->isEmpty())
-- {
-- return;
-- }
--
-- // already scheduled to re-filter?
-- if (d->updateFilterTimer->isActive())
-- {
-- return;
-- }
--
-- // do we filter at all?
-- if (!d->versionFilter.isFilteringByTags() &&
-- !d->filter.isFilteringByTags() &&
-- !d->filter.isFilteringByText())
-- {
-- return;
-- }
--
-- // is one of our images affected?
-- foreach(const qlonglong& id, changeset.ids())
-- {
-- // if one matching image id is found, trigger a refresh
-- if (d->imageModel->hasImage(id))
-- {
-- d->updateFilterTimer->start();
-- return;
-- }
-- }
--}
--
--void ImageFilterModel::slotImageChange(const ImageChangeset& changeset)
--{
-- Q_D(ImageFilterModel);
--
-- if (!d->imageModel || d->imageModel->isEmpty())
-- {
-- return;
-- }
--
-- // already scheduled to re-filter?
-- if (d->updateFilterTimer->isActive())
-- {
-- return;
-- }
--
-- // is one of the values affected that we filter or sort by?
-- DatabaseFields::Set set = changeset.changes();
-- bool sortAffected = (set & d->sorter.watchFlags());
-- bool filterAffected = (set & d->filter.watchFlags()) || (set & d->groupFilter.watchFlags());
--
-- if (!sortAffected && !filterAffected)
-- {
-- return;
-- }
--
-- // is one of our images affected?
-- bool imageAffected = false;
--
-- foreach(const qlonglong& id, changeset.ids())
-- {
-- // if one matching image id is found, trigger a refresh
-- if (d->imageModel->hasImage(id))
-- {
-- imageAffected = true;
-- break;
-- }
-- }
--
-- if (!imageAffected)
-- {
-- return;
-- }
--
-- if (filterAffected)
-- {
-- d->updateFilterTimer->start();
-- }
-- else
-- {
-- invalidate(); // just resort, reuse filter results
-- }
--}
--
--// -------------------------------------------------------------------------------------------------------
--
--NoDuplicatesImageFilterModel::NoDuplicatesImageFilterModel(QObject* parent)
-- : ImageSortFilterModel(parent)
--{
--}
--
--bool NoDuplicatesImageFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
--{
-- QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
--
-- if (index.data(ImageModel::ExtraDataDuplicateCount).toInt() <= 1)
-- {
-- return true;
-- }
--
-- QModelIndex previousIndex = sourceModel()->index(source_row - 1, 0, source_parent);
--
-- if (!previousIndex.isValid())
-- {
-- return true;
-- }
--
-- if (sourceImageModel()->imageId(mapFromDirectSourceToSourceImageModel(index)) == sourceImageModel()->imageId(mapFromDirectSourceToSourceImageModel(previousIndex)))
-- {
-- return false;
-- }
-- return true;
--}
--
--/*
--void NoDuplicatesImageFilterModel::setSourceModel(QAbstractItemModel* model)
--{
-- if (sourceModel())
-- {
-- }
--
-- ImageSortFilterModel::setSourceModel(model);
--
-- if (sourceModel())
-- {
-- connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
-- this, SLOT(slotRowsAboutToBeRemoved(QModelIndex,int,int)));
-- }
--}
--
--void NoDuplicatesImageFilterModel::slotRowsAboutToBeRemoved(const QModelIndex& parent, int begin, int end)
--{
-- bool needInvalidate = false;
--
-- for (int i = begin; i<=end; ++i)
-- {
-- QModelIndex index = sourceModel()->index(i, 0, parent);
--
-- // filtered out by us?
-- if (!mapFromSource(index).isValid())
-- {
-- continue;
-- }
--
-- QModelIndex sourceIndex = mapFromDirectSourceToSourceImageModel(index);
-- qlonglong id = sourceImageModel()->imageId(sourceIndex);
--
-- if (sourceImageModel()->numberOfIndexesForImageId(id) > 1)
-- {
-- needInvalidate = true;
-- }
-- }
--}*/
--
--} // namespace Digikam
-diff --git a/libs/models/imagefiltermodel.h b/libs/models/imagefiltermodel.h
-deleted file mode 100644
-index d131b3e..0000000
---- a/libs/models/imagefiltermodel.h
-+++ /dev/null
-@@ -1,299 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Qt item model for database entries
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- * Copyright (C) 2011 by Gilles Caulier <caulier dot gilles at gmail dot com>
-- * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-- * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-- * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 IMAGEFILTERMODEL_H
--#define IMAGEFILTERMODEL_H
--
--// Local includes
--
--#include "dcategorizedsortfilterproxymodel.h"
--#include "textfilter.h"
--#include "imagefiltersettings.h"
--#include "imagemodel.h"
--#include "imagesortsettings.h"
--#include "digikam_export.h"
--
--namespace Digikam
--{
--
--class ImageChangeset;
--class ImageFilterModel;
--class ImageTagChangeset;
--
--class DIGIKAM_DATABASE_EXPORT ImageFilterModelPrepareHook
--{
--public:
--
-- virtual ~ImageFilterModelPrepareHook() {};
-- virtual void prepare(const QVector<ImageInfo>& infos) = 0;
--};
--
--// -----------------------------------------------------------------------------------------------
--
--class DIGIKAM_DATABASE_EXPORT ImageSortFilterModel : public DCategorizedSortFilterProxyModel
--{
-- Q_OBJECT
--
--public:
--
-- explicit ImageSortFilterModel(QObject* parent = 0);
--
-- void setSourceImageModel(ImageModel* model);
-- ImageModel* sourceImageModel() const;
--
-- void setSourceFilterModel(ImageSortFilterModel* model);
-- ImageSortFilterModel* sourceFilterModel() const;
--
-- QModelIndex mapToSourceImageModel(const QModelIndex& index) const;
-- QModelIndex mapFromSourceImageModel(const QModelIndex& imagemodel_index) const;
-- QModelIndex mapFromDirectSourceToSourceImageModel(const QModelIndex& sourceModel_index) const;
--
-- /// Convenience methods mapped to ImageModel.
-- /// Mentioned indexes returned come from the source image model.
-- QList<QModelIndex> mapListToSource(const QList<QModelIndex>& indexes) const;
-- QList<QModelIndex> mapListFromSource(const QList<QModelIndex>& sourceIndexes) const;
--
-- ImageInfo imageInfo(const QModelIndex& index) const;
-- qlonglong imageId(const QModelIndex& index) const;
-- QList<ImageInfo> imageInfos(const QList<QModelIndex>& indexes) const;
-- QList<qlonglong> imageIds(const QList<QModelIndex>& indexes) const;
--
-- QModelIndex indexForPath(const QString& filePath) const;
-- QModelIndex indexForImageInfo(const ImageInfo& info) const;
-- QModelIndex indexForImageId(qlonglong id) const;
--
-- /** Returns a list of all image infos, sorted according to this model.
-- * If you do not need a sorted list, use ImageModel's imageInfos() method.
-- */
-- QList<ImageInfo> imageInfosSorted() const;
--
-- /// Returns this, any chained ImageFilterModel, or 0.
-- virtual ImageFilterModel* imageFilterModel() const;
--
--protected:
--
-- /// Reimplement if needed. Called only when model shall be set as (direct) sourceModel.
-- virtual void setDirectSourceImageModel(ImageModel* model);
--
-- // made protected
-- virtual void setSourceModel(QAbstractItemModel* model);
--
--protected:
--
-- ImageSortFilterModel* m_chainedModel;
--};
--
--// -----------------------------------------------------------------------------------------------
--
--class DIGIKAM_DATABASE_EXPORT ImageFilterModel : public ImageSortFilterModel
--{
-- Q_OBJECT
--
--public:
--
-- enum ImageFilterModelRoles
-- {
-- /// Returns the current categorization mode
-- CategorizationModeRole = ImageModel::FilterModelRoles + 1,
-- /// Returns the current sort order
-- SortOrderRole = ImageModel::FilterModelRoles + 2,
-- // / Returns the number of items in the index' category
-- //CategoryCountRole = ImageModel::FilterModelRoles + 3,
-- /// Returns the id of the PAlbum of the index which is used for category
-- CategoryAlbumIdRole = ImageModel::FilterModelRoles + 3,
-- /// Returns the format of the index which is used for category
-- CategoryFormatRole = ImageModel::FilterModelRoles + 4,
-- /// Returns true if the given image is a group leader, and the group is opened
-- GroupIsOpenRole = ImageModel::FilterModelRoles + 5,
-- ImageFilterModelPointerRole = ImageModel::FilterModelRoles + 50
-- };
--
--public:
--
-- explicit ImageFilterModel(QObject* parent = 0);
-- ~ImageFilterModel();
--
-- /** Add a hook to get added images for preparation tasks before they are added in the model */
-- void addPrepareHook(ImageFilterModelPrepareHook* hook);
-- void removePrepareHook(ImageFilterModelPrepareHook* hook);
--
-- /** Returns a set of DatabaseFields suggested to set as watch flags on the source ImageModel.
-- * The contained flags will be those that this model can sort or filter by. */
-- DatabaseFields::Set suggestedWatchFlags() const;
--
-- ImageFilterSettings imageFilterSettings() const;
-- VersionImageFilterSettings versionImageFilterSettings() const;
-- GroupImageFilterSettings groupImageFilterSettings() const;
-- ImageSortSettings imageSortSettings() const;
--
-- // group is identified by the id of its group leader
-- bool isGroupOpen(qlonglong group) const;
-- bool isAllGroupsOpen() const;
--
-- /// Enables sending imageInfosAdded and imageInfosAboutToBeRemoved
-- void setSendImageInfoSignals(bool sendSignals);
--
-- virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
-- virtual ImageFilterModel* imageFilterModel() const;
--
--public Q_SLOTS:
--
-- /** Changes the current version image filter settings and refilters. */
-- void setVersionImageFilterSettings(const VersionImageFilterSettings& settings);
--
-- /** Changes the current version image filter settings and refilters. */
-- void setGroupImageFilterSettings(const GroupImageFilterSettings& settings);
--
-- /** Adjust the current ImageFilterSettings.
-- * Equivalent to retrieving the current filter settings, adjusting the parameter
-- * and calling setImageFilterSettings.
-- * Provided for convenience.
-- * It is encouraged to use setImageFilterSettings if you change more than one
-- * parameter at a time.
-- */
-- void setDayFilter(const QList<QDateTime>& days);
-- void setTagFilter(const QList<int>& includedTags, const QList<int>& excludedTags,
-- ImageFilterSettings::MatchingCondition matchingCond, bool showUnTagged,
-- const QList<int>& clTagIds, const QList<int>& plTagIds);
-- void setRatingFilter(int rating, ImageFilterSettings::RatingCondition ratingCond, bool isUnratedExcluded);
-- void setMimeTypeFilter(int mimeTypeFilter);
-- void setGeolocationFilter(const ImageFilterSettings::GeolocationCondition& condition);
-- void setTextFilter(const SearchTextFilterSettings& settings);
--
-- void setCategorizationMode(ImageSortSettings::CategorizationMode mode);
-- void setCategorizationSortOrder(ImageSortSettings::SortOrder order);
-- void setSortRole(ImageSortSettings::SortRole role);
-- void setSortOrder(ImageSortSettings::SortOrder order);
-- void setStringTypeNatural(bool natural);
-- void setUrlWhitelist(const QList<QUrl> urlList, const QString& id);
-- void setIdWhitelist(const QList<qlonglong>& idList, const QString& id);
--
-- void setVersionManagerSettings(const VersionManagerSettings& settings);
-- void setExceptionList(const QList<qlonglong>& idlist, const QString& id);
--
-- void setGroupOpen(qlonglong group, bool open);
-- void toggleGroupOpen(qlonglong group);
-- void setAllGroupsOpen(bool open);
--
-- /** Changes the current image filter settings and refilters. */
-- virtual void setImageFilterSettings(const ImageFilterSettings& settings);
--
-- /** Changes the current image sort settings and resorts. */
-- virtual void setImageSortSettings(const ImageSortSettings& settings);
--
--Q_SIGNALS:
--
-- /// Signals that the set filter matches at least one index
-- void filterMatches(bool matches);
--
-- /** Signals that the set text filter matches at least one entry.
-- If no text filter is set, this signal is emitted
-- with 'false' when filterMatches() is emitted.
-- */
-- void filterMatchesForText(bool matchesByText);
--
-- /** Emitted when the filter settings have been changed
-- (the model may not yet have been updated)
-- */
-- void filterSettingsChanged(const ImageFilterSettings& settings);
--
-- /** These signals need to be explicitly enabled with setSendImageInfoSignals()
-- */
-- void imageInfosAdded(const QList<ImageInfo>& infos);
-- void imageInfosAboutToBeRemoved(const QList<ImageInfo>& infos);
--
--public:
--
-- // Declared as public because of use in sub-classes.
-- class ImageFilterModelPrivate;
--
--protected:
--
-- ImageFilterModelPrivate* const d_ptr;
--
--protected:
--
-- ImageFilterModel(ImageFilterModelPrivate& dd, QObject* parent);
--
-- virtual void setDirectSourceImageModel(ImageModel* model);
--
-- virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
--
-- virtual int compareCategories(const QModelIndex& left, const QModelIndex& right) const;
-- virtual bool subSortLessThan(const QModelIndex& left, const QModelIndex& right) const;
-- //virtual int categoryCount(const ImageInfo& info) const;
--
-- /** Reimplement to customize category sorting,
-- * Return negative if category of left < category right,
-- * Return 0 if left and right are in the same category, else return positive.
-- */
-- virtual int compareInfosCategories(const ImageInfo& left, const ImageInfo& right) const;
--
-- /** Reimplement to customize sorting. Do not take categories into account here.
-- */
-- virtual bool infosLessThan(const ImageInfo& left, const ImageInfo& right) const;
--
-- /** Returns a unique identifier for the category if info. The string need not be for user display.
-- */
-- virtual QString categoryIdentifier(const ImageInfo& info) const;
--
--protected Q_SLOTS:
--
-- void slotModelReset();
-- void slotUpdateFilter();
--
-- void slotImageTagChange(const ImageTagChangeset& changeset);
-- void slotImageChange(const ImageChangeset& changeset);
--
-- void slotRowsInserted(const QModelIndex& parent, int start, int end);
-- void slotRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end);
--
--private:
--
-- Q_DECLARE_PRIVATE(ImageFilterModel)
--};
--
--// -----------------------------------------------------------------------------------------------------
--
--class DIGIKAM_DATABASE_EXPORT NoDuplicatesImageFilterModel : public ImageSortFilterModel
--{
-- Q_OBJECT
--
--public:
--
-- explicit NoDuplicatesImageFilterModel(QObject* parent = 0);
--
--protected:
--
-- virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
--};
--
--} // namespace Digikam
--
--Q_DECLARE_METATYPE(Digikam::ImageFilterModel*)
--
--#endif // IMAGEMODEL_H
-diff --git a/libs/models/imagefiltermodelpriv.cpp b/libs/models/imagefiltermodelpriv.cpp
-deleted file mode 100644
-index 07d9e79..0000000
---- a/libs/models/imagefiltermodelpriv.cpp
-+++ /dev/null
-@@ -1,258 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Qt item model for database entries
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-- * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-- * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-- * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagefiltermodelpriv.h"
--
--// Local includes
--
--#include "digikam_debug.h"
--#include "imagefiltermodelthreads.h"
--
--namespace Digikam
--{
--
--ImageFilterModel::ImageFilterModelPrivate::ImageFilterModelPrivate()
--{
-- imageModel = 0;
-- version = 0;
-- lastDiscardVersion = 0;
-- sentOut = 0;
-- sentOutForReAdd = 0;
-- updateFilterTimer = 0;
-- needPrepare = false;
-- needPrepareComments = false;
-- needPrepareTags = false;
-- needPrepareGroups = false;
-- preparer = 0;
-- filterer = 0;
-- hasOneMatch = false;
-- hasOneMatchForText = false;
--
-- setupWorkers();
--}
--
--ImageFilterModel::ImageFilterModelPrivate::~ImageFilterModelPrivate()
--{
-- // facilitate thread stopping
-- ++version;
-- preparer->deactivate();
-- filterer->deactivate();
-- delete preparer;
-- delete filterer;
--}
--
--void ImageFilterModel::ImageFilterModelPrivate::init(ImageFilterModel* _q)
--{
-- q = _q;
--
-- updateFilterTimer = new QTimer(this);
-- updateFilterTimer->setSingleShot(true);
-- updateFilterTimer->setInterval(250);
--
-- connect(updateFilterTimer, SIGNAL(timeout()),
-- q, SLOT(slotUpdateFilter()));
--
-- // inter-thread redirection
-- qRegisterMetaType<ImageFilterModelTodoPackage>("ImageFilterModelTodoPackage");
--}
--
--void ImageFilterModel::ImageFilterModelPrivate::preprocessInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- infosToProcess(infos, extraValues, true);
--}
--
--void ImageFilterModel::ImageFilterModelPrivate::processAddedInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- // These have already been added, we just process them afterwards
-- infosToProcess(infos, extraValues, false);
--}
--
--void ImageFilterModel::ImageFilterModelPrivate::setupWorkers()
--{
-- preparer = new ImageFilterModelPreparer(this);
-- filterer = new ImageFilterModelFilterer(this);
--
-- // A package in constructed in infosToProcess.
-- // Normal flow is infosToProcess -> preparer::process -> filterer::process -> packageFinished.
-- // If no preparation is needed, the first step is skipped.
-- // If filter version changes, both will discard old package and send them to packageDiscarded.
--
-- connect(this, SIGNAL(packageToPrepare(ImageFilterModelTodoPackage)),
-- preparer, SLOT(process(ImageFilterModelTodoPackage)));
--
-- connect(this, SIGNAL(packageToFilter(ImageFilterModelTodoPackage)),
-- filterer, SLOT(process(ImageFilterModelTodoPackage)));
--
-- connect(preparer, SIGNAL(processed(ImageFilterModelTodoPackage)),
-- filterer, SLOT(process(ImageFilterModelTodoPackage)));
--
-- connect(filterer, SIGNAL(processed(ImageFilterModelTodoPackage)),
-- this, SLOT(packageFinished(ImageFilterModelTodoPackage)));
--
-- connect(preparer, SIGNAL(discarded(ImageFilterModelTodoPackage)),
-- this, SLOT(packageDiscarded(ImageFilterModelTodoPackage)));
--
-- connect(filterer, SIGNAL(discarded(ImageFilterModelTodoPackage)),
-- this, SLOT(packageDiscarded(ImageFilterModelTodoPackage)));
--}
--
--void ImageFilterModel::ImageFilterModelPrivate::infosToProcess(const QList<ImageInfo>& infos)
--{
-- infosToProcess(infos, QList<QVariant>(), false);
--}
--
--void ImageFilterModel::ImageFilterModelPrivate::infosToProcess(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues, bool forReAdd)
--{
-- if (infos.isEmpty())
-- {
-- return;
-- }
--
-- filterer->schedule();
--
-- if (needPrepare)
-- {
-- preparer->schedule();
-- }
--
-- Q_ASSERT(extraValues.isEmpty() || infos.size() == extraValues.size());
--
-- // prepare and filter in chunks
-- const int size = infos.size();
-- const int maxChunkSize = needPrepare ? PrepareChunkSize : FilterChunkSize;
-- const bool hasExtraValues = !extraValues.isEmpty();
-- QList<ImageInfo>::const_iterator it = infos.constBegin(), end;
-- QList<QVariant>::const_iterator xit = extraValues.constBegin(), xend;
-- int index = 0;
-- QVector<ImageInfo> infoVector;
-- QVector<QVariant> extraValueVector;
--
-- while (it != infos.constEnd())
-- {
-- const int chunkSize = qMin(maxChunkSize, size - index);
-- infoVector.resize(chunkSize);
-- end = it + chunkSize;
-- qCopy(it, end, infoVector.begin());
--
-- if (hasExtraValues)
-- {
-- extraValueVector.resize(chunkSize);
-- xend = xit + chunkSize;
-- qCopy(xit, xend, extraValueVector.begin());
-- xit = xend;
-- }
--
-- it = end;
-- index += chunkSize;
--
-- ++sentOut;
--
-- if (forReAdd)
-- {
-- ++sentOutForReAdd;
-- }
--
-- if (needPrepare)
-- {
-- emit packageToPrepare(ImageFilterModelTodoPackage(infoVector, extraValueVector, version, forReAdd));
-- }
-- else
-- {
-- emit packageToFilter(ImageFilterModelTodoPackage(infoVector, extraValueVector, version, forReAdd));
-- }
-- }
--}
--
--void ImageFilterModel::ImageFilterModelPrivate::packageFinished(const ImageFilterModelTodoPackage& package)
--{
-- // check if it got discarded on the journey
-- if (package.version != version)
-- {
-- packageDiscarded(package);
-- return;
-- }
--
-- // incorporate result
-- QHash<qlonglong, bool>::const_iterator it = package.filterResults.constBegin();
--
-- for (; it != package.filterResults.constEnd(); ++it)
-- {
-- filterResults.insert(it.key(), it.value());
-- }
--
-- // re-add if necessary
-- if (package.isForReAdd)
-- {
-- emit reAddImageInfos(package.infos.toList(), package.extraValues.toList());
--
-- if (sentOutForReAdd == 1) // last package
-- {
-- emit reAddingFinished();
-- }
-- }
--
-- // decrement counters
-- --sentOut;
--
-- if (package.isForReAdd)
-- {
-- --sentOutForReAdd;
-- }
--
-- // If all packages have returned, filtered and readded, and no more are expected,
-- // and there is need to tell the filter result to the view, do that
-- if (sentOut == 0 && sentOutForReAdd == 0 && !imageModel->isRefreshing())
-- {
-- q->invalidate(); // use invalidate, not invalidateFilter only. Sorting may have changed as well.
-- emit (q->filterMatches(hasOneMatch));
-- emit (q->filterMatchesForText(hasOneMatchForText));
-- filterer->deactivate();
-- preparer->deactivate();
-- }
--}
--
--void ImageFilterModel::ImageFilterModelPrivate::packageDiscarded(const ImageFilterModelTodoPackage& package)
--{
-- // Either, the model was reset, or the filter changed
-- // In the former case throw all away, in the latter case, recycle
-- if (package.version > lastDiscardVersion)
-- {
-- // Recycle packages: Send again with current version
-- // Do not increment sentOut or sentOutForReAdd here: it was not decremented!
--
-- if (needPrepare)
-- {
-- emit packageToPrepare(ImageFilterModelTodoPackage(package.infos, package.extraValues, version, package.isForReAdd));
-- }
-- else
-- {
-- emit packageToFilter(ImageFilterModelTodoPackage(package.infos, package.extraValues, version, package.isForReAdd));
-- }
-- }
--}
--
--} // namespace Digikam
-diff --git a/libs/models/imagefiltermodelpriv.h b/libs/models/imagefiltermodelpriv.h
-deleted file mode 100644
-index a9e3f22..0000000
---- a/libs/models/imagefiltermodelpriv.h
-+++ /dev/null
-@@ -1,159 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-11
-- * Description : Qt item model for database entries - private shared header
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- *
-- * 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 IMAGEFILTERMODELPRIV_H
--#define IMAGEFILTERMODELPRIV_H
--
--// Qt includes
--
--#include <QHash>
--#include <QMutex>
--#include <QMutexLocker>
--#include <QSet>
--#include <QThread>
--#include <QTimer>
--#include <QWaitCondition>
--
--// Local includes
--
--#include "imageinfo.h"
--#include "imagefiltermodel.h"
--
--#include "digikam_export.h"
--// Yes, we need the EXPORT macro in a private header because
--// this private header is shared across binary objects.
--// This does NOT make this classes here any more public!
--
--namespace Digikam
--{
--
--const int PrepareChunkSize = 101;
--const int FilterChunkSize = 2001;
--
--class ImageFilterModelTodoPackage
--{
--public:
--
-- ImageFilterModelTodoPackage()
-- : version(0), isForReAdd(false)
-- {
-- }
--
-- ImageFilterModelTodoPackage(const QVector<ImageInfo>& infos, const QVector<QVariant>& extraValues, int version, bool isForReAdd)
-- : infos(infos), extraValues(extraValues), version(version), isForReAdd(isForReAdd)
-- {
-- }
--
-- QVector<ImageInfo> infos;
-- QVector<QVariant> extraValues;
-- unsigned int version;
-- bool isForReAdd;
-- QHash<qlonglong, bool> filterResults;
--};
--
--// ------------------------------------------------------------------------------------------------
--
--class ImageFilterModelPreparer;
--class ImageFilterModelFilterer;
--
--class DIGIKAM_DATABASE_EXPORT ImageFilterModel::ImageFilterModelPrivate : public QObject
--{
-- Q_OBJECT
--
--public:
--
-- ImageFilterModelPrivate();
-- ~ImageFilterModelPrivate();
--
-- void init(ImageFilterModel* q);
-- void setupWorkers();
-- void infosToProcess(const QList<ImageInfo>& infos);
-- void infosToProcess(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues, bool forReAdd = true);
--
--public:
--
-- ImageFilterModel* q;
--
-- ImageModel* imageModel;
--
-- ImageFilterSettings filter;
-- ImageSortSettings sorter;
-- VersionImageFilterSettings versionFilter;
-- GroupImageFilterSettings groupFilter;
--
-- volatile unsigned int version;
-- unsigned int lastDiscardVersion;
-- unsigned int lastFilteredVersion;
-- int sentOut;
-- int sentOutForReAdd;
--
-- QTimer* updateFilterTimer;
--
-- bool needPrepare;
-- bool needPrepareComments;
-- bool needPrepareTags;
-- bool needPrepareGroups;
--
-- QMutex mutex;
-- ImageFilterSettings filterCopy;
-- VersionImageFilterSettings versionFilterCopy;
-- GroupImageFilterSettings groupFilterCopy;
-- ImageFilterModelPreparer* preparer;
-- ImageFilterModelFilterer* filterer;
--
-- QHash<qlonglong, bool> filterResults;
-- bool hasOneMatch;
-- bool hasOneMatchForText;
--
-- QList<ImageFilterModelPrepareHook*> prepareHooks;
--
--/*
-- QHash<int, QSet<qlonglong> > categoryCountHashInt;
-- QHash<QString, QSet<qlonglong> > categoryCountHashString;
--
--public:
--
-- void cacheCategoryCount(int id, qlonglong imageid) const
-- { const_cast<ImageFilterModelPrivate*>(this)->categoryCountHashInt[id].insert(imageid); }
-- void cacheCategoryCount(const QString& id, qlonglong imageid) const
-- { const_cast<ImageFilterModelPrivate*>(this)->categoryCountHashString[id].insert(imageid); }
--*/
--
--public Q_SLOTS:
--
-- void preprocessInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-- void processAddedInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-- void packageFinished(const ImageFilterModelTodoPackage& package);
-- void packageDiscarded(const ImageFilterModelTodoPackage& package);
--
--Q_SIGNALS:
--
-- void packageToPrepare(const ImageFilterModelTodoPackage& package);
-- void packageToFilter(const ImageFilterModelTodoPackage& package);
-- void reAddImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-- void reAddingFinished();
--};
--
--} // namespace Digikam
--
--#endif // IMAGEFILTERMODELPRIV_H
-diff --git a/libs/models/imagefiltermodelthreads.cpp b/libs/models/imagefiltermodelthreads.cpp
-deleted file mode 100644
-index aa5c462..0000000
---- a/libs/models/imagefiltermodelthreads.cpp
-+++ /dev/null
-@@ -1,40 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Qt item model for database entries
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-- * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-- * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-- * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagefiltermodel.h"
--#include "imagefiltermodelpriv.h"
--#include "imagefiltermodelthreads.h"
--
--namespace Digikam
--{
--
--ImageFilterModelWorker::ImageFilterModelWorker(ImageFilterModel::ImageFilterModelPrivate* const d)
-- : d(d)
--{
--}
--
--} // namespace Digikam
-diff --git a/libs/models/imagefiltermodelthreads.h b/libs/models/imagefiltermodelthreads.h
-deleted file mode 100644
-index 83fa987..0000000
---- a/libs/models/imagefiltermodelthreads.h
-+++ /dev/null
-@@ -1,100 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-11
-- * Description : Qt item model for database entries - private header
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- *
-- * 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 IMAGEFILTERMODELTHREADS_H
--#define IMAGEFILTERMODELTHREADS_H
--
--// Qt includes
--
--#include <QThread>
--
--// Local includes
--
--#include "digikam_export.h"
--#include "workerobject.h"
--
--namespace Digikam
--{
--
--class DIGIKAM_DATABASE_EXPORT ImageFilterModelWorker : public WorkerObject
--{
-- Q_OBJECT
--
--public:
--
-- explicit ImageFilterModelWorker(ImageFilterModel::ImageFilterModelPrivate* const d);
--
-- bool checkVersion(const ImageFilterModelTodoPackage& package)
-- {
-- return d->version == package.version;
-- }
--
--public Q_SLOTS:
--
-- virtual void process(ImageFilterModelTodoPackage package) = 0;
--
--Q_SIGNALS:
--
-- void processed(const ImageFilterModelTodoPackage& package);
-- void discarded(const ImageFilterModelTodoPackage& package);
--
--protected:
--
-- ImageFilterModel::ImageFilterModelPrivate* d;
--};
--
--// -----------------------------------------------------------------------------------------
--
--class DIGIKAM_DATABASE_EXPORT ImageFilterModelPreparer : public ImageFilterModelWorker
--{
-- Q_OBJECT
--
--public:
--
-- explicit ImageFilterModelPreparer(ImageFilterModel::ImageFilterModelPrivate* const d)
-- : ImageFilterModelWorker(d)
-- {
-- }
--
-- void process(ImageFilterModelTodoPackage package);
--};
--
--// ----------------------------------------------------------------------------------------
--
--class DIGIKAM_DATABASE_EXPORT ImageFilterModelFilterer : public ImageFilterModelWorker
--{
-- Q_OBJECT
--
--public:
--
-- explicit ImageFilterModelFilterer(ImageFilterModel::ImageFilterModelPrivate* const d)
-- : ImageFilterModelWorker(d)
-- {
-- }
--
-- void process(ImageFilterModelTodoPackage package);
--};
--
--} // namespace Digikam
--
--#endif // IMAGEFILTERMODELTHREADS_H
-diff --git a/libs/models/imagefiltersettings.cpp b/libs/models/imagefiltersettings.cpp
-deleted file mode 100644
-index b61e7f9..0000000
---- a/libs/models/imagefiltersettings.cpp
-+++ /dev/null
-@@ -1,952 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Filter values for use with ImageFilterModel
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-- * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-- * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-- * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagefiltersettings.h"
--
--// C++ includes
--
--#include <cmath>
--
--// Qt includes
--
--#include <QDateTime>
--
--// Local includes
--
--#include "digikam_debug.h"
--#include "coredbfields.h"
--#include "digikam_globals.h"
--#include "imageinfo.h"
--#include "tagscache.h"
--#include "versionmanagersettings.h"
--
--namespace Digikam
--{
--
--ImageFilterSettings::ImageFilterSettings()
--{
-- m_untaggedFilter = false;
-- m_isUnratedExcluded = false;
-- m_ratingFilter = 0;
-- m_mimeTypeFilter = MimeFilter::AllFiles;
-- m_ratingCond = GreaterEqualCondition;
-- m_matchingCond = OrCondition;
-- m_geolocationCondition = GeolocationNoFilter;
--}
--
--DatabaseFields::Set ImageFilterSettings::watchFlags() const
--{
-- DatabaseFields::Set set;
--
-- if (isFilteringByDay())
-- {
-- set |= DatabaseFields::CreationDate;
-- }
--
-- if (isFilteringByText())
-- {
-- set |= DatabaseFields::Name;
-- set |= DatabaseFields::Comment;
-- }
--
-- if (isFilteringByRating())
-- {
-- set |= DatabaseFields::Rating;
-- }
--
-- if (isFilteringByTypeMime())
-- {
-- set |= DatabaseFields::Category;
-- set |= DatabaseFields::Format;
-- }
--
-- if (isFilteringByGeolocation())
-- {
-- set |= DatabaseFields::ImagePositionsAll;
-- }
--
-- if (isFilteringByColorLabels())
-- {
-- set |= DatabaseFields::ColorLabel;
-- }
--
-- if (isFilteringByPickLabels())
-- {
-- set |= DatabaseFields::PickLabel;
-- }
--
-- return set;
--}
--
--bool ImageFilterSettings::isFilteringByDay() const
--{
-- if (!m_dayFilter.isEmpty())
-- {
-- return true;
-- }
--
-- return false;
--}
--
--bool ImageFilterSettings::isFilteringByTags() const
--{
-- if (!m_includeTagFilter.isEmpty() || !m_excludeTagFilter.isEmpty() || m_untaggedFilter)
-- {
-- return true;
-- }
--
-- return false;
--}
--
--bool ImageFilterSettings::isFilteringByColorLabels() const
--{
-- if (!m_colorLabelTagFilter.isEmpty())
-- {
-- return true;
-- }
--
-- return false;
--}
--
--bool ImageFilterSettings::isFilteringByPickLabels() const
--{
-- if (!m_pickLabelTagFilter.isEmpty())
-- {
-- return true;
-- }
--
-- return false;
--}
--
--bool ImageFilterSettings::isFilteringByText() const
--{
-- if (!m_textFilterSettings.text.isEmpty())
-- {
-- return true;
-- }
--
-- return false;
--}
--
--bool ImageFilterSettings::isFilteringByTypeMime() const
--{
-- if (m_mimeTypeFilter != MimeFilter::AllFiles)
-- {
-- return true;
-- }
--
-- return false;
--}
--
--bool ImageFilterSettings::isFilteringByGeolocation() const
--{
-- return (m_geolocationCondition != GeolocationNoFilter);
--}
--
--bool ImageFilterSettings::isFilteringByRating() const
--{
-- if (m_ratingFilter != 0 || m_ratingCond != GreaterEqualCondition || m_isUnratedExcluded)
-- {
-- return true;
-- }
--
-- return false;
--}
--
--bool ImageFilterSettings::isFilteringInternally() const
--{
-- return (isFiltering() || !m_urlWhitelists.isEmpty() || !m_idWhitelists.isEmpty());
--}
--
--bool ImageFilterSettings::isFiltering() const
--{
-- return isFilteringByDay() ||
-- isFilteringByTags() ||
-- isFilteringByText() ||
-- isFilteringByRating() ||
-- isFilteringByTypeMime() ||
-- isFilteringByColorLabels() ||
-- isFilteringByPickLabels() ||
-- isFilteringByGeolocation();
--}
--
--void ImageFilterSettings::setDayFilter(const QList<QDateTime>& days)
--{
-- m_dayFilter.clear();
--
-- for (QList<QDateTime>::const_iterator it = days.constBegin(); it != days.constEnd(); ++it)
-- {
-- m_dayFilter.insert(*it, true);
-- }
--}
--
--void ImageFilterSettings::setTagFilter(const QList<int>& includedTags,
-- const QList<int>& excludedTags,
-- MatchingCondition matchingCondition,
-- bool showUnTagged,
-- const QList<int>& clTagIds,
-- const QList<int>& plTagIds)
--{
-- m_includeTagFilter = includedTags;
-- m_excludeTagFilter = excludedTags;
-- m_matchingCond = matchingCondition;
-- m_untaggedFilter = showUnTagged;
-- m_colorLabelTagFilter = clTagIds;
-- m_pickLabelTagFilter = plTagIds;
--}
--
--void ImageFilterSettings::setRatingFilter(int rating, RatingCondition ratingCondition, bool isUnratedExcluded)
--{
-- m_ratingFilter = rating;
-- m_ratingCond = ratingCondition;
-- m_isUnratedExcluded = isUnratedExcluded;
--}
--
--void ImageFilterSettings::setMimeTypeFilter(int mime)
--{
-- m_mimeTypeFilter = (MimeFilter::TypeMimeFilter)mime;
--}
--
--void ImageFilterSettings::setGeolocationFilter(const GeolocationCondition& condition)
--{
-- m_geolocationCondition = condition;
--}
--
--void ImageFilterSettings::setTextFilter(const SearchTextFilterSettings& settings)
--{
-- m_textFilterSettings = settings;
--}
--
--void ImageFilterSettings::setTagNames(const QHash<int, QString>& hash)
--{
-- m_tagNameHash = hash;
--}
--
--void ImageFilterSettings::setAlbumNames(const QHash<int, QString>& hash)
--{
-- m_albumNameHash = hash;
--}
--
--void ImageFilterSettings::setUrlWhitelist(const QList<QUrl>& urlList, const QString& id)
--{
-- if (urlList.isEmpty())
-- {
-- m_urlWhitelists.remove(id);
-- }
-- else
-- {
-- m_urlWhitelists.insert(id, urlList);
-- }
--}
--
--void ImageFilterSettings::setIdWhitelist(const QList<qlonglong>& idList, const QString& id)
--{
-- if (idList.isEmpty())
-- {
-- m_idWhitelists.remove(id);
-- }
-- else
-- {
-- m_idWhitelists.insert(id, idList);
-- }
--}
--
--template <class ContainerA, class ContainerB>
--bool containsAnyOf(const ContainerA& listA, const ContainerB& listB)
--{
-- foreach (const typename ContainerA::value_type& a, listA)
-- {
-- if (listB.contains(a))
-- {
-- return true;
-- }
-- }
-- return false;
--}
--
--template <class ContainerA, typename Value, class ContainerB>
--bool containsNoneOfExcept(const ContainerA& list, const ContainerB& noneOfList, const Value& exception)
--{
-- foreach (const typename ContainerB::value_type& n, noneOfList)
-- {
-- if (n != exception && list.contains(n))
-- {
-- return false;
-- }
-- }
-- return true;
--}
--
--bool ImageFilterSettings::matches(const ImageInfo& info, bool* const foundText) const
--{
-- if (foundText)
-- {
-- *foundText = false;
-- }
--
-- if (!isFilteringInternally())
-- {
-- return true;
-- }
--
-- bool match = false;
--
-- if (!m_includeTagFilter.isEmpty() || !m_excludeTagFilter.isEmpty())
-- {
-- QList<int> tagIds = info.tagIds();
-- QList<int>::const_iterator it;
--
-- match = m_includeTagFilter.isEmpty();
--
-- if (m_matchingCond == OrCondition)
-- {
-- for (it = m_includeTagFilter.begin(); it != m_includeTagFilter.end(); ++it)
-- {
-- if (tagIds.contains(*it))
-- {
-- match = true;
-- break;
-- }
-- }
--
-- match |= (m_untaggedFilter && tagIds.isEmpty());
-- }
-- else // AND matching condition...
-- {
-- // m_untaggedFilter and non-empty tag filter, combined with AND, is logically no match
-- if (!m_untaggedFilter)
-- {
-- for (it = m_includeTagFilter.begin(); it != m_includeTagFilter.end(); ++it)
-- {
-- if (!tagIds.contains(*it))
-- {
-- break;
-- }
-- }
--
-- if (it == m_includeTagFilter.end())
-- {
-- match = true;
-- }
-- }
-- }
--
-- for (it = m_excludeTagFilter.begin(); it != m_excludeTagFilter.end(); ++it)
-- {
-- if (tagIds.contains(*it))
-- {
-- match = false;
-- break;
-- }
-- }
-- }
-- else if (m_untaggedFilter)
-- {
-- match = !TagsCache::instance()->containsPublicTags(info.tagIds());
-- }
-- else
-- {
-- match = true;
-- }
--
-- //-- Filter by pick labels ------------------------------------------------
--
-- if (!m_pickLabelTagFilter.isEmpty())
-- {
-- QList<int> tagIds = info.tagIds();
-- bool matchPL = false;
--
-- if (containsAnyOf(m_pickLabelTagFilter, tagIds))
-- {
-- matchPL = true;
-- }
-- else if (!matchPL)
-- {
-- int noPickLabelTagId = TagsCache::instance()->tagForPickLabel(NoPickLabel);
--
-- if (m_pickLabelTagFilter.contains(noPickLabelTagId))
-- {
-- // Searching for "has no ColorLabel" requires special handling:
-- // Scan that the tag ids contains none of the ColorLabel tags, except maybe the NoColorLabel tag
-- matchPL = containsNoneOfExcept(tagIds, TagsCache::instance()->pickLabelTags(), noPickLabelTagId);
-- }
-- }
--
-- match &= matchPL;
-- }
--
-- //-- Filter by color labels ------------------------------------------------
--
-- if (!m_colorLabelTagFilter.isEmpty())
-- {
-- QList<int> tagIds = info.tagIds();
-- bool matchCL = false;
--
-- if (containsAnyOf(m_colorLabelTagFilter, tagIds))
-- {
-- matchCL = true;
-- }
-- else if (!matchCL)
-- {
-- int noColorLabelTagId = TagsCache::instance()->tagForColorLabel(NoColorLabel);
--
-- if (m_colorLabelTagFilter.contains(noColorLabelTagId))
-- {
-- // Searching for "has no ColorLabel" requires special handling:
-- // Scan that the tag ids contains none of the ColorLabel tags, except maybe the NoColorLabel tag
-- matchCL = containsNoneOfExcept(tagIds, TagsCache::instance()->colorLabelTags(), noColorLabelTagId);
-- }
-- }
--
-- match &= matchCL;
-- }
--
-- //-- Filter by date -----------------------------------------------------------
--
-- if (!m_dayFilter.isEmpty())
-- {
-- match &= m_dayFilter.contains(QDateTime(info.dateTime().date(), QTime()));
-- }
--
-- //-- Filter by rating ---------------------------------------------------------
--
-- if (m_ratingFilter >= 0)
-- {
-- // for now we treat -1 (no rating) just like a rating of 0.
-- int rating = info.rating();
--
-- if (rating == -1)
-- {
-- rating = 0;
-- }
--
-- if(m_isUnratedExcluded && rating == 0)
-- {
-- match = false;
-- }
-- else
-- {
-- if (m_ratingCond == GreaterEqualCondition)
-- {
-- // If the rating is not >=, i.e it is <, then it does not match.
-- if (rating < m_ratingFilter)
-- {
-- match = false;
-- }
-- }
-- else if (m_ratingCond == EqualCondition)
-- {
-- // If the rating is not =, i.e it is !=, then it does not match.
-- if (rating != m_ratingFilter)
-- {
-- match = false;
-- }
-- }
-- else
-- {
-- // If the rating is not <=, i.e it is >, then it does not match.
-- if (rating > m_ratingFilter)
-- {
-- match = false;
-- }
-- }
-- }
-- }
--
-- // -- Filter by mime type -----------------------------------------------------
--
-- switch (m_mimeTypeFilter)
-- {
-- // info.format is a standardized string: Only one possibility per mime type
-- case MimeFilter::ImageFiles:
-- {
-- if (info.category() != DatabaseItem::Image)
-- {
-- match = false;
-- }
--
-- break;
-- }
-- case MimeFilter::JPGFiles:
-- {
-- if (info.format() != QLatin1String("JPG"))
-- {
-- match = false;
-- }
--
-- break;
-- }
-- case MimeFilter::PNGFiles:
-- {
-- if (info.format() != QLatin1String("PNG"))
-- {
-- match = false;
-- }
--
-- break;
-- }
-- case MimeFilter::TIFFiles:
-- {
-- if (info.format() != QLatin1String("TIFF"))
-- {
-- match = false;
-- }
--
-- break;
-- }
-- case MimeFilter::DNGFiles:
-- {
-- if (info.format() != QLatin1String("RAW-DNG"))
-- {
-- match = false;
-- }
--
-- break;
-- }
-- case MimeFilter::NoRAWFiles:
-- {
-- if (info.format().startsWith(QLatin1String("RAW")))
-- {
-- match = false;
-- }
--
-- break;
-- }
-- case MimeFilter::RAWFiles:
-- {
-- if (!info.format().startsWith(QLatin1String("RAW")))
-- {
-- match = false;
-- }
--
-- break;
-- }
-- case MimeFilter::MoviesFiles:
-- {
-- if (info.category() != DatabaseItem::Video)
-- {
-- match = false;
-- }
--
-- break;
-- }
-- case MimeFilter::AudioFiles:
-- {
-- if (info.category() != DatabaseItem::Audio)
-- {
-- match = false;
-- }
--
-- break;
-- }
-- case MimeFilter::RasterFiles:
-- {
-- if (info.format() != QLatin1String("PSD") && // Adobe Photoshop Document
-- info.format() != QLatin1String("PSB") && // Adobe Photoshop Big
-- info.format() != QLatin1String("XCF") && // Gimp
-- info.format() != QLatin1String("KRA") && // Krita
-- info.format() != QLatin1String("ORA") // Open Raster
-- )
-- {
-- match = false;
-- }
--
-- break;
-- }
-- default:
-- {
-- // All Files: do nothing...
-- break;
-- }
-- }
--
-- //-- Filter by geolocation ----------------------------------------------------
--
-- if (m_geolocationCondition!=GeolocationNoFilter)
-- {
-- if (m_geolocationCondition==GeolocationNoCoordinates)
-- {
-- if (info.hasCoordinates())
-- {
-- match = false;
-- }
-- }
-- else if (m_geolocationCondition==GeolocationHasCoordinates)
-- {
-- if (!info.hasCoordinates())
-- {
-- match = false;
-- }
-- }
-- }
--
-- //-- Filter by text -----------------------------------------------------------
--
-- if (!m_textFilterSettings.text.isEmpty())
-- {
-- bool textMatch = false;
--
-- // Image name
-- if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImageName &&
-- info.name().contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-- {
-- textMatch = true;
-- }
--
-- // Image title
-- if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImageTitle &&
-- info.title().contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-- {
-- textMatch = true;
-- }
--
-- // Image comment
-- if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImageComment &&
-- info.comment().contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-- {
-- textMatch = true;
-- }
--
-- // Tag names
-- foreach(int id, info.tagIds())
-- {
-- if (m_textFilterSettings.textFields & SearchTextFilterSettings::TagName &&
-- m_tagNameHash.value(id).contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-- {
-- textMatch = true;
-- }
-- }
--
-- // Album names
-- if (m_textFilterSettings.textFields & SearchTextFilterSettings::AlbumName &&
-- m_albumNameHash.value(info.albumId()).contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive))
-- {
-- textMatch = true;
-- }
--
-- // Image Aspect Ratio
-- if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImageAspectRatio)
-- {
-- QRegExp expRatio (QLatin1String("^\\d+:\\d+$"));
-- QRegExp expFloat (QLatin1String("^\\d+(.\\d+)?$"));
--
-- if (expRatio.indexIn(m_textFilterSettings.text) > -1 && m_textFilterSettings.text.contains(QRegExp(QLatin1String(":\\d+"))))
-- {
-- QString trimmedTextFilterSettingsText = m_textFilterSettings.text;
-- QStringList numberStringList = trimmedTextFilterSettingsText.split(QLatin1String(":"), QString::SkipEmptyParts);
--
-- if (numberStringList.length() == 2)
-- {
-- QString numString = (QString)numberStringList.at(0), denomString = (QString)numberStringList.at(1);
-- bool canConverseNum = false;
-- bool canConverseDenom = false;
-- int num = numString.toInt(&canConverseNum, 10), denom = denomString.toInt(&canConverseDenom, 10);
--
-- if (canConverseNum && canConverseDenom)
-- {
-- if (fabs(info.aspectRatio() - (double)num / denom) < 0.1)
-- textMatch = true;
-- }
-- }
-- }
-- else if (expFloat.indexIn(m_textFilterSettings.text) > -1)
-- {
-- QString trimmedTextFilterSettingsText = m_textFilterSettings.text;
-- bool canConverse = false;
-- double ratio = trimmedTextFilterSettingsText.toDouble(&canConverse);
--
-- if (canConverse)
-- {
-- if (fabs(info.aspectRatio() - ratio) < 0.1)
-- textMatch = true;
-- }
-- }
-- }
--
-- // Image Pixel Size
-- // See bug #341053 for details.
--
-- if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImagePixelSize)
-- {
-- QSize size = info.dimensions();
-- int pixelSize = size.height()*size.width();
-- QString text = m_textFilterSettings.text;
--
-- if(text.contains(QRegExp(QLatin1String("^>\\d{1,15}$"))) && pixelSize > (text.remove(0,1)).toInt())
-- {
-- textMatch = true;
-- }
-- else if(text.contains(QRegExp(QLatin1String("^<\\d{1,15}$"))) && pixelSize < (text.remove(0,1)).toInt())
-- {
-- textMatch = true;
-- }
-- else if(text.contains(QRegExp(QLatin1String("^\\d+$"))) && pixelSize == text.toInt())
-- {
-- textMatch = true;
-- }
-- }
--
-- match &= textMatch;
--
-- if (foundText)
-- {
-- *foundText = textMatch;
-- }
-- }
--
-- // -- filter by URL-whitelists ------------------------------------------------
-- // NOTE: whitelists are always AND for now.
--
-- if (match)
-- {
-- const QUrl url = info.fileUrl();
--
-- for (QHash<QString, QList<QUrl>>::const_iterator it = m_urlWhitelists.constBegin();
-- it!=m_urlWhitelists.constEnd(); ++it)
-- {
-- match = it->contains(url);
--
-- if (!match)
-- {
-- break;
-- }
-- }
-- }
--
-- if (match)
-- {
-- const qlonglong id = info.id();
--
-- for (QHash<QString, QList<qlonglong> >::const_iterator it = m_idWhitelists.constBegin();
-- it!=m_idWhitelists.constEnd(); ++it)
-- {
-- match = it->contains(id);
--
-- if (!match)
-- {
-- break;
-- }
-- }
-- }
--
-- return match;
--}
--
--// -------------------------------------------------------------------------------------------------
--
--VersionImageFilterSettings::VersionImageFilterSettings()
--{
-- m_includeTagFilter = 0;
-- m_exceptionTagFilter = 0;
--}
--
--VersionImageFilterSettings::VersionImageFilterSettings(const VersionManagerSettings& settings)
--{
-- setVersionManagerSettings(settings);
--}
--
--bool VersionImageFilterSettings::operator==(const VersionImageFilterSettings& other) const
--{
-- return m_excludeTagFilter == other.m_excludeTagFilter &&
-- m_exceptionLists == other.m_exceptionLists;
--}
--
--bool VersionImageFilterSettings::matches(const ImageInfo& info) const
--{
-- if (!isFiltering())
-- {
-- return true;
-- }
--
-- const qlonglong id = info.id();
--
-- for (QHash<QString, QList<qlonglong> >::const_iterator it = m_exceptionLists.constBegin();
-- it != m_exceptionLists.constEnd(); ++it)
-- {
-- if (it->contains(id))
-- {
-- return true;
-- }
-- }
--
-- bool match = true;
-- QList<int> tagIds = info.tagIds();
--
-- if (!tagIds.contains(m_includeTagFilter))
-- {
-- for (QList<int>::const_iterator it = m_excludeTagFilter.begin();
-- it != m_excludeTagFilter.end(); ++it)
-- {
-- if (tagIds.contains(*it))
-- {
-- match = false;
-- break;
-- }
-- }
-- }
--
-- if (!match)
-- {
-- if (tagIds.contains(m_exceptionTagFilter))
-- {
-- match = true;
-- }
-- }
--
-- return match;
--}
--
--bool VersionImageFilterSettings::isHiddenBySettings(const ImageInfo& info) const
--{
-- QList<int> tagIds = info.tagIds();
--
-- foreach(int tagId, m_excludeTagFilter)
-- {
-- if (tagIds.contains(tagId))
-- {
-- return true;
-- }
-- }
--
-- return false;
--}
--
--bool VersionImageFilterSettings::isExemptedBySettings(const ImageInfo& info) const
--{
-- return info.tagIds().contains(m_exceptionTagFilter);
--}
--
--void VersionImageFilterSettings::setVersionManagerSettings(const VersionManagerSettings& settings)
--{
-- m_excludeTagFilter.clear();
--
-- if (!settings.enabled)
-- {
-- return;
-- }
--
-- if (!(settings.showInViewFlags & VersionManagerSettings::ShowOriginal))
-- {
-- m_excludeTagFilter << TagsCache::instance()->getOrCreateInternalTag(InternalTagName::originalVersion());
-- }
--
-- if (!(settings.showInViewFlags & VersionManagerSettings::ShowIntermediates))
-- {
-- m_excludeTagFilter << TagsCache::instance()->getOrCreateInternalTag(InternalTagName::intermediateVersion());
-- }
--
-- m_includeTagFilter = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::currentVersion());
-- m_exceptionTagFilter = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::versionAlwaysVisible());
--}
--
--void VersionImageFilterSettings::setExceptionList(const QList<qlonglong>& idList, const QString& id)
--{
-- if (idList.isEmpty())
-- {
-- m_exceptionLists.remove(id);
-- }
-- else
-- {
-- m_exceptionLists.insert(id, idList);
-- }
--}
--
--bool VersionImageFilterSettings::isFiltering() const
--{
-- return !m_excludeTagFilter.isEmpty();
--}
--
--bool VersionImageFilterSettings::isFilteringByTags() const
--{
-- return isFiltering();
--}
--
--// -------------------------------------------------------------------------------------------------
--
--GroupImageFilterSettings::GroupImageFilterSettings()
-- : m_allOpen(false)
--{
--}
--
--bool GroupImageFilterSettings::operator==(const GroupImageFilterSettings& other) const
--{
-- return (m_allOpen == other.m_allOpen &&
-- m_openGroups == other.m_openGroups);
--}
--
--bool GroupImageFilterSettings::matches(const ImageInfo& info) const
--{
-- if (m_allOpen)
-- {
-- return true;
-- }
--
-- if (info.isGrouped())
-- {
-- return m_openGroups.contains(info.groupImage().id());
-- }
-- return true;
--}
--
--void GroupImageFilterSettings::setOpen(qlonglong group, bool open)
--{
-- if (open)
-- {
-- m_openGroups << group;
-- }
-- else
-- {
-- m_openGroups.remove(group);
-- }
--}
--
--bool GroupImageFilterSettings::isOpen(qlonglong group) const
--{
-- return m_openGroups.contains(group);
--}
--
--void GroupImageFilterSettings::setAllOpen(bool open)
--{
-- m_allOpen = open;
--}
--
--bool GroupImageFilterSettings::isAllOpen() const
--{
-- return m_allOpen;
--}
--
--bool GroupImageFilterSettings::isFiltering() const
--{
-- return !m_allOpen;
--}
--
--DatabaseFields::Set GroupImageFilterSettings::watchFlags() const
--{
-- return DatabaseFields::ImageRelations;
--}
--
--} // namespace Digikam
-diff --git a/libs/models/imagefiltersettings.h b/libs/models/imagefiltersettings.h
-deleted file mode 100644
-index 0e7beae..0000000
---- a/libs/models/imagefiltersettings.h
-+++ /dev/null
-@@ -1,349 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Filter values for use with ImageFilterModel
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles at gmail dot com>
-- * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
-- * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
-- * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 IMAGEFILTERSETTINGS_H
--#define IMAGEFILTERSETTINGS_H
--
--// Qt includes
--
--#include <QHash>
--#include <QList>
--#include <QMap>
--#include <QString>
--#include <QSet>
--#include <QUrl>
--
--// Local includes
--
--#include "searchtextbar.h"
--#include "mimefilter.h"
--#include "digikam_export.h"
--
--namespace Digikam
--{
--
--class ImageInfo;
--class VersionManagerSettings;
--
--namespace DatabaseFields
--{
-- class Set;
--}
--
--// ---------------------------------------------------------------------------------------
--
--class DIGIKAM_DATABASE_EXPORT SearchTextFilterSettings : public SearchTextSettings
--{
--
--public:
--
-- enum TextFilterFields
-- {
-- None = 0x00,
-- ImageName = 0x01,
-- ImageTitle = 0x02,
-- ImageComment = 0x04,
-- TagName = 0x08,
-- AlbumName = 0x10,
-- ImageAspectRatio = 0x20,
-- ImagePixelSize = 0x40,
-- All = ImageName | ImageTitle | ImageComment | TagName | AlbumName | ImageAspectRatio | ImagePixelSize
-- };
--
--public:
--
-- SearchTextFilterSettings()
-- {
-- textFields = None;
-- }
--
-- explicit SearchTextFilterSettings(const SearchTextSettings& settings)
-- {
-- caseSensitive = settings.caseSensitive;
-- text = settings.text;
-- textFields = None;
-- }
--
-- TextFilterFields textFields;
--};
--
--// ---------------------------------------------------------------------------------------
--
--class DIGIKAM_DATABASE_EXPORT ImageFilterSettings
--{
--public:
--
-- ImageFilterSettings();
--
-- /**
-- * Returns true if the given ImageInfo matches the filter criteria.
-- * Optionally, foundText is set to true if it matched by text search.
-- */
-- bool matches(const ImageInfo& info, bool* const foundText = 0) const;
--
--public:
--
-- /// --- Tags filter ---
--
-- /// Possible logical matching condition used to sort tags id.
-- enum MatchingCondition
-- {
-- OrCondition,
-- AndCondition
-- };
--
-- void setTagFilter(const QList<int>& includedTags,
-- const QList<int>& excludedTags,
-- MatchingCondition matchingCond,
-- bool showUnTagged,
-- const QList<int>& clTagIds,
-- const QList<int>& plTagIds);
--
--public:
--
-- /// --- Rating filter ---
--
-- /// Possible conditions used to filter rating: >=, =, <=
-- enum RatingCondition
-- {
-- GreaterEqualCondition,
-- EqualCondition,
-- LessEqualCondition
-- };
--
-- void setRatingFilter(int rating, RatingCondition ratingCond, bool isUnratedExcluded);
--
--public:
--
-- /// --- Date filter ---
-- void setDayFilter(const QList<QDateTime>& days);
--
--public:
--
-- /// --- Text filter ---
-- void setTextFilter(const SearchTextFilterSettings& settings);
-- void setTagNames(const QHash<int, QString>& tagNameHash);
-- void setAlbumNames(const QHash<int, QString>& albumNameHash);
--
--public:
--
-- /// --- Mime filter ---
-- void setMimeTypeFilter(int mimeTypeFilter);
--
--public:
--
-- /// --- Geolocation filter
-- enum GeolocationCondition
-- {
-- GeolocationNoFilter = 0,
-- GeolocationNoCoordinates = 1 << 1,
-- GeolocationHasCoordinates = 1 << 2
-- };
--
-- void setGeolocationFilter(const GeolocationCondition& condition);
--
--public:
--
-- /// Returns if the day is a filter criteria
-- bool isFilteringByDay() const;
--
-- /// Returns if the type mime is a filter criteria
-- bool isFilteringByTypeMime() const;
--
-- /// Returns whether geolocation is a filter criteria
-- bool isFilteringByGeolocation() const;
--
-- /// Returns if the rating is a filter criteria
-- bool isFilteringByRating() const;
--
-- /// Returns if the pick labels is a filter criteria
-- bool isFilteringByPickLabels() const;
--
-- /// Returns if the color labels is a filter criteria
-- bool isFilteringByColorLabels() const;
--
-- /// Returns if the tag is a filter criteria
-- bool isFilteringByTags() const;
--
-- /// Returns if the text (including comment) is a filter criteria
-- bool isFilteringByText() const;
--
-- /// Returns if images will be filtered by these criteria at all
-- bool isFiltering() const;
--
--public:
--
-- /// --- URL whitelist filter
-- void setUrlWhitelist(const QList<QUrl>& urlList, const QString& id);
--
--public:
--
-- /// --- ID whitelist filter
-- void setIdWhitelist(const QList<qlonglong>& idList, const QString& id);
--
--public:
--
-- /// --- Change notification ---
--
-- /** Returns database fields a change in which would affect the current filtering.
-- * To find out if an image tag change affects filtering, test isFilteringByTags().
-- * The text filter will also be affected by changes in tags and album names.
-- */
-- DatabaseFields::Set watchFlags() const;
--
--private:
--
-- /**
-- * @brief Returns whether some internal filtering (whitelist by id or URL) or normal filtering is going on
-- */
-- bool isFilteringInternally() const;
--
--private:
--
-- /// --- Tags filter ---
-- bool m_untaggedFilter;
-- QList<int> m_includeTagFilter;
-- QList<int> m_excludeTagFilter;
-- MatchingCondition m_matchingCond;
-- QList<int> m_colorLabelTagFilter;
-- QList<int> m_pickLabelTagFilter;
--
-- /// --- Rating filter ---
-- int m_ratingFilter;
-- RatingCondition m_ratingCond;
-- bool m_isUnratedExcluded;
--
-- /// --- Date filter ---
-- QMap<QDateTime, bool> m_dayFilter;
--
-- /// --- Text filter ---
-- SearchTextFilterSettings m_textFilterSettings;
--
-- /// Helpers for text search: Set these if you want to search album or tag names with text search
-- QHash<int, QString> m_tagNameHash;
-- QHash<int, QString> m_albumNameHash;
--
-- /// --- Mime filter ---
-- MimeFilter::TypeMimeFilter m_mimeTypeFilter;
--
-- /// --- Geolocation filter
-- GeolocationCondition m_geolocationCondition;
--
-- /// --- URL whitelist filter
-- QHash<QString,QList<QUrl>> m_urlWhitelists;
--
-- /// --- ID whitelist filter
-- QHash<QString,QList<qlonglong> > m_idWhitelists;
--};
--
--// ---------------------------------------------------------------------------------------
--
--class DIGIKAM_DATABASE_EXPORT VersionImageFilterSettings
--{
--public:
--
-- VersionImageFilterSettings();
-- explicit VersionImageFilterSettings(const VersionManagerSettings& settings);
--
-- bool operator==(const VersionImageFilterSettings& other) const;
--
-- /**
-- * Returns true if the given ImageInfo matches the filter criteria.
-- */
-- bool matches(const ImageInfo& info) const;
--
-- bool isHiddenBySettings(const ImageInfo& info) const;
-- bool isExemptedBySettings(const ImageInfo& info) const;
--
-- /// --- Tags filter ---
--
-- void setVersionManagerSettings(const VersionManagerSettings& settings);
--
-- /**
-- * Add list with exceptions: These images will be exempted from filtering by this filter
-- */
-- void setExceptionList(const QList<qlonglong>& idlist, const QString& id);
--
-- /// Returns if images will be filtered by these criteria at all
-- bool isFiltering() const;
--
-- /// Returns if the tag is a filter criteria
-- bool isFilteringByTags() const;
--
-- /// DatabaseFields::Set watchFlags() const: Would return 0
--
--protected:
--
-- QList<int> m_excludeTagFilter;
-- int m_includeTagFilter;
-- int m_exceptionTagFilter;
-- QHash<QString,QList<qlonglong> > m_exceptionLists;
--};
--
--// ---------------------------------------------------------------------------------------
--
--class DIGIKAM_DATABASE_EXPORT GroupImageFilterSettings
--{
--public:
--
-- GroupImageFilterSettings();
--
-- bool operator==(const GroupImageFilterSettings& other) const;
--
-- /**
-- * Returns true if the given ImageInfo matches the filter criteria.
-- */
-- bool matches(const ImageInfo& info) const;
--
-- /**
-- * Open or close a group.
-- */
-- void setOpen(qlonglong group, bool open);
-- bool isOpen(qlonglong group) const;
--
-- /**
-- * Open all groups
-- */
-- void setAllOpen(bool open);
-- bool isAllOpen() const;
--
-- /// Returns if images will be filtered by these criteria at all
-- bool isFiltering() const;
--
-- DatabaseFields::Set watchFlags() const;
--
--protected:
--
-- bool m_allOpen;
-- QSet<qlonglong> m_openGroups;
--};
--
--} // namespace Digikam
--
--Q_DECLARE_METATYPE(Digikam::ImageFilterSettings::GeolocationCondition)
--
--#endif // IMAGEFILTERSETTINGS_H
-diff --git a/libs/models/imagelistmodel.cpp b/libs/models/imagelistmodel.cpp
-deleted file mode 100644
-index fafce34..0000000
---- a/libs/models/imagelistmodel.cpp
-+++ /dev/null
-@@ -1,70 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2010-12-06
-- * Description : An image model based on a static list
-- *
-- * Copyright (C) 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- *
-- * 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 "imagelistmodel.h"
--
--// Local includes
--
--#include "digikam_debug.h"
--#include "coredbaccess.h"
--#include "coredbchangesets.h"
--#include "coredbwatch.h"
--#include "imageinfo.h"
--#include "imageinfolist.h"
--
--namespace Digikam
--{
--
--ImageListModel::ImageListModel(QObject* parent)
-- : ImageThumbnailModel(parent)
--{
-- connect(CoreDbAccess::databaseWatch(), SIGNAL(collectionImageChange(CollectionImageChangeset)),
-- this, SLOT(slotCollectionImageChange(CollectionImageChangeset)));
--}
--
--ImageListModel::~ImageListModel()
--{
--}
--
--void ImageListModel::slotCollectionImageChange(const CollectionImageChangeset& changeset)
--{
-- if (isEmpty())
-- {
-- return;
-- }
--
-- switch (changeset.operation())
-- {
-- case CollectionImageChangeset::Added:
-- break;
-- case CollectionImageChangeset::Removed:
-- case CollectionImageChangeset::RemovedAll:
-- removeImageInfos(ImageInfoList(changeset.ids()));
-- break;
--
-- default:
-- break;
-- }
--}
--
--} // namespace Digikam
-diff --git a/libs/models/imagelistmodel.h b/libs/models/imagelistmodel.h
-deleted file mode 100644
-index a225b1b..0000000
---- a/libs/models/imagelistmodel.h
-+++ /dev/null
-@@ -1,63 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2010-12-06
-- * Description : An image model based on a static list
-- *
-- * Copyright (C) 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- *
-- * 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 IMAGELISTMODEL_H
--#define IMAGELISTMODEL_H
--
--// Local includes
--
--#include "imagethumbnailmodel.h"
--#include "digikam_export.h"
--
--namespace Digikam
--{
--
--class ImageChangeset;
--class CollectionImageChangeset;
--
--class DIGIKAM_DATABASE_EXPORT ImageListModel : public ImageThumbnailModel
--{
-- Q_OBJECT
--
--public:
--
-- explicit ImageListModel(QObject* parent = 0);
-- ~ImageListModel();
--
-- // NOTE: necessary methods to add and remove ImageInfos to the model are inherited from ImageModel
--
--Q_SIGNALS:
--
-- /**
-- * Emitted when images are removed from the model because they are removed in the database
-- */
-- void imageInfosRemoved(const QList<ImageInfo>& infos);
--
--protected Q_SLOTS:
--
-- void slotCollectionImageChange(const CollectionImageChangeset& changeset);
--};
--
--} // namespace Digikam
--
--#endif // IMAGELISTMODEL_H
-diff --git a/libs/models/imagemodel.cpp b/libs/models/imagemodel.cpp
-deleted file mode 100644
-index 41b43cf..0000000
---- a/libs/models/imagemodel.cpp
-+++ /dev/null
-@@ -1,1368 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Qt item model for database entries
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- *
-- * 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 "imagemodel.h"
--
--// Qt includes
--
--#include <QHash>
--#include <QItemSelection>
--
--// Local includes
--
--#include "digikam_debug.h"
--#include "coredbchangesets.h"
--#include "coredbfields.h"
--#include "coredbwatch.h"
--#include "imageinfo.h"
--#include "imageinfolist.h"
--#include "abstractitemdragdrophandler.h"
--
--namespace Digikam
--{
--
--class ImageModel::Private
--{
--public:
--
-- Private()
-- {
-- preprocessor = 0;
-- keepFilePathCache = false;
-- sendRemovalSignals = false;
-- incrementalUpdater = 0;
-- refreshing = false;
-- reAdding = false;
-- incrementalRefreshRequested = false;
-- }
--
-- ImageInfoList infos;
-- QList<QVariant> extraValues;
-- QHash<qlonglong, int> idHash;
--
-- bool keepFilePathCache;
-- QHash<QString, qlonglong> filePathHash;
--
-- bool sendRemovalSignals;
--
-- QObject* preprocessor;
-- bool refreshing;
-- bool reAdding;
-- bool incrementalRefreshRequested;
--
-- DatabaseFields::Set watchFlags;
--
-- class ImageModelIncrementalUpdater* incrementalUpdater;
--
-- ImageInfoList pendingInfos;
-- QList<QVariant> pendingExtraValues;
--
-- inline bool isValid(const QModelIndex& index)
-- {
-- if (!index.isValid())
-- {
-- return false;
-- }
--
-- if (index.row() < 0 || index.row() >= infos.size())
-- {
-- qCDebug(DIGIKAM_GENERAL_LOG) << "Invalid index" << index;
-- return false;
-- }
--
-- return true;
-- }
-- inline bool extraValueValid(const QModelIndex& index)
-- {
-- // we assume isValid() being called before, no duplicate checks
-- if (index.row() >= extraValues.size())
-- {
-- qCDebug(DIGIKAM_GENERAL_LOG) << "Invalid index for extraData" << index;
-- return false;
-- }
--
-- return true;
-- }
--};
--
--typedef QPair<int, int> IntPair; // to make foreach macro happy
--typedef QList<IntPair> IntPairList;
--
--class ImageModelIncrementalUpdater
--{
--public:
--
-- explicit ImageModelIncrementalUpdater(ImageModel::Private* d);
--
-- void appendInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-- void aboutToBeRemovedInModel(const IntPairList& aboutToBeRemoved);
-- QList<IntPair> oldIndexes();
--
-- static QList<IntPair> toContiguousPairs(const QList<int>& ids);
--
--public:
--
-- QHash<qlonglong, int> oldIds;
-- QList<QVariant> oldExtraValues;
-- QList<ImageInfo> newInfos;
-- QList<QVariant> newExtraValues;
-- QList<IntPairList> modelRemovals;
--};
--
--ImageModel::ImageModel(QObject* parent)
-- : QAbstractListModel(parent),
-- d(new Private)
--{
-- connect(CoreDbAccess::databaseWatch(), SIGNAL(imageChange(ImageChangeset)),
-- this, SLOT(slotImageChange(ImageChangeset)));
--
-- connect(CoreDbAccess::databaseWatch(), SIGNAL(imageTagChange(ImageTagChangeset)),
-- this, SLOT(slotImageTagChange(ImageTagChangeset)));
--}
--
--ImageModel::~ImageModel()
--{
-- delete d->incrementalUpdater;
-- delete d;
--}
--
--// ------------ Access methods -------------
--
--void ImageModel::setKeepsFilePathCache(bool keepCache)
--{
-- d->keepFilePathCache = keepCache;
--}
--
--bool ImageModel::keepsFilePathCache() const
--{
-- return d->keepFilePathCache;
--}
--
--bool ImageModel::isEmpty() const
--{
-- return d->infos.isEmpty();
--}
--
--void ImageModel::setWatchFlags(const DatabaseFields::Set& set)
--{
-- d->watchFlags = set;
--}
--
--ImageInfo ImageModel::imageInfo(const QModelIndex& index) const
--{
-- if (!d->isValid(index))
-- {
-- return ImageInfo();
-- }
--
-- return d->infos.at(index.row());
--}
--
--ImageInfo& ImageModel::imageInfoRef(const QModelIndex& index) const
--{
-- return d->infos[index.row()];
--}
--
--qlonglong ImageModel::imageId(const QModelIndex& index) const
--{
-- if (!d->isValid(index))
-- {
-- return 0;
-- }
--
-- return d->infos.at(index.row()).id();
--}
--
--QList<ImageInfo> ImageModel::imageInfos(const QList<QModelIndex>& indexes) const
--{
-- QList<ImageInfo> infos;
--
-- foreach(const QModelIndex& index, indexes)
-- {
-- infos << imageInfo(index);
-- }
--
-- return infos;
--}
--
--QList<qlonglong> ImageModel::imageIds(const QList<QModelIndex>& indexes) const
--{
-- QList<qlonglong> ids;
--
-- foreach(const QModelIndex& index, indexes)
-- {
-- ids << imageId(index);
-- }
--
-- return ids;
--}
--
--ImageInfo ImageModel::imageInfo(int row) const
--{
-- if (row >= d->infos.size())
-- {
-- return ImageInfo();
-- }
--
-- return d->infos.at(row);
--}
--
--ImageInfo& ImageModel::imageInfoRef(int row) const
--{
-- return d->infos[row];
--}
--
--qlonglong ImageModel::imageId(int row) const
--{
-- if (row < 0 || row >= d->infos.size())
-- {
-- return -1;
-- }
--
-- return d->infos.at(row).id();
--}
--
--QModelIndex ImageModel::indexForImageInfo(const ImageInfo& info) const
--{
-- return indexForImageId(info.id());
--}
--
--QModelIndex ImageModel::indexForImageInfo(const ImageInfo& info, const QVariant& extraValue) const
--{
-- return indexForImageId(info.id(), extraValue);
--}
--
--QList<QModelIndex> ImageModel::indexesForImageInfo(const ImageInfo& info) const
--{
-- return indexesForImageId(info.id());
--}
--
--QModelIndex ImageModel::indexForImageId(qlonglong id) const
--{
-- int index = d->idHash.value(id, -1);
--
-- if (index != -1)
-- {
-- return createIndex(index, 0);
-- }
--
-- return QModelIndex();
--}
--
--QModelIndex ImageModel::indexForImageId(qlonglong id, const QVariant& extraValue) const
--{
-- if (d->extraValues.isEmpty())
-- return indexForImageId(id);
--
-- QHash<qlonglong, int>::const_iterator it;
--
-- for (it = d->idHash.constFind(id); it != d->idHash.constEnd() && it.key() == id; ++it)
-- {
-- if (d->extraValues.at(it.value()) == extraValue)
-- return createIndex(it.value(), 0);
-- }
--
-- return QModelIndex();
--}
--
--QList<QModelIndex> ImageModel::indexesForImageId(qlonglong id) const
--{
-- QList<QModelIndex> indexes;
-- QHash<qlonglong, int>::const_iterator it;
--
-- for (it = d->idHash.constFind(id); it != d->idHash.constEnd() && it.key() == id; ++it)
-- {
-- indexes << createIndex(it.value(), 0);
-- }
--
-- return indexes;
--}
--
--int ImageModel::numberOfIndexesForImageInfo(const ImageInfo& info) const
--{
-- return numberOfIndexesForImageId(info.id());
--}
--
--int ImageModel::numberOfIndexesForImageId(qlonglong id) const
--{
-- if (d->extraValues.isEmpty())
-- {
-- return 0;
-- }
--
-- int count = 0;
-- QHash<qlonglong,int>::const_iterator it;
--
-- for (it = d->idHash.constFind(id); it != d->idHash.constEnd() && it.key() == id; ++it)
-- {
-- ++count;
-- }
--
-- return count;
--}
--
--// static method
--ImageInfo ImageModel::retrieveImageInfo(const QModelIndex& index)
--{
-- if (!index.isValid())
-- {
-- return ImageInfo();
-- }
--
-- ImageModel* const model = index.data(ImageModelPointerRole).value<ImageModel*>();
-- int row = index.data(ImageModelInternalId).toInt();
--
-- if (!model)
-- {
-- return ImageInfo();
-- }
--
-- return model->imageInfo(row);
--}
--
--// static method
--qlonglong ImageModel::retrieveImageId(const QModelIndex& index)
--{
-- if (!index.isValid())
-- {
-- return 0;
-- }
--
-- ImageModel* const model = index.data(ImageModelPointerRole).value<ImageModel*>();
-- int row = index.data(ImageModelInternalId).toInt();
--
-- if (!model)
-- {
-- return 0;
-- }
--
-- return model->imageId(row);
--}
--
--QModelIndex ImageModel::indexForPath(const QString& filePath) const
--{
-- if (d->keepFilePathCache)
-- {
-- return indexForImageId(d->filePathHash.value(filePath));
-- }
-- else
-- {
-- const int size = d->infos.size();
--
-- for (int i=0; i<size; ++i)
-- {
-- if (d->infos.at(i).filePath() == filePath)
-- {
-- return createIndex(i, 0);
-- }
-- }
-- }
--
-- return QModelIndex();
--}
--
--QList<QModelIndex> ImageModel::indexesForPath(const QString& filePath) const
--{
-- if (d->keepFilePathCache)
-- {
-- return indexesForImageId(d->filePathHash.value(filePath));
-- }
-- else
-- {
-- QList<QModelIndex> indexes;
-- const int size = d->infos.size();
--
-- for (int i=0; i<size; ++i)
-- {
-- if (d->infos.at(i).filePath() == filePath)
-- {
-- indexes << createIndex(i, 0);
-- }
-- }
--
-- return indexes;
-- }
--}
--
--ImageInfo ImageModel::imageInfo(const QString& filePath) const
--{
-- if (d->keepFilePathCache)
-- {
-- qlonglong id = d->filePathHash.value(filePath);
--
-- if (id)
-- {
-- int index = d->idHash.value(id, -1);
--
-- if (index != -1)
-- {
-- return d->infos.at(index);
-- }
-- }
-- }
-- else
-- {
-- foreach(const ImageInfo& info, d->infos)
-- {
-- if (info.filePath() == filePath)
-- {
-- return info;
-- }
-- }
-- }
--
-- return ImageInfo();
--}
--
--QList<ImageInfo> ImageModel::imageInfos(const QString& filePath) const
--{
-- QList<ImageInfo> infos;
--
-- if (d->keepFilePathCache)
-- {
-- qlonglong id = d->filePathHash.value(filePath);
--
-- if (id)
-- {
-- foreach(int index, d->idHash.values(id))
-- {
-- infos << d->infos.at(index);
-- }
-- }
-- }
-- else
-- {
-- foreach(const ImageInfo& info, d->infos)
-- {
-- if (info.filePath() == filePath)
-- {
-- infos << info;
-- }
-- }
-- }
--
-- return infos;
--}
--
--void ImageModel::addImageInfo(const ImageInfo& info)
--{
-- addImageInfos(QList<ImageInfo>() << info, QList<QVariant>());
--}
--
--void ImageModel::addImageInfos(const QList<ImageInfo>& infos)
--{
-- addImageInfos(infos, QList<QVariant>());
--}
--
--void ImageModel::addImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- if (infos.isEmpty())
-- {
-- return;
-- }
--
-- if (d->incrementalUpdater)
-- {
-- d->incrementalUpdater->appendInfos(infos, extraValues);
-- }
-- else
-- {
-- appendInfos(infos, extraValues);
-- }
--}
--
--void ImageModel::addImageInfoSynchronously(const ImageInfo& info)
--{
-- addImageInfosSynchronously(QList<ImageInfo>() << info, QList<QVariant>());
--}
--
--void ImageModel::addImageInfosSynchronously(const QList<ImageInfo>& infos)
--{
-- addImageInfos(infos, QList<QVariant>());
--}
--
--void ImageModel::addImageInfosSynchronously(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- if (infos.isEmpty())
-- {
-- return;
-- }
--
-- publiciseInfos(infos, extraValues);
-- emit processAdded(infos, extraValues);
--}
--
--void ImageModel::ensureHasImageInfo(const ImageInfo& info)
--{
-- ensureHasImageInfos(QList<ImageInfo>() << info, QList<QVariant>());
--}
--
--void ImageModel::ensureHasImageInfos(const QList<ImageInfo>& infos)
--{
-- ensureHasImageInfos(infos, QList<QVariant>());
--}
--
--void ImageModel::ensureHasImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- if (extraValues.isEmpty())
-- {
-- if (!d->pendingExtraValues.isEmpty())
-- {
-- qCDebug(DIGIKAM_GENERAL_LOG) << "ExtraValue / No Extra Value mismatch. Ignoring added infos.";
-- return;
-- }
-- }
-- else
-- {
-- if (d->pendingInfos.size() != d->pendingExtraValues.size())
-- {
-- qCDebug(DIGIKAM_GENERAL_LOG) << "ExtraValue / No Extra Value mismatch. Ignoring added infos.";
-- return;
-- }
-- }
--
-- d->pendingInfos << infos;
-- d->pendingExtraValues << extraValues;
-- cleanSituationChecks();
--}
--
--void ImageModel::clearImageInfos()
--{
-- d->infos.clear();
-- d->extraValues.clear();
-- d->idHash.clear();
-- d->filePathHash.clear();
-- delete d->incrementalUpdater;
-- d->incrementalUpdater = 0;
-- d->pendingInfos.clear();
-- d->pendingExtraValues.clear();
-- d->refreshing = false;
-- d->reAdding = false;
-- d->incrementalRefreshRequested = false;
--
-- beginResetModel();
-- endResetModel();
--
-- imageInfosCleared();
--}
--
--void ImageModel::setImageInfos(const QList<ImageInfo>& infos)
--{
-- clearImageInfos();
-- addImageInfos(infos);
--}
--
--QList<ImageInfo> ImageModel::imageInfos() const
--{
-- return d->infos;
--}
--
--QList<qlonglong> ImageModel::imageIds() const
--{
-- return d->idHash.keys();
--}
--
--bool ImageModel::hasImage(qlonglong id) const
--{
-- return d->idHash.contains(id);
--}
--
--bool ImageModel::hasImage(const ImageInfo& info) const
--{
-- return d->idHash.contains(info.id());
--}
--
--bool ImageModel::hasImage(const ImageInfo& info, const QVariant& extraValue) const
--{
-- return hasImage(info.id(), extraValue);
--}
--
--bool ImageModel::hasImage(qlonglong id, const QVariant& extraValue) const
--{
-- if (d->extraValues.isEmpty())
-- return hasImage(id);
--
-- QHash<qlonglong, int>::const_iterator it;
--
-- for (it = d->idHash.constFind(id); it != d->idHash.constEnd() && it.key() == id; ++it)
-- {
-- if (d->extraValues.at(it.value()) == extraValue)
-- return true;
-- }
--
-- return false;;
--}
--
--QList<ImageInfo> ImageModel::uniqueImageInfos() const
--{
-- if (d->extraValues.isEmpty())
-- {
-- return d->infos;
-- }
--
-- QList<ImageInfo> uniqueInfos;
-- const int size = d->infos.size();
--
-- for (int i=0; i<size; ++i)
-- {
-- const ImageInfo& info = d->infos.at(i);
--
-- if (d->idHash.value(info.id()) == i)
-- {
-- uniqueInfos << info;
-- }
-- }
--
-- return uniqueInfos;
--}
--
--void ImageModel::emitDataChangedForAll()
--{
-- if (d->infos.isEmpty())
-- {
-- return;
-- }
--
-- QModelIndex first = createIndex(0, 0);
-- QModelIndex last = createIndex(d->infos.size() - 1, 0);
-- emit dataChanged(first, last);
--}
--
--void ImageModel::emitDataChangedForSelection(const QItemSelection& selection)
--{
-- if (!selection.isEmpty())
-- {
-- foreach(const QItemSelectionRange& range, selection)
-- {
-- emit dataChanged(range.topLeft(), range.bottomRight());
-- }
-- }
--}
--
--void ImageModel::ensureHasGroupedImages(const ImageInfo& groupLeader)
--{
-- ensureHasImageInfos(groupLeader.groupedImages());
--}
--
--// ------------ Preprocessing -------------
--
--void ImageModel::setPreprocessor(QObject* preprocessor)
--{
-- unsetPreprocessor(d->preprocessor);
-- d->preprocessor = preprocessor;
--}
--
--void ImageModel::unsetPreprocessor(QObject* preprocessor)
--{
-- if (preprocessor && d->preprocessor == preprocessor)
-- {
-- disconnect(this, SIGNAL(preprocess(QList<ImageInfo>,QList<QVariant>)), 0, 0);
-- disconnect(d->preprocessor, 0, this, SLOT(reAddImageInfos(QList<ImageInfo>,QList<QVariant>)));
-- disconnect(d->preprocessor, 0, this, SLOT(reAddingFinished()));
-- }
--}
--
--void ImageModel::appendInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- if (infos.isEmpty())
-- {
-- return;
-- }
--
-- if (d->preprocessor)
-- {
-- d->reAdding = true;
-- emit preprocess(infos, extraValues);
-- }
-- else
-- {
-- publiciseInfos(infos, extraValues);
-- }
--}
--
--void ImageModel::appendInfosChecked(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- // This method does deduplication. It is private because in context of readding or refreshing it is of no use.
--
-- if (extraValues.isEmpty())
-- {
-- QList<ImageInfo> checkedInfos;
--
-- foreach (const ImageInfo& info, infos)
-- {
-- if (!hasImage(info))
-- {
-- checkedInfos << info;
-- }
-- }
--
-- appendInfos(checkedInfos, QList<QVariant>());
-- }
-- else
-- {
-- QList<ImageInfo> checkedInfos;
-- QList<QVariant> checkedExtraValues;
-- const int size = infos.size();
--
-- for (int i=0; i<size; i++)
-- {
-- if (!hasImage(infos[i], extraValues[i]))
-- {
-- checkedInfos << infos[i];
-- checkedExtraValues << extraValues[i];
-- }
-- }
--
-- appendInfos(checkedInfos, checkedExtraValues);
-- }
--}
--
--void ImageModel::reAddImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- // addImageInfos -> appendInfos -> preprocessor -> reAddImageInfos
-- publiciseInfos(infos, extraValues);
--}
--
--void ImageModel::reAddingFinished()
--{
-- d->reAdding = false;
-- cleanSituationChecks();
--}
--
--void ImageModel::startRefresh()
--{
-- d->refreshing = true;
--}
--
--void ImageModel::finishRefresh()
--{
-- d->refreshing = false;
-- cleanSituationChecks();
--}
--
--bool ImageModel::isRefreshing() const
--{
-- return d->refreshing;
--}
--
--void ImageModel::cleanSituationChecks()
--{
-- // For starting an incremental refresh we want a clear situation:
-- // Any remaining batches from non-incremental refreshing subclasses have been received in appendInfos(),
-- // any batches sent to preprocessor for re-adding have been re-added.
-- if (d->refreshing || d->reAdding)
-- {
-- return;
-- }
--
-- if (!d->pendingInfos.isEmpty())
-- {
-- appendInfosChecked(d->pendingInfos, d->pendingExtraValues);
-- d->pendingInfos.clear();
-- d->pendingExtraValues.clear();
-- cleanSituationChecks();
-- return;
-- }
--
-- if (d->incrementalRefreshRequested)
-- {
-- d->incrementalRefreshRequested = false;
-- emit readyForIncrementalRefresh();
-- }
-- else
-- {
-- emit allRefreshingFinished();
-- }
--}
--
--void ImageModel::publiciseInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- if (infos.isEmpty())
-- {
-- return;
-- }
--
-- Q_ASSERT(infos.size() == extraValues.size() || (extraValues.isEmpty() && d->extraValues.isEmpty()));
--
-- emit imageInfosAboutToBeAdded(infos);
-- const int firstNewIndex = d->infos.size();
-- const int lastNewIndex = d->infos.size() + infos.size() - 1;
-- beginInsertRows(QModelIndex(), firstNewIndex, lastNewIndex);
-- d->infos << infos;
-- d->extraValues << extraValues;
--
-- for (int i=firstNewIndex; i<=lastNewIndex; ++i)
-- {
-- const ImageInfo& info = d->infos.at(i);
-- qlonglong id = info.id();
-- d->idHash.insertMulti(id, i);
--
-- if (d->keepFilePathCache)
-- {
-- d->filePathHash[info.filePath()] = id;
-- }
-- }
--
-- endInsertRows();
-- emit imageInfosAdded(infos);
--}
--
--void ImageModel::requestIncrementalRefresh()
--{
-- if (d->reAdding)
-- {
-- d->incrementalRefreshRequested = true;
-- }
-- else
-- {
-- emit readyForIncrementalRefresh();
-- }
--}
--
--bool ImageModel::hasIncrementalRefreshPending() const
--{
-- return d->incrementalRefreshRequested;
--}
--
--void ImageModel::startIncrementalRefresh()
--{
-- delete d->incrementalUpdater;
--
-- d->incrementalUpdater = new ImageModelIncrementalUpdater(d);
--}
--
--void ImageModel::finishIncrementalRefresh()
--{
-- if (!d->incrementalUpdater)
-- {
-- return;
-- }
--
-- // remove old entries
-- QList<QPair<int, int> > pairs = d->incrementalUpdater->oldIndexes();
-- removeRowPairs(pairs);
--
-- // add new indexes
-- appendInfos(d->incrementalUpdater->newInfos, d->incrementalUpdater->newExtraValues);
--
-- delete d->incrementalUpdater;
-- d->incrementalUpdater = 0;
--}
--
--void ImageModel::removeIndex(const QModelIndex& index)
--{
-- removeIndexes(QList<QModelIndex>() << index);
--}
--
--void ImageModel::removeIndexes(const QList<QModelIndex>& indexes)
--{
-- QList<int> listIndexes;
--
-- foreach(const QModelIndex& index, indexes)
-- {
-- if (d->isValid(index))
-- {
-- listIndexes << index.row();
-- }
-- }
--
-- if (listIndexes.isEmpty())
-- {
-- return;
-- }
--
-- removeRowPairsWithCheck(ImageModelIncrementalUpdater::toContiguousPairs(listIndexes));
--}
--
--void ImageModel::removeImageInfo(const ImageInfo& info)
--{
-- removeImageInfos(QList<ImageInfo>() << info);
--}
--
--void ImageModel::removeImageInfos(const QList<ImageInfo>& infos)
--{
-- QList<int> listIndexes;
--
-- foreach(const ImageInfo& info, infos)
-- {
-- QModelIndex index = indexForImageId(info.id());
--
-- if (index.isValid())
-- {
-- listIndexes << index.row();
-- }
-- }
-- removeRowPairsWithCheck(ImageModelIncrementalUpdater::toContiguousPairs(listIndexes));
--}
--
--void ImageModel::removeImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- if (extraValues.isEmpty())
-- {
-- removeImageInfos(infos);
-- return;
-- }
--
-- QList<int> listIndexes;
--
-- for (int i=0; i<infos.size(); ++i)
-- {
-- QModelIndex index = indexForImageId(infos.at(i).id(), extraValues.at(i));
--
-- if (index.isValid())
-- {
-- listIndexes << index.row();
-- }
-- }
--
-- removeRowPairsWithCheck(ImageModelIncrementalUpdater::toContiguousPairs(listIndexes));
--}
--
--void ImageModel::setSendRemovalSignals(bool send)
--{
-- d->sendRemovalSignals = send;
--}
--
--template <class List, typename T>
--static bool pairsContain(const List& list, T value)
--{
-- typename List::const_iterator middle;
-- typename List::const_iterator begin = list.begin();
-- typename List::const_iterator end = list.end();
-- int n = int(end - begin);
-- int half;
--
-- while (n > 0)
-- {
-- half = n >> 1;
-- middle = begin + half;
--
-- if (middle->first <= value && middle->second >= value)
-- {
-- return true;
-- }
-- else if (middle->second < value)
-- {
-- begin = middle + 1;
-- n -= half + 1;
-- }
-- else
-- {
-- n = half;
-- }
-- }
--
-- return false;
--}
--
--void ImageModel::removeRowPairsWithCheck(const QList<QPair<int, int> >& toRemove)
--{
-- if (d->incrementalUpdater)
-- {
-- d->incrementalUpdater->aboutToBeRemovedInModel(toRemove);
-- }
--
-- removeRowPairs(toRemove);
--}
--
--void ImageModel::removeRowPairs(const QList<QPair<int, int> >& toRemove)
--{
-- if (toRemove.isEmpty())
-- {
-- return;
-- }
--
-- // Remove old indexes
-- // Keep in mind that when calling beginRemoveRows all structures announced to be removed
-- // must still be valid, and this includes our hashes as well, which limits what we can optimize
--
-- int removedRows = 0, offset = 0;
-- typedef QPair<int, int> IntPair; // to make foreach macro happy
--
-- foreach(const IntPair& pair, toRemove)
-- {
-- const int begin = pair.first - offset;
-- const int end = pair.second - offset; // inclusive
-- removedRows = end - begin + 1;
--
-- // when removing from the list, all subsequent indexes are affected
-- offset += removedRows;
--
-- QList<ImageInfo> removedInfos;
--
-- if (d->sendRemovalSignals)
-- {
-- qCopy(d->infos.begin() + begin, d->infos.begin() + end, removedInfos.begin());
-- emit imageInfosAboutToBeRemoved(removedInfos);
-- }
--
-- imageInfosAboutToBeRemoved(begin, end);
-- beginRemoveRows(QModelIndex(), begin, end);
--
-- // update idHash - which points to indexes of d->infos, and these change now!
-- QHash<qlonglong, int>::iterator it;
--
-- for (it = d->idHash.begin(); it != d->idHash.end(); )
-- {
-- if (it.value() >= begin)
-- {
-- if (it.value() > end)
-- {
-- // after the removed interval: adjust index
-- it.value() -= removedRows;
-- }
-- else
-- {
-- // in the removed interval
-- it = d->idHash.erase(it);
-- continue;
-- }
-- }
--
-- ++it;
-- }
--
-- // remove from list
-- d->infos.erase(d->infos.begin() + begin, d->infos.begin() + (end + 1));
--
-- if (!d->extraValues.isEmpty())
-- {
-- d->extraValues.erase(d->extraValues.begin() + begin, d->extraValues.begin() + (end + 1));
-- }
--
-- endRemoveRows();
--
-- if (d->sendRemovalSignals)
-- {
-- emit imageInfosRemoved(removedInfos);
-- }
-- }
--
-- // tidy up: remove old indexes from file path hash now
-- if (d->keepFilePathCache)
-- {
-- QHash<QString, qlonglong>::iterator it;
--
-- for (it = d->filePathHash.begin(); it != d->filePathHash.end(); )
-- {
-- if (pairsContain(toRemove, it.value()))
-- {
-- it = d->filePathHash.erase(it);
-- }
-- else
-- {
-- ++it;
-- }
-- }
-- }
--}
--
--ImageModelIncrementalUpdater::ImageModelIncrementalUpdater(ImageModel::Private* d)
--{
-- oldIds = d->idHash;
-- oldExtraValues = d->extraValues;
--}
--
--void ImageModelIncrementalUpdater::appendInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues)
--{
-- if (extraValues.isEmpty())
-- {
-- foreach(const ImageInfo& info, infos)
-- {
-- QHash<qlonglong,int>::iterator it = oldIds.find(info.id());
--
-- if (it != oldIds.end())
-- {
-- oldIds.erase(it);
-- }
-- else
-- {
-- newInfos << info;
-- }
-- }
-- }
-- else
-- {
-- for (int i=0; i<infos.size(); ++i)
-- {
-- const ImageInfo& info = infos.at(i);
-- bool found = false;
-- QHash<qlonglong,int>::iterator it;
--
-- for (it = oldIds.find(info.id()); it != oldIds.end() && it.key() == info.id(); ++it)
-- {
-- // first check is for bug #262596. Not sure if needed.
-- if (it.value() < oldExtraValues.size() && extraValues.at(i) == oldExtraValues.at(it.value()))
-- {
-- found = true;
-- break;
-- }
-- }
--
-- if (found)
-- {
-- oldIds.erase(it);
-- // do not erase from oldExtraValues - oldIds is a hash id -> index.
-- }
-- else
-- {
-- newInfos << info;
-- newExtraValues << extraValues.at(i);
-- }
-- }
-- }
--}
--
--void ImageModelIncrementalUpdater::aboutToBeRemovedInModel(const IntPairList& toRemove)
--{
-- modelRemovals << toRemove;
--}
--
--QList<QPair<int, int> > ImageModelIncrementalUpdater::oldIndexes()
--{
-- // first, apply all changes to indexes by direct removal in model
-- // while the updater was active
-- foreach(const IntPairList& list, modelRemovals)
-- {
-- int removedRows = 0, offset = 0;
--
-- foreach(const IntPair& pair, list)
-- {
-- const int begin = pair.first - offset;
-- const int end = pair.second - offset; // inclusive
-- removedRows = end - begin + 1;
--
-- // when removing from the list, all subsequent indexes are affected
-- offset += removedRows;
--
-- // update idHash - which points to indexes of d->infos, and these change now!
-- QHash<qlonglong, int>::iterator it;
--
-- for (it = oldIds.begin(); it != oldIds.end(); )
-- {
-- if (it.value() >= begin)
-- {
-- if (it.value() > end)
-- {
-- // after the removed interval: adjust index
-- it.value() -= removedRows;
-- }
-- else
-- {
-- // in the removed interval
-- it = oldIds.erase(it);
-- continue;
-- }
-- }
--
-- ++it;
-- }
-- }
-- }
--
-- modelRemovals.clear();
--
-- return toContiguousPairs(oldIds.values());
--}
--
--QList<QPair<int, int> > ImageModelIncrementalUpdater::toContiguousPairs(const QList<int>& unsorted)
--{
-- // Take the given indices and return them as contiguous pairs [begin, end]
--
-- QList<QPair<int, int> > pairs;
--
-- if (unsorted.isEmpty())
-- {
-- return pairs;
-- }
--
-- QList<int> indices(unsorted);
-- qSort(indices);
--
-- QPair<int, int> pair(indices.first(), indices.first());
--
-- for (int i=1; i<indices.size(); ++i)
-- {
-- const int &index = indices.at(i);
--
-- if (index == pair.second + 1)
-- {
-- pair.second = index;
-- continue;
-- }
--
-- pairs << pair; // insert last pair
-- pair.first = index;
-- pair.second = index;
-- }
--
-- pairs << pair;
--
-- return pairs;
--}
--
--// ------------ QAbstractItemModel implementation -------------
--
--QVariant ImageModel::data(const QModelIndex& index, int role) const
--{
-- if (!d->isValid(index))
-- {
-- return QVariant();
-- }
--
-- switch (role)
-- {
-- case Qt::DisplayRole:
-- case Qt::ToolTipRole:
-- return d->infos.at(index.row()).name();
--
-- case ImageModelPointerRole:
-- return QVariant::fromValue(const_cast<ImageModel*>(this));
--
-- case ImageModelInternalId:
-- return index.row();
--
-- case CreationDateRole:
-- return d->infos.at(index.row()).dateTime();
--
-- case ExtraDataRole:
--
-- if (d->extraValueValid(index))
-- {
-- return d->extraValues.at(index.row());
-- }
-- else
-- {
-- return QVariant();
-- }
--
-- case ExtraDataDuplicateCount:
-- {
-- qlonglong id = d->infos.at(index.row()).id();
-- return numberOfIndexesForImageId(id);
-- }
-- }
--
-- return QVariant();
--}
--
--QVariant ImageModel::headerData(int section, Qt::Orientation orientation, int role) const
--{
-- Q_UNUSED(section)
-- Q_UNUSED(orientation)
-- Q_UNUSED(role)
-- return QVariant();
--}
--
--int ImageModel::rowCount(const QModelIndex& parent) const
--{
-- if (parent.isValid())
-- {
-- return 0;
-- }
--
-- return d->infos.size();
--}
--
--Qt::ItemFlags ImageModel::flags(const QModelIndex& index) const
--{
-- if (!d->isValid(index))
-- {
-- return 0;
-- }
--
-- Qt::ItemFlags f = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
--
-- f |= dragDropFlags(index);
--
-- return f;
--}
--
--QModelIndex ImageModel::index(int row, int column, const QModelIndex& parent) const
--{
-- if (column != 0 || row < 0 || parent.isValid() || row >= d->infos.size())
-- {
-- return QModelIndex();
-- }
--
-- return createIndex(row, 0);
--}
--
--// ------------ Database watch -------------
--
--void ImageModel::slotImageChange(const ImageChangeset& changeset)
--{
-- if (d->infos.isEmpty())
-- {
-- return;
-- }
--
-- if (d->watchFlags & changeset.changes())
-- {
-- QItemSelection items;
--
-- foreach(const qlonglong& id, changeset.ids())
-- {
-- QModelIndex index = indexForImageId(id);
--
-- if (index.isValid())
-- {
-- items.select(index, index);
-- }
-- }
--
-- if (!items.isEmpty())
-- {
-- emitDataChangedForSelection(items);
-- emit imageChange(changeset, items);
-- }
-- }
--}
--
--void ImageModel::slotImageTagChange(const ImageTagChangeset& changeset)
--{
-- if (d->infos.isEmpty())
-- {
-- return;
-- }
--
-- QItemSelection items;
--
-- foreach(const qlonglong& id, changeset.ids())
-- {
-- QModelIndex index = indexForImageId(id);
--
-- if (index.isValid())
-- {
-- items.select(index, index);
-- }
-- }
--
-- if (!items.isEmpty())
-- {
-- emitDataChangedForSelection(items);
-- emit imageTagChange(changeset, items);
-- }
--}
--
--} // namespace Digikam
-diff --git a/libs/models/imagemodel.h b/libs/models/imagemodel.h
-deleted file mode 100644
-index dcf94c2..0000000
---- a/libs/models/imagemodel.h
-+++ /dev/null
-@@ -1,364 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Qt item model for database entries
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- *
-- * 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 IMAGEMODEL_H
--#define IMAGEMODEL_H
--
--// Qt includes
--
--#include <QAbstractListModel>
--
--// Local includes
--
--#include "dragdropimplementations.h"
--#include "imageinfo.h"
--#include "digikam_export.h"
--
--class QItemSelection;
--
--namespace Digikam
--{
--
--class ImageChangeset;
--class ImageTagChangeset;
--
--namespace DatabaseFields
--{
--class Set;
--}
--
--class DIGIKAM_DATABASE_EXPORT ImageModel : public QAbstractListModel, public DragDropModelImplementation
--{
-- Q_OBJECT
--
--public:
--
-- enum ImageModelRoles
-- {
-- /// An ImageModel* pointer to this model
-- ImageModelPointerRole = Qt::UserRole,
-- ImageModelInternalId = Qt::UserRole + 1,
-- /// Returns a thumbnail pixmap. May be implemented by subclasses.
-- /// Returns either a valid pixmap or a null QVariant.
-- ThumbnailRole = Qt::UserRole + 2,
-- /// Returns a QDateTime with the creation date
-- CreationDateRole = Qt::UserRole + 3,
-- /// Return (optional) extraData field
-- ExtraDataRole = Qt::UserRole + 5,
-- /// Returns the number of duplicate indexes for the same image id
-- ExtraDataDuplicateCount = Qt::UserRole + 6,
--
-- // Roles which are defined here but not implemented by ImageModel
-- /// Returns position of item in Left Light Table preview.
-- LTLeftPanelRole = Qt::UserRole + 50,
-- /// Returns position of item in Right Light Table preview.
-- LTRightPanelRole = Qt::UserRole + 51,
--
-- // For use by subclasses
-- SubclassRoles = Qt::UserRole + 100,
-- // For use by filter models
-- FilterModelRoles = Qt::UserRole + 500
-- };
--
--public:
--
-- explicit ImageModel(QObject* parent = 0);
-- ~ImageModel();
--
-- /** If a cache is kept, lookup by file path is fast,
-- * without a cache it is O(n). Default is false.
-- */
-- void setKeepsFilePathCache(bool keepCache);
-- bool keepsFilePathCache() const;
--
-- /** Set a set of database fields to watch.
-- * If either of these is changed, dataChanged() will be emitted.
-- * Default is no flag (no signal will be emitted).
-- */
-- void setWatchFlags(const DatabaseFields::Set& set);
--
-- /** Returns the ImageInfo object, reference or image id from the underlying data
-- * pointed to by the index.
-- * If the index is not valid, imageInfo will return a null ImageInfo, imageId will
-- * return 0, imageInfoRef must not be called with an invalid index.
-- */
-- ImageInfo imageInfo(const QModelIndex& index) const;
-- ImageInfo& imageInfoRef(const QModelIndex& index) const;
-- qlonglong imageId(const QModelIndex& index) const;
-- QList<ImageInfo> imageInfos(const QList<QModelIndex>& indexes) const;
-- QList<qlonglong> imageIds(const QList<QModelIndex>& indexes) const;
--
-- /** Returns the ImageInfo object, reference or image id from the underlying data
-- * of the given row (parent is the invalid QModelIndex, column is 0).
-- * Note that imageInfoRef will crash if index is invalid.
-- */
-- ImageInfo imageInfo(int row) const;
-- ImageInfo& imageInfoRef(int row) const;
-- qlonglong imageId(int row) const;
--
-- /** Return the index for the given ImageInfo or id, if contained in this model.
-- */
-- QModelIndex indexForImageInfo(const ImageInfo& info) const;
-- QModelIndex indexForImageInfo(const ImageInfo& info, const QVariant& extraValue) const;
-- QModelIndex indexForImageId(qlonglong id) const;
-- QModelIndex indexForImageId(qlonglong id, const QVariant& extraValue) const;
-- QList<QModelIndex> indexesForImageInfo(const ImageInfo& info) const;
-- QList<QModelIndex> indexesForImageId(qlonglong id) const;
--
-- int numberOfIndexesForImageInfo(const ImageInfo& info) const;
-- int numberOfIndexesForImageId(qlonglong id) const;
--
-- /** Returns the index or ImageInfo object from the underlying data
-- * for the given file path. This is fast if keepsFilePathCache is enabled.
-- * The file path is as returned by ImageInfo.filePath().
-- * In case of multiple occurrences of the same file, the simpler variants return
-- * any one found first, use the QList methods to retrieve all occurrences.
-- */
-- QModelIndex indexForPath(const QString& filePath) const;
-- ImageInfo imageInfo(const QString& filePath) const;
-- QList<QModelIndex> indexesForPath(const QString& filePath) const;
-- QList<ImageInfo> imageInfos(const QString& filePath) const;
--
-- /** Main entry point for subclasses adding image infos to the model.
-- * If you list entries not unique per image id, you must add an extraValue
-- * so that every entry is unique by imageId and extraValues.
-- * Please note that these methods do not prevent addition of duplicate entries.
-- */
-- void addImageInfo(const ImageInfo& info);
-- void addImageInfos(const QList<ImageInfo>& infos);
-- void addImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
--
-- /** Clears image infos and resets model.
-- */
-- void clearImageInfos();
--
-- /** Clears and adds the infos.
-- */
-- void setImageInfos(const QList<ImageInfo>& infos);
--
-- /**
-- * Directly remove the given indexes or infos from the model.
-- */
-- void removeIndex(const QModelIndex& indexes);
-- void removeIndexes(const QList<QModelIndex>& indexes);
-- void removeImageInfo(const ImageInfo& info);
-- void removeImageInfos(const QList<ImageInfo>& infos);
-- void removeImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
--
-- /**
-- * addImageInfo() is asynchronous if a prepocessor is set.
-- * This method first adds the info, synchronously.
-- * Only afterwards, the preprocessor will have the opportunity to process it.
-- * This method also bypasses any incremental updates.
-- * Please note that these methods do not prevent addition of duplicate entries.
-- */
-- void addImageInfoSynchronously(const ImageInfo& info);
-- void addImageInfosSynchronously(const QList<ImageInfo>& infos);
-- void addImageInfosSynchronously(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
--
-- /**
-- * Add the given entries. Method returns immediately, the
-- * addition may happen later asynchronously.
-- * These methods prevent the addition of duplicate entries.
-- */
-- void ensureHasImageInfo(const ImageInfo& info);
-- void ensureHasImageInfos(const QList<ImageInfo>& infos);
-- void ensureHasImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
--
-- /**
-- * Ensure that all images grouped on the given leader are contained in the model.
-- */
-- void ensureHasGroupedImages(const ImageInfo& groupLeader);
--
-- QList<ImageInfo> imageInfos() const;
-- QList<qlonglong> imageIds() const;
-- QList<ImageInfo> uniqueImageInfos() const;
--
-- bool hasImage(qlonglong id) const;
-- bool hasImage(const ImageInfo& info) const;
-- bool hasImage(const ImageInfo& info, const QVariant& extraValue) const;
-- bool hasImage(qlonglong id, const QVariant& extraValue) const;
--
-- bool isEmpty() const;
--
-- // Drag and Drop
-- DECLARE_MODEL_DRAG_DROP_METHODS
--
-- /**
-- * Install an object as a preprocessor for ImageInfos added to this model.
-- * For every QList of ImageInfos added to addImageInfo, the signal preprocess()
-- * will be emitted. The preprocessor may process the items and shall then readd
-- * them by calling reAddImageInfos(). It may take some time to process.
-- * It shall discard any held infos when the modelReset() signal is sent.
-- * It shall call readdFinished() when no reset occurred and all infos on the way have been readded.
-- * This means that only after calling this method, you shall make three connections
-- * (preprocess -> your slot, your signal -> reAddImageInfos, your signal -> reAddingFinished)
-- * and make or already hold a connection modelReset() -> your slot.
-- * There is only one preprocessor at a time, a previously set object will be disconnected.
-- */
-- void setPreprocessor(QObject* processor);
-- void unsetPreprocessor(QObject* processor);
--
-- /**
-- * Returns true if this model is currently refreshing.
-- * For a preprocessor this means that, although the preprocessor may currently have
-- * processed all it got, more batches are to be expected.
-- */
-- bool isRefreshing() const;
--
-- /**
-- * Enable sending of imageInfosAboutToBeRemoved and imageInfosRemoved signals.
-- * Default: false
-- */
-- void setSendRemovalSignals(bool send);
--
-- virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
-- virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
-- virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
-- virtual Qt::ItemFlags flags(const QModelIndex& index) const;
-- virtual QModelIndex index(int row, int column = 0, const QModelIndex& parent = QModelIndex()) const;
--
-- /** Retrieves the imageInfo object from the data() method of the given index.
-- * The index may be from a QSortFilterProxyModel as long as an ImageModel is at the end. */
-- static ImageInfo retrieveImageInfo(const QModelIndex& index);
-- static qlonglong retrieveImageId(const QModelIndex& index);
--
--Q_SIGNALS:
--
-- /** Informs that ImageInfos will be added to the model.
-- * This signal is sent before the model data is changed and views are informed.
-- */
-- void imageInfosAboutToBeAdded(const QList<ImageInfo>& infos);
--
-- /** Informs that ImageInfos have been added to the model.
-- * This signal is sent after the model data is changed and views are informed.
-- */
-- void imageInfosAdded(const QList<ImageInfo>& infos);
--
-- /** Informs that ImageInfos will be removed from the model.
-- * This signal is sent before the model data is changed and views are informed.
-- * Note: You need to explicitly enable sending of this signal. It is not sent
-- * in clearImageInfos().
-- */
-- void imageInfosAboutToBeRemoved(const QList<ImageInfo>& infos);
--
-- /** Informs that ImageInfos have been removed from the model.
-- * This signal is sent after the model data is changed and views are informed. *
-- * Note: You need to explicitly enable sending of this signal. It is not sent
-- * in clearImageInfos().
-- */
-- void imageInfosRemoved(const QList<ImageInfo>& infos);
--
-- /** Connect to this signal only if you are the current preprocessor.
-- */
-- void preprocess(const QList<ImageInfo>& infos, const QList<QVariant>&);
-- void processAdded(const QList<ImageInfo>& infos, const QList<QVariant>&);
--
-- /** If an ImageChangeset affected indexes of this model with changes as set in watchFlags(),
-- * this signal contains the changeset and the affected indexes.
-- */
-- void imageChange(const ImageChangeset&, const QItemSelection&);
--
-- /** If an ImageTagChangeset affected indexes of this model,
-- * this signal contains the changeset and the affected indexes.
-- */
-- void imageTagChange(const ImageTagChangeset&, const QItemSelection&);
--
-- /** Signals that the model is right now ready to start an incremental refresh.
-- * This is guaranteed only for the scope of emitting this signal.
-- */
-- void readyForIncrementalRefresh();
--
-- /** Signals that the model has finished currently with all scheduled
-- * refreshing, full or incremental, and all preprocessing.
-- * The model is in polished, clean situation right now.
-- */
-- void allRefreshingFinished();
--
--public Q_SLOTS:
--
-- void reAddImageInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-- void reAddingFinished();
--
--protected:
--
-- /** Subclasses that add ImageInfos in batches shall call startRefresh()
-- * when they start sending batches and finishRefresh() when they have finished.
-- * No incremental refreshes will be started while listing.
-- * A clearImageInfos() always stops listing, calling finishRefresh() is then not necessary.
-- */
-- void startRefresh();
-- void finishRefresh();
--
-- /** As soon as the model is ready to start an incremental refresh, the signal
-- * readyForIncrementalRefresh() will be emitted. The signal will be emitted inline
-- * if the model is ready right now.
-- */
-- void requestIncrementalRefresh();
-- bool hasIncrementalRefreshPending() const;
--
-- /** Starts an incremental refresh operation. You shall only call this method from a slot
-- * connected to readyForIncrementalRefresh(). To initiate an incremental refresh,
-- * call requestIncrementalRefresh().
-- */
-- void startIncrementalRefresh();
-- void finishIncrementalRefresh();
--
-- void emitDataChangedForAll();
-- void emitDataChangedForSelection(const QItemSelection& selection);
--
-- // Called when the internal storage is cleared
-- virtual void imageInfosCleared() {};
--
-- // Called before rowsAboutToBeRemoved
-- virtual void imageInfosAboutToBeRemoved(int /*begin*/, int /*end*/) {};
--
--protected Q_SLOTS:
--
-- virtual void slotImageChange(const ImageChangeset& changeset);
-- virtual void slotImageTagChange(const ImageTagChangeset& changeset);
--
--private:
--
-- void appendInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-- void appendInfosChecked(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-- void publiciseInfos(const QList<ImageInfo>& infos, const QList<QVariant>& extraValues);
-- void cleanSituationChecks();
-- void removeRowPairsWithCheck(const QList<QPair<int, int> >& toRemove);
-- void removeRowPairs(const QList<QPair<int, int> >& toRemove);
--
--public:
--
-- // Declared public because it's used in ImageModelIncrementalUpdater class
-- class Private;
--
--private:
--
-- Private* const d;
--};
--
--} // namespace Digikam
--
--Q_DECLARE_METATYPE(Digikam::ImageModel*)
--
--#endif // IMAGEMODEL_H
-diff --git a/libs/models/imagesortsettings.cpp b/libs/models/imagesortsettings.cpp
-deleted file mode 100644
-index 39ee6e1..0000000
---- a/libs/models/imagesortsettings.cpp
-+++ /dev/null
-@@ -1,400 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Filter values for use with ImageFilterModel
-- *
-- * Copyright (C) 2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- * Copyright (C) 2014 by Mohamed Anwer <m dot anwer at gmx 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 "imagesortsettings.h"
--
--// Qt includes
--
--#include <QDateTime>
--#include <QRectF>
--
--// Local includes
--
--#include "coredbfields.h"
--#include "imageinfo.h"
--
--namespace Digikam
--{
--
--ImageSortSettings::ImageSortSettings()
--{
-- categorizationMode = NoCategories;
-- categorizationSortOrder = DefaultOrder;
-- categorizationCaseSensitivity = Qt::CaseSensitive;
-- sortRole = SortByFileName;
-- sortOrder = DefaultOrder;
-- strTypeNatural = true;
-- sortCaseSensitivity = Qt::CaseSensitive;
-- currentCategorizationSortOrder = Qt::AscendingOrder;
-- currentSortOrder = Qt::AscendingOrder;
--}
--
--bool ImageSortSettings::operator==(const ImageSortSettings& other) const
--{
-- return
-- categorizationMode == other.categorizationMode &&
-- categorizationSortOrder == other.categorizationSortOrder &&
-- categorizationCaseSensitivity == other.categorizationCaseSensitivity &&
-- sortRole == other.sortRole &&
-- sortOrder == other.sortOrder &&
-- sortCaseSensitivity == other.sortCaseSensitivity;
--}
--
--void ImageSortSettings::setCategorizationMode(CategorizationMode mode)
--{
-- categorizationMode = mode;
--
-- if (categorizationSortOrder == DefaultOrder)
-- {
-- currentCategorizationSortOrder = defaultSortOrderForCategorizationMode(categorizationMode);
-- }
--}
--
--void ImageSortSettings::setCategorizationSortOrder(SortOrder order)
--{
-- categorizationSortOrder = order;
--
-- if (categorizationSortOrder == DefaultOrder)
-- {
-- currentCategorizationSortOrder = defaultSortOrderForCategorizationMode(categorizationMode);
-- }
-- else
-- {
-- currentCategorizationSortOrder = (Qt::SortOrder)categorizationSortOrder;
-- }
--}
--
--void ImageSortSettings::setSortRole(SortRole role)
--{
-- sortRole = role;
--
-- if (sortOrder == DefaultOrder)
-- {
-- currentSortOrder = defaultSortOrderForSortRole(sortRole);
-- }
--}
--
--void ImageSortSettings::setSortOrder(SortOrder order)
--{
-- sortOrder = order;
--
-- if (sortOrder == DefaultOrder)
-- {
-- currentSortOrder = defaultSortOrderForSortRole(sortRole);
-- }
-- else
-- {
-- currentSortOrder = (Qt::SortOrder)order;
-- }
--}
--
--void ImageSortSettings::setStringTypeNatural(bool natural)
--{
-- strTypeNatural = natural;
--}
--
--Qt::SortOrder ImageSortSettings::defaultSortOrderForCategorizationMode(CategorizationMode mode)
--{
-- switch (mode)
-- {
-- case NoCategories:
-- case OneCategory:
-- case CategoryByAlbum:
-- case CategoryByFormat:
-- default:
-- return Qt::AscendingOrder;
-- }
--}
--
--Qt::SortOrder ImageSortSettings::defaultSortOrderForSortRole(SortRole role)
--{
-- switch (role)
-- {
-- case SortByFileName:
-- case SortByFilePath:
-- return Qt::AscendingOrder;
-- case SortByFileSize:
-- return Qt::DescendingOrder;
-- case SortByModificationDate:
-- case SortByCreationDate:
-- return Qt::AscendingOrder;
-- case SortByRating:
-- case SortByImageSize:
-- return Qt::DescendingOrder;
-- case SortByAspectRatio:
-- return Qt::DescendingOrder;
-- case SortBySimilarity:
-- return Qt::DescendingOrder;
-- default:
-- return Qt::AscendingOrder;
-- }
--}
--
--int ImageSortSettings::compareCategories(const ImageInfo& left, const ImageInfo& right) const
--{
-- switch (categorizationMode)
-- {
-- case NoCategories:
-- case OneCategory:
-- return 0;
-- case CategoryByAlbum:
-- {
-- int leftAlbum = left.albumId();
-- int rightAlbum = right.albumId();
--
-- // return comparation result
-- if (leftAlbum == rightAlbum)
-- {
-- return 0;
-- }
-- else if (lessThanByOrder(leftAlbum, rightAlbum, currentCategorizationSortOrder))
-- {
-- return -1;
-- }
-- else
-- {
-- return 1;
-- }
-- }
-- case CategoryByFormat:
-- {
-- return naturalCompare(left.format(), right.format(),
-- currentCategorizationSortOrder, categorizationCaseSensitivity, strTypeNatural);
-- }
-- default:
-- return 0;
-- }
--}
--
--bool ImageSortSettings::lessThan(const ImageInfo& left, const ImageInfo& right) const
--{
-- int result = compare(left, right, sortRole);
--
-- if (result != 0)
-- {
-- return result < 0;
-- }
--
-- // are they identical?
-- if (left == right)
-- {
-- return false;
-- }
--
-- // If left and right equal for first sort order, use a hierarchy of all sort orders
-- if ( (result = compare(left, right, SortByFileName)) != 0)
-- {
-- return result < 0;
-- }
--
-- if ( (result = compare(left, right, SortByCreationDate)) != 0)
-- {
-- return result < 0;
-- }
--
-- if ( (result = compare(left, right, SortByModificationDate)) != 0)
-- {
-- return result < 0;
-- }
--
-- if ( (result = compare(left, right, SortByFilePath)) != 0)
-- {
-- return result < 0;
-- }
--
-- if ( (result = compare(left, right, SortByFileSize)) != 0)
-- {
-- return result < 0;
-- }
--
-- if ( (result = compare(left, right, SortBySimilarity)) != 0)
-- {
-- return result < 0;
-- }
--
-- return false;
--}
--
--int ImageSortSettings::compare(const ImageInfo& left, const ImageInfo& right) const
--{
-- return compare(left, right, sortRole);
--}
--
--int ImageSortSettings::compare(const ImageInfo& left, const ImageInfo& right, SortRole role) const
--{
-- switch (role)
-- {
-- case SortByFileName:
-- {
-- bool versioning = (left.name().contains(QLatin1String("_v"), Qt::CaseInsensitive) ||
-- right.name().contains(QLatin1String("_v"), Qt::CaseInsensitive));
-- return naturalCompare(left.name(), right.name(), currentSortOrder, sortCaseSensitivity, strTypeNatural, versioning);
-- }
-- case SortByFilePath:
-- return naturalCompare(left.filePath(), right.filePath(), currentSortOrder, sortCaseSensitivity, strTypeNatural);
-- case SortByFileSize:
-- return compareByOrder(left.fileSize(), right.fileSize(), currentSortOrder);
-- case SortByModificationDate:
-- return compareByOrder(left.modDateTime(), right.modDateTime(), currentSortOrder);
-- case SortByCreationDate:
-- return compareByOrder(left.dateTime(), right.dateTime(), currentSortOrder);
-- case SortByRating:
-- // I have the feeling that inverting the sort order for rating is the natural order
-- return - compareByOrder(left.rating(), right.rating(), currentSortOrder);
-- case SortByImageSize:
-- {
-- QSize leftSize = left.dimensions();
-- QSize rightSize = right.dimensions();
-- int leftPixels = leftSize.width() * leftSize.height();
-- int rightPixels = rightSize.width() * rightSize.height();
-- return compareByOrder(leftPixels, rightPixels, currentSortOrder);
-- }
-- case SortByAspectRatio:
-- {
-- QSize leftSize = left.dimensions();
-- QSize rightSize = right.dimensions();
-- int leftAR = (double(leftSize.width()) / double(leftSize.height())) * 1000000;
-- int rightAR = (double(rightSize.width()) / double(rightSize.height())) * 1000000;
-- return compareByOrder(leftAR, rightAR, currentSortOrder);
-- }
-- case SortBySimilarity:
-- {
-- qlonglong leftReferenceImageId = left.currentReferenceImage();
-- qlonglong rightReferenceImageId = right.currentReferenceImage();
-- // make sure that the original image has always the highest similarity.
-- double leftSimilarity = left.id() == leftReferenceImageId ? 1.1 : left.currentSimilarity();
-- double rightSimilarity = right.id() == rightReferenceImageId ? 1.1 : right.currentSimilarity();
-- return compareByOrder(leftSimilarity, rightSimilarity, currentSortOrder);
-- }
-- default:
-- return 1;
-- }
--}
--
--bool ImageSortSettings::lessThan(const QVariant& left, const QVariant& right) const
--{
-- if (left.type() != right.type())
-- {
-- return false;
-- }
--
-- switch (left.type())
-- {
-- case QVariant::Int:
-- return compareByOrder(left.toInt(), right.toInt(), currentSortOrder);
-- case QVariant::UInt:
-- return compareByOrder(left.toUInt(), right.toUInt(), currentSortOrder);
-- case QVariant::LongLong:
-- return compareByOrder(left.toLongLong(), right.toLongLong(), currentSortOrder);
-- case QVariant::ULongLong:
-- return compareByOrder(left.toULongLong(), right.toULongLong(), currentSortOrder);
-- case QVariant::Double:
-- return compareByOrder(left.toDouble(), right.toDouble(), currentSortOrder);
-- case QVariant::Date:
-- return compareByOrder(left.toDate(), right.toDate(), currentSortOrder);
-- case QVariant::DateTime:
-- return compareByOrder(left.toDateTime(), right.toDateTime(), currentSortOrder);
-- case QVariant::Time:
-- return compareByOrder(left.toTime(), right.toTime(), currentSortOrder);
-- case QVariant::Rect:
-- case QVariant::RectF:
-- {
-- QRectF rectLeft = left.toRectF();
-- QRectF rectRight = right.toRectF();
-- int result;
--
-- if ((result = compareByOrder(rectLeft.top(), rectRight.top(), currentSortOrder)) != 0)
-- {
-- return result < 0;
-- }
--
-- if ((result = compareByOrder(rectLeft.left(), rectRight.left(), currentSortOrder)) != 0)
-- {
-- return result < 0;
-- }
--
-- QSizeF sizeLeft = rectLeft.size(), sizeRight = rectRight.size();
--
-- if ((result = compareByOrder(sizeLeft.width()*sizeLeft.height(), sizeRight.width()*sizeRight.height(), currentSortOrder)) != 0)
-- {
-- return result < 0;
-- }
-- // FIXME: fall through?? If not, add "break" here
-- }
-- default:
-- return naturalCompare(left.toString(), right.toString(), currentSortOrder, sortCaseSensitivity, strTypeNatural);
-- }
--}
--
--DatabaseFields::Set ImageSortSettings::watchFlags() const
--{
-- DatabaseFields::Set set;
--
-- switch (sortRole)
-- {
-- case SortByFileName:
-- set |= DatabaseFields::Name;
-- break;
-- case SortByFilePath:
-- set |= DatabaseFields::Name;
-- break;
-- case SortByFileSize:
-- set |= DatabaseFields::FileSize;
-- break;
-- case SortByModificationDate:
-- set |= DatabaseFields::ModificationDate;
-- break;
-- case SortByCreationDate:
-- set |= DatabaseFields::CreationDate;
-- break;
-- case SortByRating:
-- set |= DatabaseFields::Rating;
-- break;
-- case SortByImageSize:
-- set |= DatabaseFields::Width | DatabaseFields::Height;
-- break;
-- case SortByAspectRatio:
-- set |= DatabaseFields::Width | DatabaseFields::Height;
-- break;
-- case SortBySimilarity:
-- // TODO: Not sure what to do here....
-- set |= DatabaseFields::Name;
-- break;
-- }
--
-- switch (categorizationMode)
-- {
-- case NoCategories:
-- case OneCategory:
-- case CategoryByAlbum:
-- break;
-- case CategoryByFormat:
-- set |= DatabaseFields::Format;
-- break;
-- }
--
-- return set;
--}
--
--} // namespace Digikam
-diff --git a/libs/models/imagesortsettings.h b/libs/models/imagesortsettings.h
-deleted file mode 100644
-index 2a5fd8c..0000000
---- a/libs/models/imagesortsettings.h
-+++ /dev/null
-@@ -1,225 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-05-31
-- * Description : Sort settings for use with ImageFilterModel
-- *
-- * Copyright (C) 2009 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- *
-- * 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 IMAGESORTSETTINGS_H
--#define IMAGESORTSETTINGS_H
--
--// Qt includes
--
--#include <QHash>
--#include <QList>
--#include <QMap>
--#include <QString>
--#include <QCollator>
--
--// Local includes
--
--#include "digikam_export.h"
--
--namespace Digikam
--{
--
--class ImageInfo;
--
--namespace DatabaseFields
--{
-- class Set;
--}
--
--class DIGIKAM_DATABASE_EXPORT ImageSortSettings
--{
--public:
--
-- ImageSortSettings();
--
-- bool operator==(const ImageSortSettings& other) const;
--
-- /** Compares the categories of left and right.
-- * Return -1 if left is less than right, 0 if both fall in the same category,
-- * and 1 if left is greater than right.
-- * Adheres to set categorization mode and current category sort order.
-- */
-- int compareCategories(const ImageInfo& left, const ImageInfo& right) const;
--
-- /** Returns true if left is less than right.
-- * Adheres to current sort role and sort order.
-- */
-- bool lessThan(const ImageInfo& left, const ImageInfo& right) const;
--
-- /** Compares the ImageInfos left and right.
-- * Return -1 if left is less than right, 1 if left is greater than right,
-- * and 0 if left equals right comparing the current sort role's value.
-- * Adheres to set sort role and sort order.
-- */
-- int compare(const ImageInfo& left, const ImageInfo& right) const;
--
-- /** Returns true if left QVariant is less than right.
-- * Adheres to current sort role and sort order.
-- * Use for extraValue, if necessary.
-- */
-- bool lessThan(const QVariant& left, const QVariant& right) const;
--
-- enum SortOrder
-- {
-- AscendingOrder = Qt::AscendingOrder,
-- DescendingOrder = Qt::DescendingOrder,
-- DefaultOrder /// sort order depends on the chosen sort role
-- };
--
-- /// --- Categories ---
--
-- enum CategorizationMode
-- {
-- NoCategories, /// categorization switched off
-- OneCategory, /// all items in one global category
-- CategoryByAlbum,
-- CategoryByFormat
-- };
--
-- CategorizationMode categorizationMode;
-- SortOrder categorizationSortOrder;
--
-- void setCategorizationMode(CategorizationMode mode);
-- void setCategorizationSortOrder(SortOrder order);
--
-- /// Only Ascending or Descending, never DefaultOrder
-- Qt::SortOrder currentCategorizationSortOrder;
-- Qt::CaseSensitivity categorizationCaseSensitivity;
--
-- bool isCategorized() const { return categorizationMode >= CategoryByAlbum; }
--
-- /// --- Image Sorting ---
--
-- enum SortRole
-- {
-- // Note: For legacy reasons, the order of the first five entries must remain unchanged
-- SortByFileName,
-- SortByFilePath,
-- SortByCreationDate,
-- SortByFileSize,
-- SortByRating,
-- SortByModificationDate,
-- SortByImageSize, // pixel number
-- SortByAspectRatio, // width / height * 100000
-- SortBySimilarity
-- };
--
-- SortRole sortRole;
-- SortOrder sortOrder;
-- bool strTypeNatural;
--
-- void setSortRole(SortRole role);
-- void setSortOrder(SortOrder order);
-- void setStringTypeNatural(bool natural);
--
-- Qt::SortOrder currentSortOrder;
-- Qt::CaseSensitivity sortCaseSensitivity;
--
-- int compare(const ImageInfo& left, const ImageInfo& right, SortRole sortRole) const;
--
-- // --- ---
--
-- static Qt::SortOrder defaultSortOrderForCategorizationMode(CategorizationMode mode);
-- static Qt::SortOrder defaultSortOrderForSortRole(SortRole role);
--
-- /// --- Change notification ---
--
-- /** Returns database fields a change in which would affect the current sorting.
-- */
-- DatabaseFields::Set watchFlags() const;
--
-- /// --- Utilities ---
--
-- /** Returns a < b if sortOrder is Ascending, or b < a if order is descending.
-- */
-- template <typename T>
-- static inline bool lessThanByOrder(const T& a, const T& b, Qt::SortOrder sortOrder)
-- {
-- if (sortOrder == Qt::AscendingOrder)
-- {
-- return a < b;
-- }
-- else
-- {
-- return b < a;
-- }
-- }
--
-- /** Returns the usual compare result of -1, 0, or 1 for lessThan, equals and greaterThan.
-- */
-- template <typename T>
-- static inline int compareValue(const T& a, const T& b)
-- {
-- if (a == b)
-- {
-- return 0;
-- }
--
-- if (a < b)
-- {
-- return -1;
-- }
-- else
-- {
-- return 1;
-- }
-- }
--
-- /** Takes a typical result from a compare method (0 is equal, -1 is less than, 1 is greater than)
-- * and applies the given sort order to it.
-- */
-- static inline int compareByOrder(int compareResult, Qt::SortOrder sortOrder)
-- {
-- if (sortOrder == Qt::AscendingOrder)
-- {
-- return compareResult;
-- }
-- else
-- {
-- return - compareResult;
-- }
-- }
--
-- template <typename T>
-- static inline int compareByOrder(const T& a, const T& b, Qt::SortOrder sortOrder)
-- {
-- return compareByOrder(compareValue(a, b), sortOrder);
-- }
--
-- /** Compares the two string by natural comparison and adheres to given sort order
-- */
-- static inline int naturalCompare(const QString& a, const QString& b, Qt::SortOrder sortOrder,
-- Qt::CaseSensitivity caseSensitive = Qt::CaseSensitive,
-- bool natural = true, bool versioning = false)
-- {
-- QCollator collator;
-- collator.setNumericMode(natural);
-- collator.setIgnorePunctuation(versioning);
-- collator.setCaseSensitivity(caseSensitive);
-- return (compareByOrder(collator.compare(a, b), sortOrder));
-- }
--};
--
--} // namespace Digikam
--
--#endif // IMAGESORTSETTINGS_H
-diff --git a/libs/models/imagethumbnailmodel.cpp b/libs/models/imagethumbnailmodel.cpp
-deleted file mode 100644
-index b7f5661..0000000
---- a/libs/models/imagethumbnailmodel.cpp
-+++ /dev/null
-@@ -1,323 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Qt item model for database entries with support for thumbnail loading
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- * Copyright (C) 2011-2017 by Gilles Caulier <caulier dot gilles 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 "imagethumbnailmodel.h"
--
--// Qt includes
--
--#include <QHash>
--
--// Local includes
--
--#include "digikam_debug.h"
--#include "thumbnailloadthread.h"
--#include "digikam_export.h"
--#include "digikam_globals.h"
--
--namespace Digikam
--{
--
--class ImageThumbnailModel::ImageThumbnailModelPriv
--{
--public:
--
-- ImageThumbnailModelPriv() :
-- thread(0),
-- preloadThread(0),
-- thumbSize(0),
-- lastGlobalThumbSize(0),
-- preloadThumbSize(0),
-- emitDataChanged(true)
-- {
-- staticListContainingThumbnailRole << ImageModel::ThumbnailRole;
-- }
--
-- ThumbnailLoadThread* thread;
-- ThumbnailLoadThread* preloadThread;
-- ThumbnailSize thumbSize;
-- ThumbnailSize lastGlobalThumbSize;
-- ThumbnailSize preloadThumbSize;
-- QRect detailRect;
-- QVector<int> staticListContainingThumbnailRole;
--
-- bool emitDataChanged;
--
-- int preloadThumbnailSize() const
-- {
-- if (preloadThumbSize.size())
-- {
-- return preloadThumbSize.size();
-- }
--
-- return thumbSize.size();
-- }
--};
--
--ImageThumbnailModel::ImageThumbnailModel(QObject* parent)
-- : ImageModel(parent), d(new ImageThumbnailModelPriv)
--{
-- setKeepsFilePathCache(true);
--}
--
--ImageThumbnailModel::~ImageThumbnailModel()
--{
-- delete d->preloadThread;
-- delete d;
--}
--
--void ImageThumbnailModel::setThumbnailLoadThread(ThumbnailLoadThread* thread)
--{
-- d->thread = thread;
--
-- connect(d->thread, SIGNAL(signalThumbnailLoaded(LoadingDescription,QPixmap)),
-- this, SLOT(slotThumbnailLoaded(LoadingDescription,QPixmap)));
--}
--
--ThumbnailLoadThread* ImageThumbnailModel::thumbnailLoadThread() const
--{
-- return d->thread;
--}
--
--ThumbnailSize ImageThumbnailModel::thumbnailSize() const
--{
-- return d->thumbSize;
--}
--
--void ImageThumbnailModel::setThumbnailSize(const ThumbnailSize& size)
--{
-- d->lastGlobalThumbSize = size;
-- d->thumbSize = size;
--}
--
--void ImageThumbnailModel::setPreloadThumbnailSize(const ThumbnailSize& size)
--{
-- d->preloadThumbSize = size;
--}
--
--void ImageThumbnailModel::setEmitDataChanged(bool emitSignal)
--{
-- d->emitDataChanged = emitSignal;
--}
--
--void ImageThumbnailModel::setPreloadThumbnails(bool preload)
--{
-- if (preload)
-- {
-- if (!d->preloadThread)
-- {
-- d->preloadThread = new ThumbnailLoadThread;
-- d->preloadThread->setPixmapRequested(false);
-- d->preloadThread->setPriority(QThread::LowestPriority);
-- }
--
-- connect(this, SIGNAL(allRefreshingFinished()),
-- this, SLOT(preloadAllThumbnails()));
-- }
-- else
-- {
-- delete d->preloadThread;
-- d->preloadThread = 0;
-- disconnect(this, SIGNAL(allRefreshingFinished()),
-- this, SLOT(preloadAllThumbnails()));
-- }
--}
--
--void ImageThumbnailModel::prepareThumbnails(const QList<QModelIndex>& indexesToPrepare)
--{
-- prepareThumbnails(indexesToPrepare, d->thumbSize);
--}
--
--void ImageThumbnailModel::prepareThumbnails(const QList<QModelIndex>& indexesToPrepare, const ThumbnailSize& thumbSize)
--{
-- if (!d->thread)
-- {
-- return;
-- }
--
-- QList<ThumbnailIdentifier> ids;
-- foreach(const QModelIndex& index, indexesToPrepare)
-- {
-- ids << imageInfoRef(index).thumbnailIdentifier();
-- }
-- d->thread->findGroup(ids, thumbSize.size());
--}
--
--void ImageThumbnailModel::preloadThumbnails(const QList<ImageInfo>& infos)
--{
-- if (!d->preloadThread)
-- {
-- return;
-- }
--
-- QList<ThumbnailIdentifier> ids;
-- foreach(const ImageInfo& info, infos)
-- {
-- ids << info.thumbnailIdentifier();
-- }
-- d->preloadThread->pregenerateGroup(ids, d->preloadThumbnailSize());
--}
--
--void ImageThumbnailModel::preloadThumbnails(const QList<QModelIndex>& indexesToPreload)
--{
-- if (!d->preloadThread)
-- {
-- return;
-- }
--
-- QList<ThumbnailIdentifier> ids;
-- foreach(const QModelIndex& index, indexesToPreload)
-- {
-- ids << imageInfoRef(index).thumbnailIdentifier();
-- }
-- d->preloadThread->stopAllTasks();
-- d->preloadThread->pregenerateGroup(ids, d->preloadThumbnailSize());
--}
--
--void ImageThumbnailModel::preloadAllThumbnails()
--{
-- preloadThumbnails(imageInfos());
--}
--
--void ImageThumbnailModel::imageInfosCleared()
--{
-- if (d->preloadThread)
-- {
-- d->preloadThread->stopAllTasks();
-- }
--}
--
--QVariant ImageThumbnailModel::data(const QModelIndex& index, int role) const
--{
-- if (role == ThumbnailRole && d->thread && index.isValid())
-- {
-- QPixmap thumbnail;
-- ImageInfo info = imageInfo(index);
-- QString path = info.filePath();
--
-- if (info.isNull())
-- {
-- return QVariant(QVariant::Pixmap);
-- }
--
-- if (!d->detailRect.isNull())
-- {
-- if (d->thread->find(info.thumbnailIdentifier(), d->detailRect, thumbnail, d->thumbSize.size()))
-- {
-- return thumbnail;
-- }
-- }
-- else
-- {
-- if (d->thread->find(info.thumbnailIdentifier(), thumbnail, d->thumbSize.size()))
-- {
-- return thumbnail;
-- }
-- }
--
-- return QVariant(QVariant::Pixmap);
-- }
--
-- return ImageModel::data(index, role);
--}
--
--bool ImageThumbnailModel::setData(const QModelIndex& index, const QVariant& value, int role)
--{
-- if (role == ThumbnailRole)
-- {
-- switch (value.type())
-- {
-- case QVariant::Invalid:
-- d->thumbSize = d->lastGlobalThumbSize;
-- d->detailRect = QRect();
-- break;
--
-- case QVariant::Int:
--
-- if (value.isNull())
-- {
-- d->thumbSize = d->lastGlobalThumbSize;
-- }
-- else
-- {
-- d->thumbSize = value.toInt();
-- }
-- break;
--
-- case QVariant::Rect:
--
-- if (value.isNull())
-- {
-- d->detailRect = QRect();
-- }
-- else
-- {
-- d->detailRect = value.toRect();
-- }
-- break;
--
-- default:
-- break;
-- }
-- }
--
-- return ImageModel::setData(index, value, role);
--}
--
--void ImageThumbnailModel::slotThumbnailLoaded(const LoadingDescription& loadingDescription, const QPixmap& thumb)
--{
-- if (thumb.isNull())
-- {
-- return;
-- }
--
-- // In case of multiple occurrence, we currently do not know which thumbnail is this. Signal change on all.
-- QModelIndexList indexes;
-- ThumbnailIdentifier thumbId = loadingDescription.thumbnailIdentifier();
-- if (thumbId.filePath.isEmpty())
-- {
-- indexes = indexesForImageId(thumbId.id);
-- }
-- else
-- {
-- indexes = indexesForPath(thumbId.filePath);
-- }
-- foreach(const QModelIndex& index, indexes)
-- {
-- if (thumb.isNull())
-- {
-- emit thumbnailFailed(index, loadingDescription.previewParameters.size);
-- }
-- else
-- {
-- emit thumbnailAvailable(index, loadingDescription.previewParameters.size);
--
-- if (d->emitDataChanged)
-- {
-- emit dataChanged(index, index, d->staticListContainingThumbnailRole);
-- }
-- }
-- }
--}
--
--} // namespace Digikam
-diff --git a/libs/models/imagethumbnailmodel.h b/libs/models/imagethumbnailmodel.h
-deleted file mode 100644
-index 366ca65..0000000
---- a/libs/models/imagethumbnailmodel.h
-+++ /dev/null
-@@ -1,140 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2009-03-05
-- * Description : Qt item model for database entries with support for thumbnail loading
-- *
-- * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
-- * Copyright (C) 2011 by Gilles Caulier <caulier dot gilles 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 IMAGETHUMBNAILMODEL_H
--#define IMAGETHUMBNAILMODEL_H
--
--// Local includes
--
--#include "imagemodel.h"
--#include "thumbnailsize.h"
--#include "digikam_export.h"
--
--namespace Digikam
--{
--
--class LoadingDescription;
--class ThumbnailLoadThread;
--
--class DIGIKAM_DATABASE_EXPORT ImageThumbnailModel : public ImageModel
--{
-- Q_OBJECT
--
--public:
--
-- /**
-- * An ImageModel that supports thumbnail loading.
-- * You need to set a ThumbnailLoadThread to enable thumbnail loading.
-- * Adjust the thumbnail size to your needs.
-- * Note that setKeepsFilePathCache is enabled per default.
-- */
-- explicit ImageThumbnailModel(QObject* parent);
-- ~ImageThumbnailModel();
--
-- /** Enable thumbnail loading and set the thread that shall be used.
-- * The thumbnail size of this thread will be adjusted.
-- */
-- void setThumbnailLoadThread(ThumbnailLoadThread* thread);
-- ThumbnailLoadThread* thumbnailLoadThread() const;
--
-- /// Set the thumbnail size to use
-- void setThumbnailSize(const ThumbnailSize& thumbSize);
--
-- /// If you want to fix a size for preloading, do it here.
-- void setPreloadThumbnailSize(const ThumbnailSize& thumbSize);
--
-- void setExifRotate(bool rotate);
--
-- /**
-- * Enable emitting dataChanged() when a thumbnail becomes available.
-- * The thumbnailAvailable() signal will be emitted in any case.
-- * Default is true.
-- */
-- void setEmitDataChanged(bool emitSignal);
--
-- /**
-- * Enable preloading of thumbnails:
-- * If preloading is enabled, for every entry in the model a thumbnail generation is started.
-- * Default: false.
-- */
-- void setPreloadThumbnails(bool preload);
--
-- ThumbnailSize thumbnailSize() const;
--
-- /**
-- * Handles the ThumbnailRole.
-- * If the pixmap is available, returns it in the QVariant.
-- * If it still needs to be loaded, returns a null QVariant and emits
-- * thumbnailAvailable() as soon as it is available.
-- */
-- virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
--
-- /**
-- * You can override the current thumbnail size by giving an integer value for ThumbnailRole.
-- * Set a null QVariant to use the thumbnail size set by setThumbnailSize() again.
-- * The index given here is ignored for this purpose.
-- */
-- virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::DisplayRole);
--
--public Q_SLOTS:
--
-- /** Prepare the thumbnail loading for the given indexes
-- */
-- void prepareThumbnails(const QList<QModelIndex>& indexesToPrepare);
-- void prepareThumbnails(const QList<QModelIndex>& indexesToPrepare, const ThumbnailSize& thumbSize);
--
-- /**
-- * Preload thumbnail for the given infos resp. indexes.
-- * Note: Use setPreloadThumbnails to automatically preload all entries in the model.
-- * Note: This only ensures thumbnail generation. It is not guaranteed that pixmaps
-- * are stored in the cache. For thumbnails that are expect to be drawn immediately,
-- * include them in prepareThumbnails().
-- * Note: Stops preloading of previously added thumbnails.
-- */
-- void preloadThumbnails(const QList<ImageInfo>&);
-- void preloadThumbnails(const QList<QModelIndex>&);
-- void preloadAllThumbnails();
--
--Q_SIGNALS:
--
-- void thumbnailAvailable(const QModelIndex& index, int requestedSize);
-- void thumbnailFailed(const QModelIndex& index, int requestedSize);
--
--protected:
--
-- virtual void imageInfosCleared();
--
--protected Q_SLOTS:
--
-- void slotThumbnailLoaded(const LoadingDescription& loadingDescription, const QPixmap& thumb);
--
--private:
--
-- class ImageThumbnailModelPriv;
-- ImageThumbnailModelPriv* const d;
--};
--
--} // namespace Digikam
--
--#endif /* IMAGETHUMBNAILMODEL_H */
-diff --git a/libs/models/imageversionsmodel.cpp b/libs/models/imageversionsmodel.cpp
-deleted file mode 100644
-index e6ba582..0000000
---- a/libs/models/imageversionsmodel.cpp
-+++ /dev/null
-@@ -1,183 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2010-07-13
-- * Description : Model for image versions
-- *
-- * Copyright (C) 2010 by Martin Klapetek <martin dot klapetek 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 "imageversionsmodel.h"
--
--// KDE includes
--
--#include <klocalizedstring.h>
--
--// Local includes
--
--#include "digikam_debug.h"
--#include "workingwidget.h"
--
--namespace Digikam
--{
--
--class ImageVersionsModel::Private
--{
--public:
--
-- Private()
-- {
-- data = 0;
-- paintTree = false;
-- }
--
-- ///Complete paths with filenames and tree level
-- QList<QPair<QString, int> >* data;
-- ///This is for delegate to paint it as selected
-- QString currentSelectedImage;
-- ///If true, the delegate will paint items as a tree
-- ///if false, it will be painted as a list
-- bool paintTree;
--};
--
--ImageVersionsModel::ImageVersionsModel(QObject* parent)
-- : QAbstractListModel(parent),
-- d(new Private)
--{
-- d->data = new QList<QPair<QString, int> >;
--}
--
--ImageVersionsModel::~ImageVersionsModel()
--{
-- //qDeleteAll(d->data);
-- delete d;
--}
--
--Qt::ItemFlags ImageVersionsModel::flags(const QModelIndex& index) const
--{
-- if (!index.isValid())
-- {
-- return 0;
-- }
--
-- return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
--}
--
--QVariant ImageVersionsModel::data(const QModelIndex& index, int role) const
--{
-- if (!index.isValid())
-- {
-- return QVariant();
-- }
--
-- if (role == Qt::DisplayRole && !d->data->isEmpty())
-- {
-- return d->data->at(index.row()).first;
-- }
-- else if (role == Qt::UserRole && !d->data->isEmpty())
-- {
-- return d->data->at(index.row()).second;
-- }
-- else if (role == Qt::DisplayRole && d->data->isEmpty())
-- {
-- //TODO: make this text Italic
-- return QVariant(QString(i18n("No image selected")));
-- }
--
-- return QVariant();
--}
--
--int ImageVersionsModel::rowCount(const QModelIndex& parent) const
--{
-- Q_UNUSED(parent)
-- return d->data->count();
--}
--
--void ImageVersionsModel::setupModelData(QList<QPair<QString, int> >& data)
--{
-- beginResetModel();
--
-- d->data->clear();
--
-- if (!data.isEmpty())
-- {
-- d->data->append(data);
-- }
-- else
-- {
-- d->data->append(qMakePair(QString(i18n("This is the original image")), 0));
-- }
--
-- endResetModel();
--}
--
--void ImageVersionsModel::clearModelData()
--{
-- beginResetModel();
--
-- if (!d->data->isEmpty())
-- {
-- d->data->clear();
-- }
--
-- endResetModel();
--}
--
--void ImageVersionsModel::slotAnimationStep()
--{
-- emit dataChanged(createIndex(0, 0), createIndex(rowCount()-1, 1));
--}
--
--QString ImageVersionsModel::currentSelectedImage() const
--{
-- return d->currentSelectedImage;
--}
--
--void ImageVersionsModel::setCurrentSelectedImage(const QString& path)
--{
-- d->currentSelectedImage = path;
--}
--
--QModelIndex ImageVersionsModel::currentSelectedImageIndex() const
--{
-- return index(listIndexOf(d->currentSelectedImage), 0);
--}
--
--bool ImageVersionsModel::paintTree() const
--{
-- return d->paintTree;
--}
--
--void ImageVersionsModel::setPaintTree(bool paint)
--{
-- d->paintTree = paint;
--}
--
--int ImageVersionsModel::listIndexOf(const QString& item) const
--{
-- for (int i = 0; i < d->data->size(); ++i)
-- {
-- if (d->data->at(i).first == item)
-- {
-- return i;
-- }
-- }
--
-- return -1;
--}
--
--} // namespace Digikam
-diff --git a/libs/models/imageversionsmodel.h b/libs/models/imageversionsmodel.h
-deleted file mode 100644
-index ed08529..0000000
---- a/libs/models/imageversionsmodel.h
-+++ /dev/null
-@@ -1,75 +0,0 @@
--/* ============================================================
-- *
-- * This file is a part of digiKam project
-- * http://www.digikam.org
-- *
-- * Date : 2010-07-13
-- * Description : Model for image versions
-- *
-- * Copyright (C) 2010 by Martin Klapetek <martin dot klapetek 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 IMAGEVERSIONSMODEL_H
--#define IMAGEVERSIONSMODEL_H
--
--// Qt includes
--
--#include <QModelIndex>
--#include <QPixmap>
--
--// Local includes
--
--#include "digikam_export.h"
--
--namespace Digikam
--{
--
--class DIGIKAM_DATABASE_EXPORT ImageVersionsModel : public QAbstractListModel
--{
-- Q_OBJECT
--
--public:
--
-- explicit ImageVersionsModel(QObject* parent = 0);
-- ~ImageVersionsModel();
--
-- Qt::ItemFlags flags(const QModelIndex& index) const;
-- QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
-- int rowCount(const QModelIndex& parent = QModelIndex()) const;
--
-- void setupModelData(QList<QPair<QString, int> >& data);
-- void clearModelData();
--
-- QString currentSelectedImage() const;
-- void setCurrentSelectedImage(const QString& path);
-- QModelIndex currentSelectedImageIndex() const;
--
-- bool paintTree() const;
-- int listIndexOf(const QString& item) const;
--
--public Q_SLOTS:
--
-- void slotAnimationStep();
-- void setPaintTree(bool paint);
--
--private:
--
-- class Private;
-- Private* const d;
--};
--
--} // namespace Digikam
--
--#endif // IMAGEVERSIONSMODEL_H
---
-cgit v0.11.2
-
diff --git a/kde/patch/digikam/digikam_imagemagick7.patch b/kde/patch/digikam/digikam_imagemagick7.patch
deleted file mode 100644
index 04a7752..0000000
--- a/kde/patch/digikam/digikam_imagemagick7.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-From: Antonio Rojas <arojas@archlinux.org>
-Date: Thu, 7 Nov 2019 09:25:02 +0100
-Subject: Properly initialize ExceptionInfo in libMagick
-
-Otherwise it will crash if some plugins can't be loaded.
-
-diff --git a/core/dplugins/dimg/imagemagick/dimgimagemagickplugin.cpp b/core/dplugins/dimg/imagemagick/dimgimagemagickplugin.cpp
-index 1858b4d..20ef01b 100644
---- a/core/dplugins/dimg/imagemagick/dimgimagemagickplugin.cpp
-+++ b/core/dplugins/dimg/imagemagick/dimgimagemagickplugin.cpp
-@@ -125,7 +125,7 @@ QMap<QString, QString> DImgImageMagickPlugin::extraAboutData() const
- QString mimes = typeMimes();
-
- QMap<QString, QString> map;
-- ExceptionInfo ex;
-+ ExceptionInfo ex = *AcquireExceptionInfo();
- size_t n = 0;
- const MagickInfo** inflst = GetMagickInfoList("*", &n, &ex);
-
-@@ -219,7 +219,7 @@ int DImgImageMagickPlugin::canRead(const QFileInfo& fileInfo, bool magic) const
- int DImgImageMagickPlugin::canWrite(const QString& format) const
- {
- QStringList formats;
-- ExceptionInfo ex;
-+ ExceptionInfo ex = *AcquireExceptionInfo();
- size_t n = 0;
- const MagickInfo** inflst = GetMagickInfoList("*", &n, &ex);
-
-@@ -266,7 +266,7 @@ DImgLoader* DImgImageMagickPlugin::loader(DImg* const image, const DRawDecoding&
- QStringList DImgImageMagickPlugin::decoderFormats() const
- {
- QStringList formats;
-- ExceptionInfo ex;
-+ ExceptionInfo ex = *AcquireExceptionInfo();
- size_t n = 0;
- const MagickInfo** inflst = GetMagickInfoList("*", &n, &ex);
-
---
-cgit v1.1
-