Bug 115160

Summary: digikam: 'Filter tags' should use 'and' not 'or' or maybe better label 'Show Tags'
Product: [Applications] digikam Reporter: Achim Bohnet <ach>
Component: Tags-EngineAssignee: Digikam Developers <digikam-bugs-null>
Status: RESOLVED FIXED    
Severity: wishlist CC: ana, gschintgen
Priority: NOR    
Version: 0.8.0   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In: 0.9.0
Attachments: new matching condition options available into popup menu

Description Achim Bohnet 2005-10-26 23:50:02 UTC
Version:           0.8.0-beta2 (using KDE 3.4.3, Kubuntu Package 4:3.4.3-0ubuntu1 )
Compiler:          Target: i486-linux-gnu
OS:                Linux (i686) release 2.6.12-9-686

This was originally report in debians BTS:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=329014

After using Tags more extensivly I agree with
the submitter.  In my cases I always wanted 'and'
and not 'or' in 'filter tags'.  But I'm sure 'or' is needed too ;)

Nevertheless, that more images match when one applies
more filter rules (aka selecting more tags) is
strange.  More filter usually means less output.

Maybe 'Filter Tags' is better labeled 'Show Tags'??

So 'Show Tags' with 'or'
and 'Filter Tags' with 'and'?

Achim
Comment 1 caulier.gilles 2006-09-03 14:25:34 UTC
Achim,

I'm not favorable to dupplicate sidebar tab only for that. The more simple way is to adda 2 toolbar boutton on the top on the sidebar (like Metadata tab for example) to choose OR or AND condition using by the filter.

Your viewpoints...

Gilles
Comment 2 F.J. Cruz 2006-09-03 22:00:41 UTC
El Domingo, 3 de Septiembre de 2006 14:25, Gilles Caulier escribi
Comment 3 caulier.gilles 2006-09-04 10:55:19 UTC
Ok, i have seen where we can implement the _AND_ condition with tags filter view (AlbumLister::matchesFilter() from albumlister.cpp)

I will try to do it using a new sub option in contextual menu (more simple to do it against to use toolbar buttons)

Gilles
Comment 4 caulier.gilles 2006-09-04 12:57:13 UTC
SVN commit 580718 by cgilles:

digiKam from trunk: tag filters view: new options to set the matching condition to use between tags : OR condition or AND condition
The settings is stored in digiKAm config file and is restored between session.

BUG: 115160


 M  +42 -20    albumlister.cpp  
 M  +13 -1     albumlister.h  
 M  +46 -8     tagfilterview.cpp  


--- trunk/extragear/graphics/digikam/digikam/albumlister.cpp #580717:580718
@@ -66,28 +66,31 @@
 
     AlbumListerPriv()
     {
-        filterTimer = 0;
-        job         = 0;
-        currAlbum   = 0;
-        filter      = "*";
+        filterTimer  = 0;
+        job          = 0;
+        currAlbum    = 0;
+        filter       = "*";
+        matchingCond = AlbumLister::OrCondition;
     }
 
-    bool                       untaggedFilter;
+    bool                            untaggedFilter;
 
-    QString                    filter;
+    QString                         filter;
 
-    QMap<Q_LLONG, ImageInfo*>  itemMap;
-    QMap<int,bool>             dayFilter;
+    QMap<Q_LLONG, ImageInfo*>       itemMap;
+    QMap<int,bool>                  dayFilter;
 
-    QValueList<int>            tagFilter;
+    QValueList<int>                 tagFilter;
 
-    QTimer                    *filterTimer;
+    QTimer                         *filterTimer;
 
-    KIO::TransferJob          *job;
+    KIO::TransferJob               *job;
 
-    ImageInfoList              itemList;
+    ImageInfoList                   itemList;
 
-    Album                     *currAlbum;
+    Album                          *currAlbum;
+
+    AlbumLister::MatchingCondition matchingCond;
 };
 
 AlbumLister* AlbumLister::m_instance = 0;
@@ -202,9 +205,11 @@
     d->filterTimer->start(100, true);
 }
 
-void AlbumLister::setTagFilter(const QValueList<int>& tags, bool showUnTagged)
+void AlbumLister::setTagFilter(const QValueList<int>& tags, const MatchingCondition& matchingCond, 
+                               bool showUnTagged)
 {
-    d->tagFilter = tags;
+    d->tagFilter      = tags;
+    d->matchingCond   = matchingCond;
     d->untaggedFilter = showUnTagged;
     d->filterTimer->start(100, true);
 }
@@ -220,16 +225,33 @@
     if (!d->tagFilter.isEmpty())
     {
         QValueList<int> tagIDs = info->tagIDs();
-        for (QValueList<int>::iterator it = d->tagFilter.begin();
-             it != d->tagFilter.end(); ++it)
+        QValueList<int>::iterator it;
+
+        if (d->matchingCond == OrCondition)        
         {
-            if (tagIDs.contains(*it))
+            for (it = d->tagFilter.begin(); it != d->tagFilter.end(); ++it)
             {
-                match = true;
-                break;
+                if (tagIDs.contains(*it))
+                {
+                    match = true;
+                    break;
+                }
             }
         }
+        else
+        {
+            // AND matching condition...
 
+            for (it = d->tagFilter.begin(); it != d->tagFilter.end(); ++it)
+            {
+                if (!tagIDs.contains(*it))
+                    break;
+            }
+    
+            if (it == d->tagFilter.end())
+                match = true;
+        }
+
         match |= (d->untaggedFilter && tagIDs.isEmpty());
     }
     else if (d->untaggedFilter)
--- trunk/extragear/graphics/digikam/digikam/albumlister.h #580717:580718
@@ -58,6 +58,17 @@
 
 public:
 
+    /** @enum MatchingCondition
+     * Possible logical matching condition used to sort tags id.
+     */
+    enum MatchingCondition
+    {
+        OrCondition = 0,
+        AndCondition
+    };
+
+public:
+
     static AlbumLister* instance();
     
     ~AlbumLister();
@@ -76,7 +87,8 @@
     void setNameFilter(const QString& nameFilter);
 
     void setDayFilter(const QValueList<int>& days);
-    void setTagFilter(const QValueList<int>& tags, bool showUnTagged=false);
+    void setTagFilter(const QValueList<int>& tags, const MatchingCondition& matchingCond, 
+                      bool showUnTagged=false);
     
 signals:
 
--- trunk/extragear/graphics/digikam/digikam/tagfilterview.cpp #580717:580718
@@ -34,6 +34,7 @@
 #include <klocale.h>
 #include <kdebug.h>
 #include <kapplication.h>
+#include <kconfig.h>
 #include <kiconloader.h>
 #include <kglobalsettings.h>
 #include <kcursor.h>
@@ -72,7 +73,7 @@
         : FolderCheckListItem(parent, tag ? tag->title() : i18n("Not Tagged"),
                               QCheckListItem::CheckBoxController)
     {
-        m_tag = tag;
+        m_tag      = tag;
         m_untagged = untagged;
         setDragEnabled(!untagged);
 
@@ -83,7 +84,7 @@
     TagFilterViewItem(QListViewItem* parent, TAlbum* tag)
         : FolderCheckListItem(parent, tag->title(), QCheckListItem::CheckBoxController)
     {
-        m_tag = tag;
+        m_tag      = tag;
         m_untagged = false;
         setDragEnabled(true);
 
@@ -132,7 +133,7 @@
         FolderCheckListItem::paintCell(p, mcg, column, width, align);
     }
 
-    TAlbum* m_tag;
+    TAlbum *m_tag;
     bool    m_untagged;
 };
 
@@ -145,10 +146,13 @@
 
     TagFilterViewPriv()
     {
-        timer = 0;
+        timer        = 0;
+        matchingCond = AlbumLister::OrCondition;
     }
 
-    QTimer *timer;
+    QTimer                         *timer;
+ 
+    AlbumLister::MatchingCondition  matchingCond;
 };
 
 TagFilterView::TagFilterView(QWidget* parent)
@@ -168,6 +172,8 @@
     TagFilterViewItem* notTaggedItem = new TagFilterViewItem(this, 0, true);
     notTaggedItem->setPixmap(0, AlbumThumbnailLoader::instance()->getStandardTagIcon());
 
+    // -- setup slots ---------------------------------------------------------
+
     connect(AlbumManager::instance(), SIGNAL(signalAlbumAdded(Album*)),
             this, SLOT(slotTagAdded(Album*)));
             
@@ -199,10 +205,22 @@
 
     connect(d->timer, SIGNAL(timeout()),
             this, SLOT(slotTimeOut()));
+
+    // -- read config ---------------------------------------------------------
+
+    KConfig* config = kapp->config();
+    config->setGroup("Tag Filters View");
+    d->matchingCond = (AlbumLister::MatchingCondition)(config->readNumEntry("Matching Condition", 
+                                                       AlbumLister::OrCondition));
 }
 
 TagFilterView::~TagFilterView()
 {
+    KConfig* config = kapp->config();
+    config->setGroup("Tag Filters View");
+    config->writeEntry("Matching Condition", (int)(d->matchingCond));
+    config->sync();
+
     delete d->timer;
     delete d;
 }
@@ -297,10 +315,10 @@
         else
         {
             QPopupMenu popMenu(this);
-            popMenu.insertItem( SmallIcon("tag"), i18n("Assign Tag '%1' to Dropped Items")
+            popMenu.insertItem(SmallIcon("tag"), i18n("Assign Tag '%1' to Dropped Items")
                                 .arg(destAlbum->prettyURL()), 10) ;
             popMenu.insertSeparator(-1);
-            popMenu.insertItem( SmallIcon("cancel"), i18n("C&ancel") );
+            popMenu.insertItem(SmallIcon("cancel"), i18n("C&ancel"));
 
             popMenu.setMouseTracking(true);
             id = popMenu.exec(QCursor::pos());
@@ -497,7 +515,7 @@
         ++it;
     }
 
-    AlbumLister::instance()->setTagFilter(filterTags, showUnTagged);
+    AlbumLister::instance()->setTagFilter(filterTags, d->matchingCond, showUnTagged);
 }
 
 void TagFilterView::slotContextMenu(QListViewItem* it, const QPoint&, int)
@@ -521,7 +539,15 @@
     popmenu.insertItem(i18n("Select All"),       14);
     popmenu.insertItem(i18n("Deselect"),         15);
     popmenu.insertItem(i18n("Invert Selection"), 16);
+    popmenu.insertSeparator();
 
+    QPopupMenu matchingCongMenu;
+    matchingCongMenu.setCheckable(true);
+    matchingCongMenu.insertItem(i18n("Or Between Tags"),  17);
+    matchingCongMenu.insertItem(i18n("And Between Tags"), 18);
+    matchingCongMenu.setItemChecked((d->matchingCond == AlbumLister::OrCondition) ? 17 : 18, true);
+    popmenu.insertItem(i18n("Matching Condition"), &matchingCongMenu);
+
     int choice = popmenu.exec((QCursor::pos()));
     switch( choice )
     {
@@ -592,6 +618,18 @@
             triggerChange();
             break;
         }
+        case 17:
+        {
+            d->matchingCond = AlbumLister::OrCondition;
+            triggerChange();
+            break;
+        }
+        case 18:
+        {
+            d->matchingCond = AlbumLister::AndCondition;
+            triggerChange();
+            break;
+        }
         default:
             break;
     }
Comment 5 caulier.gilles 2006-09-04 13:08:01 UTC
Created attachment 17633 [details]
new matching condition options available into popup menu