1 /* ============================================================
2 *
3 * This file is a part of digiKam project
4 * https://www.digikam.org
5 *
6 * Date : 2009-03-05
7 * Description : Filter values for use with ItemFilterModel
8 *
9 * Copyright (C) 2009-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
10 * Copyright (C) 2011-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
11 * Copyright (C) 2010 by Andi Clemens <andi dot clemens at gmail dot com>
12 * Copyright (C) 2011 by Michael G. Hansen <mike at mghansen dot de>
13 * Copyright (C) 2014 by Mohamed_Anwer <m_dot_anwer at gmx dot com>
14 *
15 * This program is free software; you can redistribute it
16 * and/or modify it under the terms of the GNU General
17 * Public License as published by the Free Software Foundation;
18 * either version 2, or (at your option)
19 * any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * ============================================================ */
27
28 #include "itemfiltersettings.h"
29
30 // C++ includes
31
32 #include <cmath>
33
34 // Qt includes
35
36 #include <QDateTime>
37
38 // Local includes
39
40 #include "digikam_debug.h"
41 #include "coredbfields.h"
42 #include "digikam_globals.h"
43 #include "iteminfo.h"
44 #include "tagscache.h"
45 #include "versionmanagersettings.h"
46
47 namespace Digikam
48 {
49
ItemFilterSettings()50 ItemFilterSettings::ItemFilterSettings()
51 : m_untaggedFilter (false),
52 m_matchingCond (OrCondition),
53 m_ratingFilter (0),
54 m_ratingCond (GreaterEqualCondition),
55 m_isUnratedExcluded (false),
56 m_mimeTypeFilter (MimeFilter::AllFiles),
57 m_geolocationCondition(GeolocationNoFilter)
58 {
59 }
60
watchFlags() const61 DatabaseFields::Set ItemFilterSettings::watchFlags() const
62 {
63 DatabaseFields::Set set;
64
65 if (isFilteringByDay())
66 {
67 set |= DatabaseFields::CreationDate;
68 }
69
70 if (isFilteringByText())
71 {
72 set |= DatabaseFields::Name;
73 set |= DatabaseFields::Comment;
74 }
75
76 if (isFilteringByRating())
77 {
78 set |= DatabaseFields::Rating;
79 }
80
81 if (isFilteringByTypeMime())
82 {
83 set |= DatabaseFields::Category;
84 set |= DatabaseFields::Format;
85 }
86
87 if (isFilteringByGeolocation())
88 {
89 set |= DatabaseFields::ItemPositionsAll;
90 }
91
92 if (isFilteringByColorLabels())
93 {
94 set |= DatabaseFields::ColorLabel;
95 }
96
97 if (isFilteringByPickLabels())
98 {
99 set |= DatabaseFields::PickLabel;
100 }
101
102 return set;
103 }
104
isFilteringByDay() const105 bool ItemFilterSettings::isFilteringByDay() const
106 {
107 if (!m_dayFilter.isEmpty())
108 {
109 return true;
110 }
111
112 return false;
113 }
114
isFilteringByTags() const115 bool ItemFilterSettings::isFilteringByTags() const
116 {
117 if (!m_includeTagFilter.isEmpty() || !m_excludeTagFilter.isEmpty() || m_untaggedFilter)
118 {
119 return true;
120 }
121
122 return false;
123 }
124
isFilteringByColorLabels() const125 bool ItemFilterSettings::isFilteringByColorLabels() const
126 {
127 if (!m_colorLabelTagFilter.isEmpty())
128 {
129 return true;
130 }
131
132 return false;
133 }
134
isFilteringByPickLabels() const135 bool ItemFilterSettings::isFilteringByPickLabels() const
136 {
137 if (!m_pickLabelTagFilter.isEmpty())
138 {
139 return true;
140 }
141
142 return false;
143 }
144
isFilteringByText() const145 bool ItemFilterSettings::isFilteringByText() const
146 {
147 if (!m_textFilterSettings.text.isEmpty())
148 {
149 return true;
150 }
151
152 return false;
153 }
154
isFilteringByTypeMime() const155 bool ItemFilterSettings::isFilteringByTypeMime() const
156 {
157 if (m_mimeTypeFilter != MimeFilter::AllFiles)
158 {
159 return true;
160 }
161
162 return false;
163 }
164
isFilteringByGeolocation() const165 bool ItemFilterSettings::isFilteringByGeolocation() const
166 {
167 return (m_geolocationCondition != GeolocationNoFilter);
168 }
169
isFilteringByRating() const170 bool ItemFilterSettings::isFilteringByRating() const
171 {
172 if ((m_ratingFilter != 0) || (m_ratingCond != GreaterEqualCondition) || m_isUnratedExcluded)
173 {
174 return true;
175 }
176
177 return false;
178 }
179
isFilteringInternally() const180 bool ItemFilterSettings::isFilteringInternally() const
181 {
182 return (isFiltering() || !m_urlWhitelists.isEmpty() || !m_idWhitelists.isEmpty());
183 }
184
isFiltering() const185 bool ItemFilterSettings::isFiltering() const
186 {
187 return (isFilteringByDay() ||
188 isFilteringByTags() ||
189 isFilteringByText() ||
190 isFilteringByRating() ||
191 isFilteringByTypeMime() ||
192 isFilteringByColorLabels() ||
193 isFilteringByPickLabels() ||
194 isFilteringByGeolocation());
195 }
196
setDayFilter(const QList<QDateTime> & days)197 void ItemFilterSettings::setDayFilter(const QList<QDateTime>& days)
198 {
199 m_dayFilter.clear();
200
201 for (QList<QDateTime>::const_iterator it = days.constBegin() ; it != days.constEnd() ; ++it)
202 {
203 m_dayFilter.insert(*it, true);
204 }
205 }
206
setTagFilter(const QList<int> & includedTags,const QList<int> & excludedTags,MatchingCondition matchingCondition,bool showUnTagged,const QList<int> & clTagIds,const QList<int> & plTagIds)207 void ItemFilterSettings::setTagFilter(const QList<int>& includedTags,
208 const QList<int>& excludedTags,
209 MatchingCondition matchingCondition,
210 bool showUnTagged,
211 const QList<int>& clTagIds,
212 const QList<int>& plTagIds)
213 {
214 m_includeTagFilter = includedTags;
215 m_excludeTagFilter = excludedTags;
216 m_matchingCond = matchingCondition;
217 m_untaggedFilter = showUnTagged;
218 m_colorLabelTagFilter = clTagIds;
219 m_pickLabelTagFilter = plTagIds;
220 }
221
setRatingFilter(int rating,RatingCondition ratingCondition,bool isUnratedExcluded)222 void ItemFilterSettings::setRatingFilter(int rating, RatingCondition ratingCondition, bool isUnratedExcluded)
223 {
224 m_ratingFilter = rating;
225 m_ratingCond = ratingCondition;
226 m_isUnratedExcluded = isUnratedExcluded;
227 }
228
setMimeTypeFilter(int mime)229 void ItemFilterSettings::setMimeTypeFilter(int mime)
230 {
231 m_mimeTypeFilter = (MimeFilter::TypeMimeFilter)mime;
232 }
233
setGeolocationFilter(const GeolocationCondition & condition)234 void ItemFilterSettings::setGeolocationFilter(const GeolocationCondition& condition)
235 {
236 m_geolocationCondition = condition;
237 }
238
setTextFilter(const SearchTextFilterSettings & settings)239 void ItemFilterSettings::setTextFilter(const SearchTextFilterSettings& settings)
240 {
241 m_textFilterSettings = settings;
242 }
243
setTagNames(const QHash<int,QString> & hash)244 void ItemFilterSettings::setTagNames(const QHash<int, QString>& hash)
245 {
246 m_tagNameHash = hash;
247 }
248
setAlbumNames(const QHash<int,QString> & hash)249 void ItemFilterSettings::setAlbumNames(const QHash<int, QString>& hash)
250 {
251 m_albumNameHash = hash;
252 }
253
setUrlWhitelist(const QList<QUrl> & urlList,const QString & id)254 void ItemFilterSettings::setUrlWhitelist(const QList<QUrl>& urlList, const QString& id)
255 {
256 if (urlList.isEmpty())
257 {
258 m_urlWhitelists.remove(id);
259 }
260 else
261 {
262 m_urlWhitelists.insert(id, urlList);
263 }
264 }
265
setIdWhitelist(const QList<qlonglong> & idList,const QString & id)266 void ItemFilterSettings::setIdWhitelist(const QList<qlonglong>& idList, const QString& id)
267 {
268 if (idList.isEmpty())
269 {
270 m_idWhitelists.remove(id);
271 }
272 else
273 {
274 m_idWhitelists.insert(id, idList);
275 }
276 }
277
278 template <class ContainerA, class ContainerB>
containsAnyOf(const ContainerA & listA,const ContainerB & listB)279 bool containsAnyOf(const ContainerA& listA, const ContainerB& listB)
280 {
281 foreach (const typename ContainerA::value_type& a, listA)
282 {
283 if (listB.contains(a))
284 {
285 return true;
286 }
287 }
288
289 return false;
290 }
291
292 template <class ContainerA, typename Value, class ContainerB>
containsNoneOfExcept(const ContainerA & list,const ContainerB & noneOfList,const Value & exception)293 bool containsNoneOfExcept(const ContainerA& list, const ContainerB& noneOfList, const Value& exception)
294 {
295 foreach (const typename ContainerB::value_type& n, noneOfList)
296 {
297 if (n != exception && list.contains(n))
298 {
299 return false;
300 }
301 }
302
303 return true;
304 }
305
matches(const ItemInfo & info,bool * const foundText) const306 bool ItemFilterSettings::matches(const ItemInfo& info, bool* const foundText) const
307 {
308 if (foundText)
309 {
310 *foundText = false;
311 }
312
313 if (!isFilteringInternally())
314 {
315 return true;
316 }
317
318 bool match = false;
319
320 if (!m_includeTagFilter.isEmpty() || !m_excludeTagFilter.isEmpty())
321 {
322 QList<int> tagIds = info.tagIds();
323 QList<int>::const_iterator it;
324
325 match = m_includeTagFilter.isEmpty();
326
327 if (m_matchingCond == OrCondition)
328 {
329 for (it = m_includeTagFilter.begin() ; it != m_includeTagFilter.end() ; ++it)
330 {
331 if (tagIds.contains(*it))
332 {
333 match = true;
334 break;
335 }
336 }
337
338 match |= (m_untaggedFilter && tagIds.isEmpty());
339 }
340 else // AND matching condition...
341 {
342 // m_untaggedFilter and non-empty tag filter, combined with AND, is logically no match
343 if (!m_untaggedFilter)
344 {
345 for (it = m_includeTagFilter.begin() ; it != m_includeTagFilter.end() ; ++it)
346 {
347 if (!tagIds.contains(*it))
348 {
349 break;
350 }
351 }
352
353 if (it == m_includeTagFilter.end())
354 {
355 match = true;
356 }
357 }
358 }
359
360 for (it = m_excludeTagFilter.begin() ; it != m_excludeTagFilter.end() ; ++it)
361 {
362 if (tagIds.contains(*it))
363 {
364 match = false;
365 break;
366 }
367 }
368 }
369 else if (m_untaggedFilter)
370 {
371 match = !TagsCache::instance()->containsPublicTags(info.tagIds());
372 }
373 else
374 {
375 match = true;
376 }
377
378 //-- Filter by pick labels ------------------------------------------------
379
380 if (!m_pickLabelTagFilter.isEmpty())
381 {
382 QList<int> tagIds = info.tagIds();
383 bool matchPL = false;
384
385 if (containsAnyOf(m_pickLabelTagFilter, tagIds))
386 {
387 matchPL = true;
388 }
389 else
390 {
391 int noPickLabelTagId = TagsCache::instance()->tagForPickLabel(NoPickLabel);
392
393 if (m_pickLabelTagFilter.contains(noPickLabelTagId))
394 {
395 // Searching for "has no ColorLabel" requires special handling:
396 // Scan that the tag ids contains none of the ColorLabel tags, except maybe the NoColorLabel tag
397
398 matchPL = containsNoneOfExcept(tagIds, TagsCache::instance()->pickLabelTags(), noPickLabelTagId);
399 }
400 }
401
402 match &= matchPL;
403 }
404
405 //-- Filter by color labels ------------------------------------------------
406
407 if (!m_colorLabelTagFilter.isEmpty())
408 {
409 QList<int> tagIds = info.tagIds();
410 bool matchCL = false;
411
412 if (containsAnyOf(m_colorLabelTagFilter, tagIds))
413 {
414 matchCL = true;
415 }
416 else
417 {
418 int noColorLabelTagId = TagsCache::instance()->tagForColorLabel(NoColorLabel);
419
420 if (m_colorLabelTagFilter.contains(noColorLabelTagId))
421 {
422 // Searching for "has no ColorLabel" requires special handling:
423 // Scan that the tag ids contains none of the ColorLabel tags, except maybe the NoColorLabel tag
424 matchCL = containsNoneOfExcept(tagIds, TagsCache::instance()->colorLabelTags(), noColorLabelTagId);
425 }
426 }
427
428 match &= matchCL;
429 }
430
431 //-- Filter by date -----------------------------------------------------------
432
433 if (!m_dayFilter.isEmpty())
434 {
435 match &= m_dayFilter.contains(QDateTime(info.dateTime().date(), QTime()));
436 }
437
438 //-- Filter by rating ---------------------------------------------------------
439
440 if (m_ratingFilter >= 0)
441 {
442 // for now we treat -1 (no rating) just like a rating of 0.
443
444 int rating = info.rating();
445
446 if (rating == -1)
447 {
448 rating = 0;
449 }
450
451 if (m_isUnratedExcluded && rating == 0)
452 {
453 match = false;
454 }
455 else
456 {
457 if (m_ratingCond == GreaterEqualCondition)
458 {
459 // If the rating is not >=, i.e it is <, then it does not match.
460
461 if (rating < m_ratingFilter)
462 {
463 match = false;
464 }
465 }
466 else if (m_ratingCond == EqualCondition)
467 {
468 // If the rating is not =, i.e it is !=, then it does not match.
469
470 if (rating != m_ratingFilter)
471 {
472 match = false;
473 }
474 }
475 else
476 {
477 // If the rating is not <=, i.e it is >, then it does not match.
478
479 if (rating > m_ratingFilter)
480 {
481 match = false;
482 }
483 }
484 }
485 }
486
487 // -- Filter by mime type -----------------------------------------------------
488
489 switch (m_mimeTypeFilter)
490 {
491 // info.format is a standardized string: Only one possibility per mime type
492
493 case MimeFilter::ImageFiles:
494 {
495 if (info.category() != DatabaseItem::Image)
496 {
497 match = false;
498 }
499
500 break;
501 }
502
503 case MimeFilter::JPGFiles:
504 {
505 if (info.format() != QLatin1String("JPG"))
506 {
507 match = false;
508 }
509
510 break;
511 }
512
513 case MimeFilter::PNGFiles:
514 {
515 if (info.format() != QLatin1String("PNG"))
516 {
517 match = false;
518 }
519
520 break;
521 }
522
523 case MimeFilter::HEIFFiles:
524 {
525 if (info.format() != QLatin1String("HEIF"))
526 {
527 match = false;
528 }
529
530 break;
531 }
532
533 case MimeFilter::PGFFiles:
534 {
535 if (info.format() != QLatin1String("PGF"))
536 {
537 match = false;
538 }
539
540 break;
541 }
542
543 case MimeFilter::TIFFiles:
544 {
545 if (info.format() != QLatin1String("TIFF"))
546 {
547 match = false;
548 }
549
550 break;
551 }
552
553 case MimeFilter::DNGFiles:
554 {
555 if (info.format() != QLatin1String("RAW-DNG"))
556 {
557 match = false;
558 }
559
560 break;
561 }
562
563 case MimeFilter::NoRAWFiles:
564 {
565 if (info.format().startsWith(QLatin1String("RAW")))
566 {
567 match = false;
568 }
569
570 break;
571 }
572
573 case MimeFilter::RAWFiles:
574 {
575 if (!info.format().startsWith(QLatin1String("RAW")))
576 {
577 match = false;
578 }
579
580 break;
581 }
582
583 case MimeFilter::MoviesFiles:
584 {
585 if (info.category() != DatabaseItem::Video)
586 {
587 match = false;
588 }
589
590 break;
591 }
592
593 case MimeFilter::AudioFiles:
594 {
595 if (info.category() != DatabaseItem::Audio)
596 {
597 match = false;
598 }
599
600 break;
601 }
602
603 case MimeFilter::RasterGraphics:
604 {
605 if (
606 info.format() != QLatin1String("PSD") && // Adobe Photoshop Document
607 info.format() != QLatin1String("PSB") && // Adobe Photoshop Big
608 info.format() != QLatin1String("XCF") && // Gimp
609 info.format() != QLatin1String("KRA") && // Krita
610 info.format() != QLatin1String("ORA") // Open Raster
611 )
612 {
613 match = false;
614 }
615
616 break;
617 }
618
619 default:
620 {
621 // All Files: do nothing...
622 break;
623 }
624 }
625
626 //-- Filter by geolocation ----------------------------------------------------
627
628 if (m_geolocationCondition != GeolocationNoFilter)
629 {
630 if (m_geolocationCondition == GeolocationNoCoordinates)
631 {
632 if (info.hasCoordinates())
633 {
634 match = false;
635 }
636 }
637 else if (m_geolocationCondition == GeolocationHasCoordinates)
638 {
639 if (!info.hasCoordinates())
640 {
641 match = false;
642 }
643 }
644 }
645
646 //-- Filter by text -----------------------------------------------------------
647
648 if (!m_textFilterSettings.text.isEmpty())
649 {
650 bool textMatch = false;
651
652 QRegExp textRegExp(m_textFilterSettings.text);
653 textRegExp.setPatternSyntax(QRegExp::WildcardUnix);
654 textRegExp.setCaseSensitivity(m_textFilterSettings.caseSensitive);
655
656 // Image name
657
658 if ((m_textFilterSettings.textFields & SearchTextFilterSettings::ImageName) &&
659 (textRegExp.exactMatch(info.name()) ||
660 info.name().contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive)))
661 {
662 textMatch = true;
663 }
664
665 // Image title
666
667 if ((m_textFilterSettings.textFields & SearchTextFilterSettings::ImageTitle) &&
668 (textRegExp.exactMatch(info.title()) ||
669 info.title().contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive)))
670 {
671 textMatch = true;
672 }
673
674 // Image comment
675
676 if ((m_textFilterSettings.textFields & SearchTextFilterSettings::ImageComment) &&
677 (textRegExp.exactMatch(info.comment()) ||
678 info.comment().contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive)))
679 {
680 textMatch = true;
681 }
682
683 // Tag names
684
685 foreach (int id, info.tagIds())
686 {
687 if ((m_textFilterSettings.textFields & SearchTextFilterSettings::TagName) &&
688 (textRegExp.exactMatch(m_tagNameHash.value(id)) ||
689 m_tagNameHash.value(id).contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive)))
690 {
691 textMatch = true;
692 }
693 }
694
695 // Album names
696
697 if ((m_textFilterSettings.textFields & SearchTextFilterSettings::AlbumName) &&
698 (textRegExp.exactMatch(m_albumNameHash.value(info.albumId())) ||
699 m_albumNameHash.value(info.albumId()).contains(m_textFilterSettings.text, m_textFilterSettings.caseSensitive)))
700 {
701 textMatch = true;
702 }
703
704 // Image Aspect Ratio
705
706 if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImageAspectRatio)
707 {
708 QRegExp expRatio (QLatin1String("^\\d+:\\d+$"));
709 QRegExp expFloat (QLatin1String("^\\d+(.\\d+)?$"));
710
711 if ((expRatio.indexIn(m_textFilterSettings.text) > -1) && m_textFilterSettings.text.contains(QRegExp(QLatin1String(":\\d+"))))
712 {
713 QString trimmedTextFilterSettingsText = m_textFilterSettings.text;
714 QStringList numberStringList = trimmedTextFilterSettingsText.split(QLatin1Char(':'), QString::SkipEmptyParts);
715
716 if (numberStringList.length() == 2)
717 {
718 QString numString = (QString)numberStringList.at(0), denomString = (QString)numberStringList.at(1);
719 bool canConverseNum = false;
720 bool canConverseDenom = false;
721 int num = numString.toInt(&canConverseNum, 10), denom = denomString.toInt(&canConverseDenom, 10);
722
723 if (canConverseNum && canConverseDenom)
724 {
725 if (fabs(info.aspectRatio() - (double)num / denom) < 0.1)
726 {
727 textMatch = true;
728 }
729 }
730 }
731 }
732 else if (expFloat.indexIn(m_textFilterSettings.text) > -1)
733 {
734 QString trimmedTextFilterSettingsText = m_textFilterSettings.text;
735 bool canConverse = false;
736 double ratio = trimmedTextFilterSettingsText.toDouble(&canConverse);
737
738 if (canConverse)
739 {
740 if (fabs(info.aspectRatio() - ratio) < 0.1)
741 {
742 textMatch = true;
743 }
744 }
745 }
746 }
747
748 // Image Pixel Size
749 // See bug #341053 for details.
750
751 if (m_textFilterSettings.textFields & SearchTextFilterSettings::ImagePixelSize)
752 {
753 QSize size = info.dimensions();
754 int pixelSize = size.height()*size.width();
755 QString text = m_textFilterSettings.text;
756
757 if (text.contains(QRegExp(QLatin1String("^>\\d{1,15}$"))) &&
758 (pixelSize > (text.remove(0, 1)).toInt()))
759 {
760 textMatch = true;
761 }
762 else if (text.contains(QRegExp(QLatin1String("^<\\d{1,15}$"))) &&
763 (pixelSize < (text.remove(0, 1)).toInt()))
764 {
765 textMatch = true;
766 }
767 else if (text.contains(QRegExp(QLatin1String("^\\d+$"))) &&
768 (pixelSize == text.toInt()))
769 {
770 textMatch = true;
771 }
772 }
773
774 match &= textMatch;
775
776 if (foundText)
777 {
778 *foundText = textMatch;
779 }
780 }
781
782 // -- filter by URL-whitelists ------------------------------------------------
783 // NOTE: whitelists are always AND for now.
784
785 if (match)
786 {
787 const QUrl url = info.fileUrl();
788
789 for (QHash<QString, QList<QUrl>>::const_iterator it = m_urlWhitelists.constBegin() ;
790 it != m_urlWhitelists.constEnd() ; ++it)
791 {
792 match = it->contains(url);
793
794 if (!match)
795 {
796 break;
797 }
798 }
799 }
800
801 if (match)
802 {
803 const qlonglong id = info.id();
804
805 for (QHash<QString, QList<qlonglong> >::const_iterator it = m_idWhitelists.constBegin() ;
806 it != m_idWhitelists.constEnd() ; ++it)
807 {
808 match = it->contains(id);
809
810 if (!match)
811 {
812 break;
813 }
814 }
815 }
816
817 return match;
818 }
819
820 // -------------------------------------------------------------------------------------------------
821
VersionItemFilterSettings()822 VersionItemFilterSettings::VersionItemFilterSettings()
823 : m_includeTagFilter (0),
824 m_exceptionTagFilter(0)
825 {
826 }
827
VersionItemFilterSettings(const VersionManagerSettings & settings)828 VersionItemFilterSettings::VersionItemFilterSettings(const VersionManagerSettings& settings)
829 {
830 setVersionManagerSettings(settings);
831 }
832
operator ==(const VersionItemFilterSettings & other) const833 bool VersionItemFilterSettings::operator==(const VersionItemFilterSettings& other) const
834 {
835 return ((m_excludeTagFilter == other.m_excludeTagFilter) &&
836 (m_exceptionLists == other.m_exceptionLists));
837 }
838
matches(const ItemInfo & info) const839 bool VersionItemFilterSettings::matches(const ItemInfo& info) const
840 {
841 if (!isFiltering())
842 {
843 return true;
844 }
845
846 const qlonglong id = info.id();
847
848 for (QHash<QString, QList<qlonglong> >::const_iterator it = m_exceptionLists.constBegin() ;
849 it != m_exceptionLists.constEnd() ; ++it)
850 {
851 if (it->contains(id))
852 {
853 return true;
854 }
855 }
856
857 bool match = true;
858 QList<int> tagIds = info.tagIds();
859
860 if (!tagIds.contains(m_includeTagFilter))
861 {
862 for (QList<int>::const_iterator it = m_excludeTagFilter.begin() ;
863 it != m_excludeTagFilter.end() ; ++it)
864 {
865 if (tagIds.contains(*it))
866 {
867 match = false;
868 break;
869 }
870 }
871 }
872
873 if (!match)
874 {
875 if (tagIds.contains(m_exceptionTagFilter))
876 {
877 match = true;
878 }
879 }
880
881 return match;
882 }
883
isHiddenBySettings(const ItemInfo & info) const884 bool VersionItemFilterSettings::isHiddenBySettings(const ItemInfo& info) const
885 {
886 QList<int> tagIds = info.tagIds();
887
888 foreach (int tagId, m_excludeTagFilter)
889 {
890 if (tagIds.contains(tagId))
891 {
892 return true;
893 }
894 }
895
896 return false;
897 }
898
isExemptedBySettings(const ItemInfo & info) const899 bool VersionItemFilterSettings::isExemptedBySettings(const ItemInfo& info) const
900 {
901 return info.tagIds().contains(m_exceptionTagFilter);
902 }
903
setVersionManagerSettings(const VersionManagerSettings & settings)904 void VersionItemFilterSettings::setVersionManagerSettings(const VersionManagerSettings& settings)
905 {
906 m_excludeTagFilter.clear();
907
908 if (!settings.enabled)
909 {
910 return;
911 }
912
913 if (!(settings.showInViewFlags & VersionManagerSettings::ShowOriginal))
914 {
915 m_excludeTagFilter << TagsCache::instance()->getOrCreateInternalTag(InternalTagName::originalVersion());
916 }
917
918 if (!(settings.showInViewFlags & VersionManagerSettings::ShowIntermediates))
919 {
920 m_excludeTagFilter << TagsCache::instance()->getOrCreateInternalTag(InternalTagName::intermediateVersion());
921 }
922
923 m_includeTagFilter = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::currentVersion());
924 m_exceptionTagFilter = TagsCache::instance()->getOrCreateInternalTag(InternalTagName::versionAlwaysVisible());
925 }
926
setExceptionList(const QList<qlonglong> & idList,const QString & id)927 void VersionItemFilterSettings::setExceptionList(const QList<qlonglong>& idList, const QString& id)
928 {
929 if (idList.isEmpty())
930 {
931 m_exceptionLists.remove(id);
932 }
933 else
934 {
935 m_exceptionLists.insert(id, idList);
936 }
937 }
938
isFiltering() const939 bool VersionItemFilterSettings::isFiltering() const
940 {
941 return !m_excludeTagFilter.isEmpty();
942 }
943
isFilteringByTags() const944 bool VersionItemFilterSettings::isFilteringByTags() const
945 {
946 return isFiltering();
947 }
948
949 // -------------------------------------------------------------------------------------------------
950
GroupItemFilterSettings()951 GroupItemFilterSettings::GroupItemFilterSettings()
952 : m_allOpen(false)
953 {
954 }
955
operator ==(const GroupItemFilterSettings & other) const956 bool GroupItemFilterSettings::operator==(const GroupItemFilterSettings& other) const
957 {
958 return ((m_allOpen == other.m_allOpen) &&
959 (m_openGroups == other.m_openGroups));
960 }
961
matches(const ItemInfo & info) const962 bool GroupItemFilterSettings::matches(const ItemInfo& info) const
963 {
964 if (m_allOpen)
965 {
966 return true;
967 }
968
969 if (info.isGrouped())
970 {
971 return m_openGroups.contains(info.groupImage().id());
972 }
973
974 return true;
975 }
976
setOpen(qlonglong group,bool open)977 void GroupItemFilterSettings::setOpen(qlonglong group, bool open)
978 {
979 if (open)
980 {
981 m_openGroups << group;
982 }
983 else
984 {
985 m_openGroups.remove(group);
986 }
987 }
988
isOpen(qlonglong group) const989 bool GroupItemFilterSettings::isOpen(qlonglong group) const
990 {
991 return m_openGroups.contains(group);
992 }
993
setAllOpen(bool open)994 void GroupItemFilterSettings::setAllOpen(bool open)
995 {
996 m_allOpen = open;
997 }
998
isAllOpen() const999 bool GroupItemFilterSettings::isAllOpen() const
1000 {
1001 return m_allOpen;
1002 }
1003
isFiltering() const1004 bool GroupItemFilterSettings::isFiltering() const
1005 {
1006 return !m_allOpen;
1007 }
1008
watchFlags() const1009 DatabaseFields::Set GroupItemFilterSettings::watchFlags() const
1010 {
1011 return DatabaseFields::Set(DatabaseFields::ImageRelations);
1012 }
1013
1014 } // namespace Digikam
1015