[calligra] /: Add resource categorizing with tags

Boudewijn Rempt boud at valdyas.org
Sat May 18 08:39:01 UTC 2013


Git commit a86b7b848a4a93ffc7ab427aa70827e410d40e64 by Boudewijn Rempt.
Committed on 18/05/2013 at 10:37.
Pushed by rempt into branch 'master'.

Add resource categorizing with tags

Patch by Sascha Suelzer
CCMAIL:s_suelzer at lavabit.com
CCMAIL:kimageshop at kde.org
REVIEW:110429
FEATURE: Add resource categorizing with tags

Todo: keep the comboboxes synchronized

This improves the way the user can organize resources into named sets
that can be added, deleted and chosen from a drop down menu that I've
added to KoResourceItemChooser. This made the changes available to the
paintoppreset choosers, the gradient choosers and the pattern choosers.

Usage right now is:

Mostly mouse based version:
Right clicking any resource can assign it to or remove it from any tag.
There is an option to create a new tag for the resource as well.
It's fairly intuitive.
-----------------------------------------------------------------------

Mostly keyboard based version:
Resource dockers and popups start with an unfiltered view, in this view
the tag search bar at the bottom is disabled.

To add a tag category, press the plus button and enter a name for the tag.

This creates an empty view and enables the search text box at the bottom.

Terms in double quotes "like this" will be matched to the resource name
exactly.

Entering terms without quotes will partial matching, good for filtering
many resources. filtering eraser would remove all resources with eraser in
their name.

Putting an exclamation mark in front of a term will exclude the term from
the set.

Pressing enter saves the set and will clear the search box, so we don't end
up with something like erase,sketch,fur,!paint,smudge_1,smudge_2,... etc

Once a set is defined, it can be used as a search term as well.
For example:
We've created a set that contains all erasers and is called 'erasers'.
If we switch to a different set and type [erasers] in the search box then
all the items of that set will be added to the current set, exclusions work
the same way.

============================================================================
Remarks about the patch:

Currently only adding and deleting categories is supported, renaming them
is in the code but lacks an UI feature, which I was unable to implement.
(I wanted the unfiltered view to be immutable and tried dis and enabling
the editable state of the drop down box based on which index was active,
but that introduced a segfault.)
All in all the UI parts I've written aren't exactly amazing, maybe
someone more experienced can take care of that? I can do it but it'd be
slow since I have very little experience with that.

I have removed the `show all' checkbox in the paintop preset docker and
all references to that functionality since it made filtering a bit more
complicated as well as just not making too much sense with the
improvements to the tagging system.

I have also removed the proxy adapter in KisPresetChooser since it
didn't do anything useful after these changes, yet required attention
since it overloaded some now improved functions.

Current shortcomings of the system, most of them are UI related:

- Since I used the already existing KoResourceTagging class to handle all
 the tagging bits, and ultimately save tags to disk, in alphabetical
 order, restarting Krita, and thus repopulating the combo boxes also
 fills them in alphabetical order and not in the order they might have
 been defined by the user.

- Adding a new tag in a pop-up chooser closes the popup since I used an
 input dialog after failing to implement it with combobox editing.

- Combo boxes aren't updated for all item choosers of the same kind.
 For example adding a few categories in the preset docker does not update
 the combo box in the preset chooser popup that can be found in the toolbar.

I also had a crash at one point in time where some brush presets got
changed around in master and clicking some resources in the brush preset
box crashed the program, but I was not able to reproduce that after a
clean rebuild of my local workspace and changing presets around
externally, so it might not be an issue, but I'm including it for
completeness sake.

M  +1    -5    krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.cpp
M  +0    -1    krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.h
M  +0    -13   krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.cpp
M  +0    -1    krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.h
M  +4    -29   krita/ui/forms/wdgpaintoppresets.ui
M  +0    -11   krita/ui/kis_config.cc
M  +0    -3    krita/ui/kis_config.h
M  +0    -1    krita/ui/kis_paintop_box.cc
M  +9    -5    krita/ui/kis_palette_manager.cpp
M  +2    -37   krita/ui/widgets/kis_paintop_presets_chooser_popup.cpp
M  +0    -8    krita/ui/widgets/kis_paintop_presets_chooser_popup.h
M  +16   -135  krita/ui/widgets/kis_preset_chooser.cpp
M  +3    -9    krita/ui/widgets/kis_preset_chooser.h
M  +0    -7    krita/ui/widgets/kis_preset_selector_strip.cpp
M  +1    -0    libs/widgets/CMakeLists.txt
A  +199  -0    libs/widgets/KoResourceFiltering.cpp     [License: LGPL (v2+)]
A  +61   -0    libs/widgets/KoResourceFiltering.h     [License: LGPL (v2+)]
M  +325  -98   libs/widgets/KoResourceItemChooser.cpp
M  +41   -9    libs/widgets/KoResourceItemChooser.h
M  +9    -2    libs/widgets/KoResourceItemView.cpp
M  +7    -6    libs/widgets/KoResourceItemView.h
M  +25   -10   libs/widgets/KoResourceModel.cpp
M  +3    -1    libs/widgets/KoResourceModel.h
M  +5    -0    libs/widgets/KoResourceServer.h
M  +62   -26   libs/widgets/KoResourceServerAdapter.h

http://commits.kde.org/calligra/a86b7b848a4a93ffc7ab427aa70827e410d40e64

diff --git a/krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.cpp b/krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.cpp
index 08466cf..dc9effe 100644
--- a/krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.cpp
+++ b/krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.cpp
@@ -39,12 +39,8 @@ void PresetDockerDock::setCanvas(KoCanvasBase * canvas)
 
     m_canvas = canvas;
     
-    connect(m_canvas->resourceManager(), SIGNAL(resourceChanged(int, const QVariant&)),
-            this, SLOT(resourceChanged(int, const QVariant&)));
 }
 
-void PresetDockerDock::resourceChanged(int key, const QVariant& v)
-{
-}
+
 
 #include "presetdocker_dock.moc"
diff --git a/krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.h b/krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.h
index 43fe4e3..6af6246 100644
--- a/krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.h
+++ b/krita/plugins/extensions/dockers/dockerplugintemplate/presetdocker_dock.h
@@ -34,7 +34,6 @@ public:
     virtual void setCanvas(KoCanvasBase *canvas);
     virtual void unsetCanvas() { m_canvas = 0; }
 public slots:
-    void resourceChanged(int, const QVariant&);
 private slots:
 private:
     KoCanvasBase* m_canvas;
diff --git a/krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.cpp b/krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.cpp
index 097ebd3..648746a 100644
--- a/krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.cpp
+++ b/krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.cpp
@@ -54,21 +54,8 @@ void PresetDockerDock::setCanvas(KoCanvasBase * canvas)
     Q_ASSERT(m_canvas);
     if (!m_canvas) return;
 
-    connect(m_canvas->resourceManager(), SIGNAL(resourceChanged(int, const QVariant&)),
-           this, SLOT(resourceChanged(int, const QVariant&)));
-
     connect(m_presetChooser, SIGNAL(resourceSelected(KoResource*)),
             m_canvas->view()->paintOpBox(), SLOT(resourceSelected(KoResource*)));
 }
 
-void PresetDockerDock::resourceChanged(int /*key*/, const QVariant& /*v*/)
-{
-    if (m_canvas) {
-        KisPaintOpPresetSP preset = m_canvas->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value<KisPaintOpPresetSP>();
-        if (preset) {
-            m_presetChooser->setPresetFilter(preset->paintOp());
-        }
-    }
-}
-
 #include "presetdocker_dock.moc"
diff --git a/krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.h b/krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.h
index 2a92777..7ec72ff 100644
--- a/krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.h
+++ b/krita/plugins/extensions/dockers/presetdocker/presetdocker_dock.h
@@ -32,7 +32,6 @@ public:
     virtual void setCanvas(KoCanvasBase *canvas);
     virtual void unsetCanvas() { m_canvas = 0; }
 public slots:
-    void resourceChanged(int, const QVariant&);
 private slots:
 private:
     KisCanvas2* m_canvas;
diff --git a/krita/ui/forms/wdgpaintoppresets.ui b/krita/ui/forms/wdgpaintoppresets.ui
index c2560a5..bb95281 100644
--- a/krita/ui/forms/wdgpaintoppresets.ui
+++ b/krita/ui/forms/wdgpaintoppresets.ui
@@ -18,28 +18,15 @@
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
-    <layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1,0" columnminimumwidth="0,0,0">
-     <item row="0" column="0">
-      <widget class="KLineEdit" name="searchBar">
-       <property name="clickMessage">
-        <string>Search Preset</string>
-       </property>
-       <property name="showClearButton" stdset="0">
-        <bool>true</bool>
-       </property>
-      </widget>
-     </item>
+    <layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0">
      <item row="0" column="1">
-      <widget class="QCheckBox" name="showAllCheckBox">
+      <widget class="QToolButton" name="viewModeButton">
        <property name="text">
-        <string>Show all</string>
-       </property>
-       <property name="checked">
-        <bool>true</bool>
+        <string>...</string>
        </property>
       </widget>
      </item>
-     <item row="1" column="0" colspan="3">
+     <item row="1" column="0" colspan="2">
       <widget class="KisPresetChooser" name="wdgPresetChooser" native="true">
        <property name="sizePolicy">
         <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
@@ -55,24 +42,12 @@
        </property>
       </widget>
      </item>
-     <item row="0" column="2">
-      <widget class="QToolButton" name="viewModeButton">
-       <property name="text">
-        <string>...</string>
-       </property>
-      </widget>
-     </item>
     </layout>
    </item>
   </layout>
  </widget>
  <customwidgets>
   <customwidget>
-   <class>KLineEdit</class>
-   <extends>QLineEdit</extends>
-   <header>klineedit.h</header>
-  </customwidget>
-  <customwidget>
    <class>KisPresetChooser</class>
    <extends>QWidget</extends>
    <header>widgets/kis_preset_chooser.h</header>
diff --git a/krita/ui/kis_config.cc b/krita/ui/kis_config.cc
index ae51c5c..c6e50da 100644
--- a/krita/ui/kis_config.cc
+++ b/krita/ui/kis_config.cc
@@ -736,17 +736,6 @@ void KisConfig::setPresetChooserViewMode(const int mode)
     m_cfg.writeEntry("presetChooserViewMode", mode);
 }
 
-
-bool KisConfig::presetShowAllMode() const
-{
-    return m_cfg.readEntry("presetChooserShowAllPresets", true);
-}
-
-void KisConfig::setPresetShowAllMode(bool showAll)
-{
-    m_cfg.writeEntry("presetChooserShowAllPresets", showAll);
-}
-
 bool KisConfig::firstRun() const
 {
     return m_cfg.readEntry("firstRun", true);
diff --git a/krita/ui/kis_config.h b/krita/ui/kis_config.h
index aaa1b3d..dace8b7 100644
--- a/krita/ui/kis_config.h
+++ b/krita/ui/kis_config.h
@@ -230,9 +230,6 @@ public:
     int presetChooserViewMode() const;
     void setPresetChooserViewMode(const int mode);
 
-    bool presetShowAllMode() const;
-    void setPresetShowAllMode(bool showAll);
-
     bool firstRun() const;
     void setFirstRun(const bool firstRun) const;
 
diff --git a/krita/ui/kis_paintop_box.cc b/krita/ui/kis_paintop_box.cc
index 17cf40b..61c0d12 100644
--- a/krita/ui/kis_paintop_box.cc
+++ b/krita/ui/kis_paintop_box.cc
@@ -372,7 +372,6 @@ void KisPaintopBox::setCurrentPaintop(const KoID& paintop, KisPaintOpPresetSP pr
     m_optionWidget->setConfiguration(preset->settings());
 
     m_presetsPopup->setPaintOpSettingsWidget(m_optionWidget);
-    m_presetsChooserPopup->setPresetFilter(paintop);
 
     Q_ASSERT(m_optionWidget && m_presetWidget);
     connect(m_optionWidget, SIGNAL(sigConfigurationUpdated()), this, SLOT(slotUpdatePreset()));
diff --git a/krita/ui/kis_palette_manager.cpp b/krita/ui/kis_palette_manager.cpp
index 326590d..568859a 100644
--- a/krita/ui/kis_palette_manager.cpp
+++ b/krita/ui/kis_palette_manager.cpp
@@ -67,14 +67,12 @@ KisPaletteManager::KisPaletteManager(KoFavoriteResourceManager *manager, KisPain
     m_allPresetsView = new KisPresetChooser(this);
     m_allPresetsView->showButtons(false);
     m_allPresetsView->showTaggingBar(false,false);
-    m_allPresetsView->setPresetFilter(KoID("dummy",""));
-    m_allPresetsView->setShowAll(true);
+    m_allPresetsView->enableContextMenu(false);
 
     m_palettePresetsView = new KisPresetChooser(this);
     m_palettePresetsView->showButtons(false);
     m_palettePresetsView->showTaggingBar(false,false);
-    m_palettePresetsView->setPresetFilter(KoID("dummy",""));
-    m_palettePresetsView->setShowAll(true);
+    m_palettePresetsView->enableContextMenu(false);
 
     /*LEFT COMPONENTS*/
     QFrame *HSeparator = new QFrame();
@@ -211,7 +209,13 @@ void KisPaletteManager::showEvent(QShowEvent* e)
 
 void KisPaletteManager::updatePaletteView()
 {
-    m_palettePresetsView->setFilteredNames(m_resourceManager->favoritePresetList());
+    QStringList faves = m_resourceManager->favoritePresetList();
+    // this filters all the resources, making the view empty
+    // the palette view is a special case that basically uses all presets
+    // by virtue of using kis_preset_chooser even though it's only interested
+    // in up to ten of them. not sure if that warrants an 'empty' mode somewhere.
+    if (faves.isEmpty())faves.push_back("!!!!!!");
+    m_palettePresetsView->setFilteredNames(faves);
 }
 
 void KisPaletteManager::slotThumbnailMode()
diff --git a/krita/ui/widgets/kis_paintop_presets_chooser_popup.cpp b/krita/ui/widgets/kis_paintop_presets_chooser_popup.cpp
index 9f5a7f8..078c572 100644
--- a/krita/ui/widgets/kis_paintop_presets_chooser_popup.cpp
+++ b/krita/ui/widgets/kis_paintop_presets_chooser_popup.cpp
@@ -45,7 +45,6 @@ KisPaintOpPresetsChooserPopup::KisPaintOpPresetsChooserPopup(QWidget * parent)
     QActionGroup *actionGroup = new QActionGroup(this);
 
     KisPresetChooser::ViewMode mode = (KisPresetChooser::ViewMode)KisConfig().presetChooserViewMode();
-    bool showAll = KisConfig().presetShowAllMode();
 
     QAction* action = menu->addAction(koIcon("view-preview"), i18n("Thumbnails"), this, SLOT(slotThumbnailMode()));
     action->setCheckable(true);
@@ -61,38 +60,20 @@ KisPaintOpPresetsChooserPopup::KisPaintOpPresetsChooserPopup(QWidget * parent)
     m_d->uiWdgPaintOpPresets.viewModeButton->setMenu(menu);
     m_d->uiWdgPaintOpPresets.viewModeButton->setPopupMode(QToolButton::InstantPopup);
     m_d->uiWdgPaintOpPresets.wdgPresetChooser->setViewMode(mode);
-    m_d->uiWdgPaintOpPresets.wdgPresetChooser->showTaggingBar(false,true);
+    m_d->uiWdgPaintOpPresets.wdgPresetChooser->showTaggingBar(true,true);
 
     connect(m_d->uiWdgPaintOpPresets.wdgPresetChooser, SIGNAL(resourceSelected(KoResource*)),
             this, SIGNAL(resourceSelected(KoResource*)));
-
-    connect(m_d->uiWdgPaintOpPresets.searchBar, SIGNAL(textChanged(QString)),
-            m_d->uiWdgPaintOpPresets.wdgPresetChooser, SLOT(searchTextChanged(QString)));
-
-    connect(m_d->uiWdgPaintOpPresets.searchBar, SIGNAL(textChanged(QString)),
-                this, SLOT(setLineEditCompleter(QString)));
-
-    connect(m_d->uiWdgPaintOpPresets.searchBar, SIGNAL(returnPressed(QString)),
-                this, SLOT(returnKeyPressed(QString)));
-
-    connect(m_d->uiWdgPaintOpPresets.showAllCheckBox, SIGNAL(toggled(bool)),
-            m_d->uiWdgPaintOpPresets.wdgPresetChooser, SLOT(setShowAll(bool)));
+    
     m_d->firstShown = true;
 
-    m_d->uiWdgPaintOpPresets.showAllCheckBox->setChecked(showAll);
 }
 
 KisPaintOpPresetsChooserPopup::~KisPaintOpPresetsChooserPopup()
 {
-    KisConfig().setPresetShowAllMode(m_d->uiWdgPaintOpPresets.showAllCheckBox->isChecked());
     delete m_d;
 }
 
-void KisPaintOpPresetsChooserPopup::setPresetFilter(const KoID& paintopID)
-{
-    m_d->uiWdgPaintOpPresets.wdgPresetChooser->setPresetFilter(paintopID);
-}
-
 void KisPaintOpPresetsChooserPopup::slotThumbnailMode()
 {
     KisConfig().setPresetChooserViewMode(KisPresetChooser::THUMBNAIL);
@@ -115,22 +96,6 @@ void KisPaintOpPresetsChooserPopup::paintEvent(QPaintEvent* event)
     }
 }
 
-void KisPaintOpPresetsChooserPopup::setLineEditCompleter(const QString& searchString)
-{
-    QCompleter* tagCompleter = new QCompleter(m_d->uiWdgPaintOpPresets.wdgPresetChooser->getTagNamesList(searchString),this);
-    m_d->uiWdgPaintOpPresets.searchBar->setCompleter(tagCompleter);
-}
-
-void KisPaintOpPresetsChooserPopup::returnKeyPressed(QString lineEditText)
-{
-    m_d->uiWdgPaintOpPresets.wdgPresetChooser->returnKeyPressed(lineEditText);
-    if(!lineEditText.endsWith(", ")) {
-        lineEditText.append(", ");
-    }
-    m_d->uiWdgPaintOpPresets.searchBar->setText(lineEditText);
-    setLineEditCompleter(lineEditText);
-}
-
 void KisPaintOpPresetsChooserPopup::showButtons(bool show)
 {
     m_d->uiWdgPaintOpPresets.wdgPresetChooser->showButtons(show);
diff --git a/krita/ui/widgets/kis_paintop_presets_chooser_popup.h b/krita/ui/widgets/kis_paintop_presets_chooser_popup.h
index 69880ee..b0c9af7 100644
--- a/krita/ui/widgets/kis_paintop_presets_chooser_popup.h
+++ b/krita/ui/widgets/kis_paintop_presets_chooser_popup.h
@@ -34,10 +34,6 @@ public:
     KisPaintOpPresetsChooserPopup(QWidget * parent = 0);
     virtual ~KisPaintOpPresetsChooserPopup();
     
-    ///Set id for paintop to be accept by the proxy model
-    ///@param paintopID id of the paintop for which the presets will be shown
-    void setPresetFilter(const KoID & paintopID);
-
     void showButtons(bool show);
 signals:
     void resourceSelected( KoResource * resource );
@@ -45,10 +41,6 @@ signals:
 private slots:
     void slotThumbnailMode();
     void slotDetailMode();
-    /// Passes the lineEdit text to the preset Chooser when a returnPressed signal is generated
-    void returnKeyPressed(QString lineEditText);
-    /// Sets the lineEdit so that it can search for multiple tags like "round, circle, "
-    void setLineEditCompleter(const QString& searchString);
     virtual void paintEvent(QPaintEvent* );
    
 private:
diff --git a/krita/ui/widgets/kis_preset_chooser.cpp b/krita/ui/widgets/kis_preset_chooser.cpp
index 01f1b7b..9f07c8a 100644
--- a/krita/ui/widgets/kis_preset_chooser.cpp
+++ b/krita/ui/widgets/kis_preset_chooser.cpp
@@ -38,6 +38,8 @@
 #include <KoResourceModel.h>
 #include <KoResourceServerAdapter.h>
 
+#include <KoResourceFiltering.h>
+
 #include "kis_paintop_settings.h"
 #include "kis_paintop_preset.h"
 #include "kis_resource_server_provider.h"
@@ -109,100 +111,6 @@ void KisPresetDelegate::paint(QPainter * painter, const QStyleOptionViewItem & o
     painter->restore();
 }
 
-class KisPresetProxyAdapter : public KoResourceServerAdapter<KisPaintOpPreset>
-{
-    static bool compareKoResources(const KoResource* a, const KoResource* b)
-    {
-        return a->name() < b->name();
-    }
-
-public:
-    KisPresetProxyAdapter(KoResourceServer< KisPaintOpPreset >* resourceServer)
-        : KoResourceServerAdapter<KisPaintOpPreset>(resourceServer), m_filterNames(false)
-    {
-        m_showAll = KisConfig().presetShowAllMode();
-    }
-    virtual ~KisPresetProxyAdapter() {}
-
-    virtual QList< KoResource* > resources() {
-        if( ! resourceServer() )
-            return QList<KoResource*>();
-
-        QList<KisPaintOpPreset*> serverResources = resourceServer()->resources();
-
-        QList<KoResource*> resources;
-        foreach( KisPaintOpPreset* resource, serverResources ) {
-            if(filterAcceptsPreset(resource) || (m_filterNames && m_filteredNames.contains(resource->filename())) ) {
-                resources.append( resource );
-            }
-        }
-
-        qSort(resources.begin(), resources.end(), KisPresetProxyAdapter::compareKoResources);
-        return resources;
-    }
-
-    bool filterAcceptsPreset(KisPaintOpPreset* preset) const
-    {
-        if(m_paintopID.id().isEmpty())
-            return true;
-
-        return ((preset->paintOp() == m_paintopID || m_showAll) &&
-                preset->name().contains(m_nameFilter, Qt::CaseInsensitive) &&
-                (!m_filterNames || m_filteredNames.contains(preset->name())));
-    }
-
-    ///Set id for paintop to be accept by the proxy model, if not filter is set all
-    ///presets will be shown.
-    void setPresetFilter(const KoID &paintopID)
-    {
-        m_paintopID = paintopID;
-    }
-
-    KoID presetFilter()
-    {
-        return m_paintopID;
-    }
-
-    /// Set a filter for preset name, only presets with name containing the string will be shown
-    void setPresetNameFilter(const QString &nameFilter)
-    {
-        m_nameFilter = nameFilter;
-    }
-
-    void setFilteredNames(const QStringList filteredNames)
-    {
-        m_filteredNames = filteredNames;
-    }
-
-    void setFilterNames(bool filterNames)
-    {
-        m_filterNames = filterNames;
-    }
-
-    void setShowAll(bool show)
-    {
-        m_showAll = show;
-    }
-
-    bool showAll()
-    {
-        return m_showAll;
-    }
-
-
-    ///Resets the model connected to the adapter
-    void invalidate() {
-        emitRemovingResource(0);
-    }
-
-private:
-    KoID m_paintopID;
-    QString m_nameFilter;
-    bool m_showAll;
-    bool m_filterNames;
-    QStringList m_filteredNames;
-};
-
 KisPresetChooser::KisPresetChooser(QWidget *parent, const char *name)
     : QWidget(parent)
 {
@@ -210,8 +118,10 @@ KisPresetChooser::KisPresetChooser(QWidget *parent, const char *name)
     QVBoxLayout * layout = new QVBoxLayout(this);
     layout->setMargin(0);
     KoResourceServer<KisPaintOpPreset> * rserver = KisResourceServerProvider::instance()->paintOpPresetServer();
-    m_presetProxy = new KisPresetProxyAdapter(rserver);
-    m_chooser = new KoResourceItemChooser(m_presetProxy, this);
+
+    m_adapter = new KoResourceServerAdapter<KisPaintOpPreset>(rserver);
+
+    m_chooser = new KoResourceItemChooser(m_adapter, this);
     QString knsrcFile = "kritapresets.knsrc";
     m_chooser->setKnsrcFile(knsrcFile);
     m_chooser->showGetHotNewStuff(true, true);
@@ -232,39 +142,12 @@ KisPresetChooser::~KisPresetChooser()
 {
 }
 
-void KisPresetChooser::setPresetFilter(const KoID& paintopID)
-{
-    KoID oldFilter = m_presetProxy->presetFilter();
-    m_presetProxy->setPresetFilter(paintopID);
-    if(oldFilter.id() != paintopID.id() && !m_presetProxy->showAll()) {
-        m_presetProxy->invalidate();
-        updateViewSettings();
-    }
-}
-
 void KisPresetChooser::setFilteredNames(const QStringList filteredNames)
 {
-    m_presetProxy->setFilterNames(true);
-    m_presetProxy->setFilteredNames(filteredNames);
-    m_presetProxy->invalidate();
-    updateViewSettings();
-}
-
-void KisPresetChooser::searchTextChanged(const QString& searchString)
-{
-    if(searchString.isEmpty()) {
-        m_presetProxy->setFilterNames(false);
-    }
-    m_presetProxy->setPresetNameFilter(searchString);
-    m_presetProxy->invalidate();
-    updateViewSettings();
-}
+    m_adapter->setTaggedResourceFileNames(filteredNames);
+    m_adapter->enableResourceFiltering(true);
+    m_adapter->updateServer();
 
-void KisPresetChooser::returnKeyPressed(QString lineEditText)
-{
-    m_presetProxy->setFilterNames(true);
-    m_presetProxy->setFilteredNames(m_chooser->getTaggedResourceFileNames(lineEditText));
-    m_presetProxy->invalidate();
     updateViewSettings();
 }
 
@@ -273,13 +156,6 @@ QStringList KisPresetChooser::getTagNamesList(const QString& searchString)
     return m_chooser->getTagNamesList(searchString);
 }
 
-void KisPresetChooser::setShowAll(bool show)
-{
-    m_presetProxy->setShowAll(show);
-    m_presetProxy->invalidate();
-    updateViewSettings();
-}
-
 void KisPresetChooser::showButtons(bool show)
 {
     m_chooser->showButtons(show);
@@ -300,7 +176,7 @@ void KisPresetChooser::resizeEvent(QResizeEvent* event)
 void KisPresetChooser::updateViewSettings()
 {
     if (m_mode == THUMBNAIL) {
-        int resourceCount = m_presetProxy->resources().count();
+        int resourceCount = m_adapter->resources().count();
         int width = m_chooser->viewSize().width();
         int maxColums = width/50;
         int cols = width/100 + 1;
@@ -324,7 +200,6 @@ void KisPresetChooser::updateViewSettings()
         m_chooser->setColumnWidth(m_chooser->viewSize().height() - 7);
         m_delegate->setShowText(false);
     }
-
 }
 
 KoResource* KisPresetChooser::currentResource()
@@ -342,5 +217,11 @@ KoResourceItemChooser *KisPresetChooser::itemChooser()
     return m_chooser;
 }
 
+void KisPresetChooser::enableContextMenu(bool enable)
+{
+    m_chooser->enableContextMenu(enable);
+}
+
+
 #include "kis_preset_chooser.moc"
 
diff --git a/krita/ui/widgets/kis_preset_chooser.h b/krita/ui/widgets/kis_preset_chooser.h
index 0433173..5df3b56 100644
--- a/krita/ui/widgets/kis_preset_chooser.h
+++ b/krita/ui/widgets/kis_preset_chooser.h
@@ -24,8 +24,8 @@
 #include <krita_export.h>
 #include <KoID.h>
 
+class KoAbstractResourceServerAdapter;
 class KisPresetDelegate;
-class KisPresetProxyAdapter;
 class KoResourceItemChooser;
 class KoResource;
 
@@ -48,10 +48,6 @@ public:
         DETAIL,  /// Shows thumbsnails with text next to it
         STRIP  /// Shows thumbnails arranged in a single row
     };
-    
-    ///Set id for paintop to be accept by the proxy model
-    ///@param paintopID id of the paintop for which the presets will be shown
-    void setPresetFilter(const KoID & paintopID);
 
     /// Set a list of preset names for resources that should be show, others will be hidden
     /// Turns on name filter mode
@@ -60,13 +56,13 @@ public:
     /// get tag names and used to set Completer object in paintop_presets_popup class
     QStringList getTagNamesList(const QString& searchString);
     /// Sets a list of resources in the paintop list, when ever user press enter in the linedit of paintop_presets_popup Class
-    void returnKeyPressed(QString lineEditText);
     void setViewMode(ViewMode mode);
     void showButtons(bool show);
     
     KoResource* currentResource();
     /// Sets the visibility of tagging klineEdits
     void showTaggingBar( bool showSearchBar, bool showOpBar );
+    void enableContextMenu(bool enable);
 
 
     KoResourceItemChooser *itemChooser();
@@ -75,8 +71,6 @@ signals:
     void resourceSelected(KoResource * resource);
     
 public slots:
-    void searchTextChanged(const QString& searchString);
-    void setShowAll(bool show);
     void updateViewSettings();
     
 protected:
@@ -84,9 +78,9 @@ protected:
     
 private:
     KoResourceItemChooser *m_chooser;
-    KisPresetProxyAdapter *m_presetProxy;
     KisPresetDelegate* m_delegate;
     ViewMode m_mode;
+    KoAbstractResourceServerAdapter * m_adapter;
 };
 
 #endif // KIS_ITEM_CHOOSER_H_
diff --git a/krita/ui/widgets/kis_preset_selector_strip.cpp b/krita/ui/widgets/kis_preset_selector_strip.cpp
index 068c745..4eddfc4 100644
--- a/krita/ui/widgets/kis_preset_selector_strip.cpp
+++ b/krita/ui/widgets/kis_preset_selector_strip.cpp
@@ -45,7 +45,6 @@ KisPresetSelectorStrip::KisPresetSelectorStrip(QWidget* parent)
     /* This is an heuristic to fill smallPresetChooser with only the presets
      * for the paintop that comes selected by default: Pixel Brush. */
     const QString PIXEL_BRUSH_ID = "paintbrush";
-    smallPresetChooser->setPresetFilter(KoID(PIXEL_BRUSH_ID));
 
     deletePresetBtn->setIcon(koIcon("trash-empty"));
     deletePresetBtn->setVisible(true);
@@ -70,12 +69,6 @@ void KisPresetSelectorStrip::showEvent(QShowEvent* event)
 
 void KisPresetSelectorStrip::currentPaintopChanged(QString paintOpID)
 {
-    foreach (const KoID &paintOp, KisPaintOpRegistry::instance()->listKeys()) {
-        if (paintOp.id() == paintOpID) {
-            smallPresetChooser->setPresetFilter(paintOp);
-            break;
-        }
-    }
     deletePresetBtn->hide();
 }
 
diff --git a/libs/widgets/CMakeLists.txt b/libs/widgets/CMakeLists.txt
index 4e6e362..2106d3f 100644
--- a/libs/widgets/CMakeLists.txt
+++ b/libs/widgets/CMakeLists.txt
@@ -66,6 +66,7 @@ set(kowidgets_LIB_SRCS
     KoDockWidgetTitleBarButton.cpp
     KoViewItemContextBar.cpp
     KoContextBarButton.cpp
+    KoResourceFiltering.cpp
 
 )
 
diff --git a/libs/widgets/KoResourceFiltering.cpp b/libs/widgets/KoResourceFiltering.cpp
new file mode 100644
index 0000000..f564210
--- /dev/null
+++ b/libs/widgets/KoResourceFiltering.cpp
@@ -0,0 +1,199 @@
+/*  This file is part of the KDE project
+
+    Copyright (C) 2013 Sascha Suelzer <s.suelzer at lavabit.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "KoResourceFiltering.h"
+#include "KoResourceTagging.h"
+
+class KoResourceFiltering::Private
+{
+public:
+    Private()
+    : m_isTag("\\[([\\w\\s]+)\\]")
+    , m_isExactMatch("\"([\\w\\s]+)\"")
+    , m_searchTokenizer("\\s*,+\\s*")
+    , m_hasNewFilters(false)
+    {}
+    bool m_hasNewFilters;
+    QRegExp m_isTag;
+    QRegExp m_isExactMatch;
+    QRegExp m_searchTokenizer;
+    QStringList m_rootTagList;
+    QStringList m_includedNames;
+    QStringList m_excludedNames;
+
+};
+
+KoResourceFiltering::KoResourceFiltering() : d(new Private())
+{}
+
+KoResourceFiltering::~KoResourceFiltering()
+{
+    delete d;
+}
+void KoResourceFiltering::setChanged()
+{
+    d->m_hasNewFilters = true;
+}
+
+void KoResourceFiltering::setRootResourceFilenames(QStringList tag)
+{
+    d->m_rootTagList = tag;
+    d->m_excludedNames.clear();
+    d->m_includedNames.clear();
+    setChanged();
+}
+
+bool KoResourceFiltering::matchesResource(QString &resourceName, QString &resourceFileName,const QStringList &filterList) const
+{
+    Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
+    foreach (QString filter, filterList) {
+        if (!filter.startsWith("\"")) {
+        if (resourceName.contains(filter,sensitivity) || resourceFileName.contains(filter,sensitivity))
+            return true;
+        }
+        else {
+            filter = filter.replace("\"","");
+            if (!resourceName.compare(filter)) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void KoResourceFiltering::sanitizeExclusionList()
+{
+   if(!d->m_includedNames.isEmpty()) {
+
+        foreach (QString exclusion, d->m_excludedNames) {
+            if (!excludeFilterIsValid(exclusion))
+                d->m_excludedNames.removeAll(exclusion);
+        }
+    }
+}
+
+QStringList KoResourceFiltering::tokenizeSearchString(const QString searchString)
+{
+    return searchString.split(d->m_searchTokenizer, QString::SkipEmptyParts);
+}
+
+void KoResourceFiltering::populateIncludeExcludeFilters(const QStringList& filteredNames, KoResourceTagging* tagObject)
+{
+    foreach (QString name, filteredNames) {
+        QStringList* target;
+
+        if(name.startsWith("!")) {
+            name.remove("!");
+            target = &d->m_excludedNames;
+        } else {
+            target = &d->m_includedNames;
+        }
+
+        if(!name.isEmpty()) {
+            if (name.startsWith("[")) {
+                if (d->m_isTag.exactMatch(name) && tagObject) {
+                    name = d->m_isTag.cap(1);
+                    (*target) += tagObject->searchTag(name);
+                }
+            }
+            else if (name.startsWith("\"")) {
+                if (d->m_isExactMatch.exactMatch(name)) {
+                    target->push_back(name);
+                }
+            }
+            else {
+                target->push_back(name);
+            }
+        }
+    }
+    sanitizeExclusionList();
+}
+
+bool KoResourceFiltering::hasFilters()
+{
+    return (!d->m_rootTagList.isEmpty() || !d->m_includedNames.isEmpty() || !d->m_excludedNames.isEmpty());
+}
+
+bool KoResourceFiltering::filtersHaveChanged()
+{
+    return d->m_hasNewFilters;
+}
+
+void KoResourceFiltering::setFilters(const QString &searchString, KoResourceTagging * tagObject)
+{
+    d->m_excludedNames.clear();
+    d->m_includedNames.clear();
+    QStringList filteredNames = tokenizeSearchString(searchString);
+    populateIncludeExcludeFilters(filteredNames,tagObject);
+    setChanged();
+}
+
+bool KoResourceFiltering::presetMatchesSearch(KoResource * resource) const
+{
+
+    QString resourceName = resource->name();
+    QString resourceFileName = resource->filename();
+    if (matchesResource(resourceName,resourceFileName,d->m_excludedNames))
+        return false;
+    if (matchesResource(resourceName,resourceFileName,d->m_includedNames))
+        return true;
+    foreach (QString filter, d->m_rootTagList) {
+        if (!resourceFileName.compare(filter) || !resourceName.compare(filter))
+            return true;
+    }
+    return false;
+}
+void KoResourceFiltering::setInclusions(QStringList inclusions)
+{
+    d->m_includedNames = inclusions;
+    setChanged();
+}
+void KoResourceFiltering::setExclusions(QStringList exclusions)
+{
+    d->m_excludedNames = exclusions;
+    setChanged();
+}
+
+bool KoResourceFiltering::excludeFilterIsValid(const QString &exclusion)
+{
+    foreach(QString inclusion, d->m_includedNames) {
+        if ((inclusion.startsWith(exclusion)  && exclusion.size() <= inclusion.size())) {
+            return false;
+        }
+    }
+    return true;
+}
+QList< KoResource* > KoResourceFiltering::filterResources(QList< KoResource* > resources)
+{
+
+    foreach(KoResource* resource, resources) {
+        if(!presetMatchesSearch(resource)) {
+            resources.removeAll(resource);
+        }
+    }
+    setDoneFiltering();
+    return resources;
+
+}
+
+void KoResourceFiltering::setDoneFiltering()
+{
+    d->m_hasNewFilters = false;
+}
+
diff --git a/libs/widgets/KoResourceFiltering.h b/libs/widgets/KoResourceFiltering.h
new file mode 100644
index 0000000..9f8f967
--- /dev/null
+++ b/libs/widgets/KoResourceFiltering.h
@@ -0,0 +1,61 @@
+
+/*  This file is part of the KDE project
+
+    Copyright (C) 2013 Sascha Suelzer <s.suelzer at lavabit.com>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef KORESOURCEFILTER_H
+#define KORESOURCEFILTER_H
+
+#include <QStringList>
+#include <QString>
+
+#include "KoResource.h"
+
+#include "kowidgets_export.h"
+
+class KoResourceTagging;
+
+class KOWIDGETS_EXPORT KoResourceFiltering
+{
+
+public:
+    KoResourceFiltering();
+    virtual ~KoResourceFiltering();
+    bool hasFilters();
+    bool filtersHaveChanged();
+    void setRootResourceFilenames(QStringList tag);
+    void setFilters(const QString& searchString, KoResourceTagging* tagObject);
+    QList<KoResource*> filterResources(QList<KoResource*> resources);
+
+private:
+    void setInclusions(QStringList inclusions);
+    void setExclusions(QStringList exclusions);
+    void setDoneFiltering();
+    bool presetMatchesSearch(KoResource * resource) const;
+    void setChanged();
+    bool excludeFilterIsValid(const QString &exclusion);
+    bool matchesResource(QString &resourceName, QString &resourceFileName,const QStringList &filterList) const;
+    void populateIncludeExcludeFilters(const QStringList& filteredNames, KoResourceTagging* tagObject);
+    void sanitizeExclusionList();
+    QStringList tokenizeSearchString(const QString searchString);
+    class Private;
+    Private * const d;
+
+};
+
+#endif // KORESOURCEFILTER_H
diff --git a/libs/widgets/KoResourceItemChooser.cpp b/libs/widgets/KoResourceItemChooser.cpp
index 61273fe..a2750b5 100644
--- a/libs/widgets/KoResourceItemChooser.cpp
+++ b/libs/widgets/KoResourceItemChooser.cpp
@@ -34,11 +34,15 @@
 #include <QPainter>
 #include <QToolButton>
 #include <QSplitter>
+#include <QInputDialog>
+#include <QMenu>
+#include <QMessageBox>
 
 #include <kfiledialog.h>
 #include <klocale.h>
 #include <kdebug.h>
 #include <klineedit.h>
+#include <kcombobox.h>
 
 
 #ifdef GHNS
@@ -55,20 +59,45 @@
 #include "KoResourceModel.h"
 #include "KoResource.h"
 
+ContextMenuTagAction::ContextMenuTagAction(KoResource* resource, QString tag, QObject* parent)
+: QAction(parent)
+, m_resource(resource)
+, m_tag(tag)
+{
+    setText(tag);
+    connect (this, SIGNAL(triggered()),
+             this, SLOT(onTriggered()));
+}
+
+ContextMenuTagAction::~ContextMenuTagAction()
+{
+}
+
+void ContextMenuTagAction::onTriggered()
+{
+    emit triggered(m_resource,m_tag);
+}
+
+
+
 class KoResourceItemChooser::Private
 {
 public:
+    enum TagButtons { Button_AddTag, Button_RemoveTag };
     Private()
         : model(0)
         , view(0)
         , buttonGroup(0)
         , tiledPreview(false)
         , grayscalePreview(false)
+        , showContextMenu(true)
     {}
     KoResourceModel* model;
     KoResourceItemView* view;
     QButtonGroup* buttonGroup;
-    KLineEdit *tagSearchLineEdit, *tagOpLineEdit;
+    QButtonGroup* tagButtonGroup;
+    KLineEdit *tagSearchLineEdit;
+    KComboBox *tagOpComboBox;
     QString knsrcFile;
     QCompleter *tagCompleter;
     QScrollArea *previewScroller;
@@ -76,6 +105,10 @@ public:
     QSplitter *splitter;
     bool tiledPreview;
     bool grayscalePreview;
+    bool showContextMenu;
+    QString currentTag;
+    QList<KoResource*> originalResources;
+
 };
 
 KoResourceItemChooser::KoResourceItemChooser(KoAbstractResourceServerAdapter * resourceAdapter, QWidget *parent )
@@ -92,6 +125,8 @@ KoResourceItemChooser::KoResourceItemChooser(KoAbstractResourceServerAdapter * r
 
     connect(d->view, SIGNAL(currentResourceChanged( const QModelIndex &)),
             this, SLOT(activated(const QModelIndex &)));
+    connect (d->view, SIGNAL(contextMenuRequested(const QPoint &)),
+             this, SLOT(contextMenuRequested(const QPoint &)));
 
     d->previewScroller = new QScrollArea(this);
     d->previewScroller->setWidgetResizable(true);
@@ -108,18 +143,54 @@ KoResourceItemChooser::KoResourceItemChooser(KoAbstractResourceServerAdapter * r
     d->buttonGroup = new QButtonGroup( this );
     d->buttonGroup->setExclusive( false );
 
-    d->tagSearchLineEdit = new KLineEdit(this);
-    d->tagSearchLineEdit->setClearButtonShown(true);
-    d->tagSearchLineEdit->setClickMessage("Enter search tag here");
-    d->tagSearchLineEdit->setEnabled( true );
-    d->tagSearchLineEdit->hide();
+    d->tagButtonGroup = new QButtonGroup( this );
+    d->tagButtonGroup->setExclusive( false );
 
-    connect( d->tagSearchLineEdit, SIGNAL(returnPressed(QString)), this, SLOT(tagSearchLineEditActivated(QString)));
-    connect( d->tagSearchLineEdit, SIGNAL(textChanged(QString)), this, SLOT(tagSearchLineEditTextChanged(QString)));
+    d->tagOpComboBox = new KComboBox( this );
+    d->tagOpComboBox->setInsertPolicy(KComboBox::NoInsert);
+    d->tagOpComboBox->setEnabled( true );
+    d->tagOpComboBox->hide();
+
+    addTagToComboBox(i18n("Unfiltered View"),false);
+
+    QStringList tagNames = d->model->getTagNamesList();
+    foreach (QString tagName, tagNames) {
+        addTagToComboBox(tagName,false);
+    }
+
+    connect(d->tagOpComboBox, SIGNAL(returnPressed(QString)), this, SLOT(tagChooserReturnPressed(QString)));
+    connect(d->tagOpComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(tagChooserIndexChanged(QString)));
 
     QVBoxLayout* layout = new QVBoxLayout( this );
+    QGridLayout* comboLayout = new QGridLayout;
+
     layout->setMargin(0);
-    layout->addWidget( d->tagSearchLineEdit );
+    comboLayout->addWidget( d->tagOpComboBox, 0, 0 );
+
+    QPushButton *tagButton = new QPushButton( this );
+
+    tagButton->setText("+");
+    tagButton->setToolTip( "Add Tag" );
+    tagButton->setEnabled( true );
+    d->tagButtonGroup->addButton( tagButton, Private::Button_AddTag );
+    tagButton->hide();
+    comboLayout->addWidget( tagButton, 0, 1 );
+
+    tagButton = new QPushButton( this );
+    tagButton->setText("-");
+    tagButton->setToolTip( "Remove Tag" );
+    tagButton->setEnabled( true );
+    tagButton->hide();
+    d->tagButtonGroup->addButton( tagButton, Private::Button_RemoveTag );
+    comboLayout->addWidget( tagButton, 0, 2 );
+
+    connect( d->tagButtonGroup, SIGNAL( buttonClicked( int ) ), this, SLOT( slotTagButtonClicked( int ) ));
+
+    comboLayout->setSpacing( 0 );
+    comboLayout->setMargin( 0 );
+    comboLayout->setColumnStretch(0,3);
+
+    layout->addLayout(comboLayout);
     layout->addWidget( d->splitter );
 
     QGridLayout* buttonLayout = new QGridLayout;
@@ -162,15 +233,17 @@ KoResourceItemChooser::KoResourceItemChooser(KoAbstractResourceServerAdapter * r
     buttonLayout->setSpacing( 0 );
     buttonLayout->setMargin( 0 );
 
-    d->tagOpLineEdit = new KLineEdit( this );
-    d->tagOpLineEdit->setClickMessage("Add / Remove Tag");
-    d->tagOpLineEdit->setEnabled( false );
-    d->tagOpLineEdit->hide();
 
-    connect(d->tagOpLineEdit, SIGNAL(returnPressed(QString)), this, SLOT(tagOpLineEditActivated(QString)));
-    connect(d->tagOpLineEdit, SIGNAL(textChanged(QString)), this, SLOT(tagOpLineEditTextChanged(QString)));
+    d->tagSearchLineEdit = new KLineEdit(this);
+    d->tagSearchLineEdit->setClearButtonShown(true);
+    d->tagSearchLineEdit->setClickMessage(i18n("Switch to/create a Tag to filter"));
+    d->tagSearchLineEdit->setEnabled( false );
+    d->tagSearchLineEdit->hide();
+
+    connect( d->tagSearchLineEdit, SIGNAL(returnPressed(QString)), this, SLOT(tagSearchLineEditActivated(QString)));
+    connect( d->tagSearchLineEdit, SIGNAL(textChanged(QString)), this, SLOT(tagSearchLineEditTextChanged(QString)));
 
-    layout->addWidget( d->tagOpLineEdit );
+    layout->addWidget( d->tagSearchLineEdit );
     layout->addLayout( buttonLayout );
 
     d->tagCompleter = new QCompleter(getTagNamesList(""),this);
@@ -277,7 +350,10 @@ void KoResourceItemChooser::showGetHotNewStuff( bool showDownload, bool showUplo
 void KoResourceItemChooser::showTaggingBar(bool showSearchBar, bool showOpBar)
 {
     showSearchBar ? d->tagSearchLineEdit->show() : d->tagSearchLineEdit->hide();
-    showOpBar ? d->tagOpLineEdit->show() : d->tagOpLineEdit->hide();
+    showOpBar ? d->tagOpComboBox->show() : d->tagOpComboBox->hide();
+
+    foreach( QAbstractButton * button, d->tagButtonGroup->buttons() )
+        showOpBar ? button->show() : button->hide();
 }
 
 void KoResourceItemChooser::setRowCount( int rowCount )
@@ -331,7 +407,6 @@ void KoResourceItemChooser::setCurrentResource(KoResource* resource)
         return;
 
     d->view->setCurrentIndex(index);
-    setTagOpLineEdit(d->model->getAssignedTagsList(resource));
     updatePreview(resource);
 }
 
@@ -365,8 +440,6 @@ void KoResourceItemChooser::setCurrentItem(int row, int column)
     if (index.isValid()) {
         updatePreview(resourceFromModelIndex(index));
     }
-
-
 }
 
 void KoResourceItemChooser::setProxyModel( QAbstractProxyModel* proxyModel )
@@ -380,7 +453,6 @@ void KoResourceItemChooser::activated(const QModelIndex &/*index*/)
     KoResource* resource = currentResource();
     if (resource) {
         emit resourceSelected( resource );
-        setTagOpLineEdit(d->model->getAssignedTagsList(resource));
         updatePreview(resource);
         updateButtonState();
     }
@@ -400,13 +472,13 @@ void KoResourceItemChooser::updateButtonState()
     if( resource ) {
         removeButton->setEnabled( true );
         uploadButton->setEnabled(resource->removable());
-        d->tagOpLineEdit->setEnabled(true);
+        d->tagOpComboBox->setEnabled(true);
         return;
     }
 
     removeButton->setEnabled( false );
     uploadButton->setEnabled(false);
-    d->tagOpLineEdit->setEnabled( false );
+    d->tagOpComboBox->setEnabled( true );
 }
 
 void KoResourceItemChooser::updatePreview(KoResource *resource)
@@ -484,69 +556,6 @@ QSize KoResourceItemChooser::viewSize()
     return d->view->size();
 }
 
-void KoResourceItemChooser::setTagOpLineEdit(QStringList tagsList)
-{
-    QString tags;
-    if(!tagsList.isEmpty()) {
-        tagsList.sort();
-        tags = tagsList.join(", ");
-        tags.append(", ");
-        d->tagOpLineEdit->setText(tags);
-    }
-    else
-    {
-        d->tagOpLineEdit->clear();
-    }
-
-    d->tagCompleter = new QCompleter(getTagNamesList(tags),this);
-    d->tagOpLineEdit->setCompleter(d->tagCompleter);
-}
-
-
-void KoResourceItemChooser::tagOpLineEditActivated(QString lineEditText)
-{
-    QStringList tagsListNew = lineEditText.split(", ");
-    if(tagsListNew.contains("")) {
-        tagsListNew.removeAll("");
-    }
-
-    KoResource* resource = currentResource();
-    if(!resource) {
-        return;
-    }
-    QStringList tagsList = d->model->getAssignedTagsList(resource);
-
-    foreach(const QString& tag, tagsListNew) {
-        if(!tagsList.contains(tag)) {
-            d->model->addTag(resource, tag);
-        }
-    }
-
-    foreach(const QString& tag, tagsList) {
-        if(!tagsListNew.contains(tag)) {
-            d->model->deleteTag(resource, tag);
-        }
-    }
-
-    setTagOpLineEdit( d->model->getAssignedTagsList(resource));
-}
-
-void KoResourceItemChooser::tagOpLineEditTextChanged(QString lineEditText)
-{
-    KoResource* resource = currentResource();
-    if(!resource) {
-        return;
-    }
-    if(lineEditText.isEmpty()) {
-        QStringList assignedTagsList = d->model->getAssignedTagsList(resource);
-        foreach(const QString& tag, assignedTagsList) {
-            d->model->deleteTag(resource, tag);
-        }
-    }
-    d->tagCompleter = new QCompleter(getTagNamesList(lineEditText),this);
-    d->tagOpLineEdit->setCompleter(d->tagCompleter);
-}
-
 QStringList KoResourceItemChooser::getTagNamesList(QString lineEditText)
 {
     QStringList tagNamesList = d->model->getTagNamesList();
@@ -586,32 +595,250 @@ KoResourceItemView *KoResourceItemChooser::itemView()
 
 QStringList KoResourceItemChooser::getTaggedResourceFileNames(QString lineEditText)
 {
-    return d->model->searchTag(lineEditText);
+    return QStringList();
 }
 
 void KoResourceItemChooser::tagSearchLineEditActivated(QString lineEditText)
 {
-    d->model->setTagSearch(true);
-    d->model->setTaggedResourceFileNames(getTaggedResourceFileNames(lineEditText));
+    QList<KoResource*> newResources = d->model->currentlyVisibleResources();
+    foreach(KoResource * oldRes, d->originalResources) {
+        if (!newResources.contains(oldRes))
+            removeResourceTag(oldRes,d->currentTag);
+    }
+    foreach(KoResource * newRes, newResources) {
+        if (!d->originalResources.contains(newRes))
+            addResourceTag(newRes,d->currentTag);
+    }
+    updateTaggedResourceView();
+    d->tagSearchLineEdit->clear();
+}
+
+void KoResourceItemChooser::tagSearchLineEditTextChanged(QString lineEditText)
+{
+    d->model->searchTextChanged(lineEditText);
     d->model->updateServer();
 
-    if(!lineEditText.endsWith(", ")) {
-        lineEditText.append(", ");
-    }
     d->tagCompleter = new QCompleter(getTagNamesList(lineEditText),this);
     d->tagSearchLineEdit->setCompleter(d->tagCompleter);
-    d->tagSearchLineEdit->setText( lineEditText );
+}
+
+void KoResourceItemChooser::tagChooserIndexChanged(QString lineEditText)
+{
+    int index = d->tagOpComboBox->currentIndex();
+
+    if ( index > 0) {
+        d->currentTag = lineEditText;
+        d->model->enableResourceFiltering(true);
+        d->tagSearchLineEdit->setClickMessage(i18n("Enter resources or [Tags] to in-/!exclude."));
+        d->tagSearchLineEdit->setEnabled(true);
+    }
+    else {
+        d->model->enableResourceFiltering(false);
+        d->tagSearchLineEdit->setClickMessage(i18n("Create a Tag to enable filtering."));
+        d->tagSearchLineEdit->setEnabled(false);
+        d->currentTag.clear();
+    }
 
+     d->tagSearchLineEdit->clear();
+     updateTaggedResourceView();
 }
 
-void KoResourceItemChooser::tagSearchLineEditTextChanged(QString lineEditText)
+void KoResourceItemChooser::updateTaggedResourceView()
 {
-    if(lineEditText.isEmpty()) {
-        d->model->setTagSearch(false);
-        d->model->updateServer();
+    d->model->setTaggedResourceFileNames(d->model->searchTag(d->currentTag));
+    d->model->updateServer();
+    d->originalResources = d->model->currentlyVisibleResources();
+}
+
+
+// TODO: put the newName.compare check in the add index function
+QString KoResourceItemChooser::renameTag(QString oldName, QString newName)
+{
+
+    if (!newName.compare(oldName)) {
+        d->tagOpComboBox->setEditText(oldName);
+        return oldName;
     }
+
+    QList<KoResource*> resources = d->model->currentlyVisibleResources();
+    foreach(KoResource * resource, resources) {
+        QStringList tagsList = d->model->getAssignedTagsList(resource);
+
+        foreach(QString tagname, tagsList) {
+            if(!tagname.compare(oldName)) {
+                d->model->deleteTag(resource, oldName);
+            }
+            if(tagname.compare(newName)) {
+                d->model->addTag(resource, newName);
+            }
+        }
+    }
+    return oldName;
+}
+
+void KoResourceItemChooser::tagChooserReturnPressed(QString lineEditText)
+{
+    int index = d->tagOpComboBox->currentIndex();
+    QString oldTagname = d->tagOpComboBox->itemText(index);
+    QString newTagName = renameTag(oldTagname, lineEditText);
+    d->tagOpComboBox->setItemText(index,newTagName);
+    d->currentTag = newTagName;
+
     d->tagCompleter = new QCompleter(getTagNamesList(lineEditText),this);
-    d->tagSearchLineEdit->setCompleter(d->tagCompleter);
+    d->tagOpComboBox->setCompleter(d->tagCompleter);
+
+}
+
+void KoResourceItemChooser::addTagToComboBox(QString tagName, bool followEntry)
+{
+    int pos = d->tagOpComboBox->findText(tagName);
+    if (pos == -1) {
+        d->tagOpComboBox->addItem(tagName);
+        if (followEntry)
+        d->tagOpComboBox->setCurrentIndex(d->tagOpComboBox->findText(tagName));
+    }
+}
+
+void KoResourceItemChooser::removeTagFromComboBox()
+{
+    int index = d->tagOpComboBox->currentIndex();
+    if (index > 0) {
+        if (QMessageBox::Yes == QMessageBox::question(this, i18n("Tag deletion"),
+                    i18n("Really delete this Tag?"), QMessageBox::Yes|QMessageBox::No)) {
+
+            QList<KoResource*> resources = d->model->currentlyVisibleResources();
+            foreach(KoResource * resource, resources) {
+                removeResourceTag(resource,d->currentTag);
+            }
+            d->tagOpComboBox->removeItem(index);
+        }
+    }
+}
+
+void KoResourceItemChooser::slotTagButtonClicked( int button )
+{
+    if( button == Private::Button_AddTag ) {
+        bool ok;
+        QString tagName = QInputDialog::getText(this,i18n("Enter name for new Tag"),i18n("Tag name:"),QLineEdit::Normal,"",&ok);
+        if (ok) {
+            addTagToComboBox(tagName,true);
+        }
+    }
+    else if( button == Private::Button_RemoveTag ) {
+
+        removeTagFromComboBox();
+    }
+}
+
+void KoResourceItemChooser::addResourceTag(KoResource * resource, QString tagName)
+{
+    QStringList tagsList = d->model->getAssignedTagsList(resource);
+    if (tagsList.isEmpty()) {
+        d->model->addTag(resource, tagName);
+    }
+    else {
+        foreach(QString tag, tagsList) {
+            if(tag.compare(tagName)) {
+                d->model->addTag(resource, tagName);
+            }
+        }
+    }
+}
+
+void KoResourceItemChooser::removeResourceTag(KoResource * resource, QString tagName)
+{
+    QStringList tagsList = d->model->getAssignedTagsList(resource);
+
+    foreach(QString oldName, tagsList) {
+        if(!oldName.compare(tagName)) {
+            d->model->deleteTag(resource, oldName);
+        }
+    }
+}
+
+void KoResourceItemChooser::contextMenuRequested ( const QPoint& pos )
+{
+
+
+    KoResource * resource = currentResource();
+    if (!resource || !d->showContextMenu)
+        return;
+
+    QMenu menu;
+    QImage image = resource->image();
+    QIcon icon(QPixmap::fromImage(image));
+    QAction * label = new QAction(resource->name(),this);
+    label->setIcon(icon);
+
+    menu.addAction(label);
+
+    QMenu * removableTagsMenu;
+    QMenu * assignableTagsMenu;
+
+    QStringList removables = d->model->getAssignedTagsList(resource);
+    QStringList assignables = d->model->getTagNamesList();
+
+    assignableTagsMenu = menu.addMenu(koIcon("list-add"),i18n("Assign to Tag:"));
+
+    if (!removables.isEmpty()) {
+        menu.addSeparator();
+        removableTagsMenu = menu.addMenu(koIcon("list-remove"),i18n("Remove from Tag:"));
+    }
+
+    foreach (QString tag, removables) {
+        assignables.removeAll(tag);
+        ContextMenuTagAction * removeTagAction = new ContextMenuTagAction(resource,tag,this);
+
+        connect(removeTagAction, SIGNAL(triggered(KoResource *,QString)),
+                this, SLOT(contextRemoveTagFromResource(KoResource *, QString)));
+        removableTagsMenu->addAction(removeTagAction);
+    }
+
+    foreach (QString tag, assignables) {
+        ContextMenuTagAction * addTagAction = new ContextMenuTagAction(resource,tag,this);
+
+        connect(addTagAction, SIGNAL(triggered(KoResource *,QString)),
+                this, SLOT(contextAddTagToResource(KoResource*,QString)));
+        assignableTagsMenu->addAction(addTagAction);
+    }
+    assignableTagsMenu->addSeparator();
+
+    ContextMenuTagAction * addTagAction = new ContextMenuTagAction(resource,i18n("New Tag."),this);
+    addTagAction->setIcon(koIcon("document-new"));
+    connect(addTagAction, SIGNAL(triggered(KoResource *,QString)),
+                this, SLOT(contextCreateNewResourceTag(KoResource*,QString)));
+    assignableTagsMenu->addAction(addTagAction);
+
+    if (!menu.isEmpty()) {
+        menu.exec(pos);
+    }
+}
+
+void KoResourceItemChooser::contextAddTagToResource(KoResource* resource, QString tag )
+{
+    addResourceTag(resource,tag);
+    updateTaggedResourceView();
+}
+
+void KoResourceItemChooser::contextRemoveTagFromResource(KoResource* resource, QString tag )
+{
+    removeResourceTag(resource, tag);
+    updateTaggedResourceView();
+}
+
+void KoResourceItemChooser::contextCreateNewResourceTag(KoResource* resource , QString tag)
+{
+     bool ok;
+        QString tagName = QInputDialog::getText(this,i18n("Enter name for new Tag"),i18n("Tag name:"),QLineEdit::Normal,"",&ok);
+        if (ok) {
+            addTagToComboBox(tagName,false);
+            addResourceTag(resource,tagName);
+        }
+}
+
+void KoResourceItemChooser::enableContextMenu(bool enable)
+{
+    d->showContextMenu = enable;
 }
 
 #include <KoResourceItemChooser.moc>
diff --git a/libs/widgets/KoResourceItemChooser.h b/libs/widgets/KoResourceItemChooser.h
index 3bd790a..d26f5a5 100644
--- a/libs/widgets/KoResourceItemChooser.h
+++ b/libs/widgets/KoResourceItemChooser.h
@@ -26,6 +26,7 @@
 #define KO_RESOURCE_ITEM_CHOOSER
 
 #include <QWidget>
+#include <QAction>
 #include <QModelIndex>
 #include <QCompleter>
 
@@ -39,6 +40,24 @@ class KoAbstractResourceServerAdapter;
 class KoResourceItemView;
 class KoResource;
 
+class ContextMenuTagAction : public QAction
+{
+    Q_OBJECT
+public:
+    explicit ContextMenuTagAction( KoResource * resource, QString tag, QObject* parent = 0);
+    ~ContextMenuTagAction();
+    
+signals:
+    void triggered(KoResource * resource, QString tag);
+    
+protected slots:
+    void onTriggered();
+    
+private:
+    KoResource * m_resource;
+    QString m_tag;
+};
+
 /**
  * A widget that contains a KoResourceChooser as well
  * as an import/export button
@@ -48,7 +67,7 @@ class KOWIDGETS_EXPORT KoResourceItemChooser : public QWidget
   Q_OBJECT
 public:
     enum Buttons { Button_Import, Button_Remove, Button_GhnsDownload, Button_GhnsUpload };
-    
+
     explicit KoResourceItemChooser( KoAbstractResourceServerAdapter * resourceAdapter, QWidget *parent = 0 );
     ~KoResourceItemChooser();
 
@@ -57,13 +76,13 @@ public:
 
     /// Sets number of rows in the view and causes the number of columns to be calculated accordingly
     void setRowCount( int rowCount );
-    
+
     /// Sets the height of the view rows
     void setRowHeight( int rowHeight );
 
     /// Sets the width of the view columns
     void setColumnWidth( int columnWidth );
-    
+
     /// Sets a custom delegate for the view
     void setItemDelegate( QAbstractItemDelegate * delegate );
 
@@ -82,6 +101,8 @@ public:
     void setCurrentItem(int row, int column);
 
     void showButtons( bool show );
+    
+    void enableContextMenu(bool enable);
 
     /// shows the aside preview with the resource's image
     void showPreview(bool show);
@@ -115,21 +136,32 @@ signals:
     void splitterMoved();
 public slots:
     void slotButtonClicked( int button );
-    
+    void slotTagButtonClicked( int button );
+
 private slots:
     void activated ( const QModelIndex & index );
 
-    void setTagOpLineEdit(QStringList assignedTagsList);
-
-    void tagOpLineEditActivated(QString lineEditText);
-    void tagOpLineEditTextChanged(QString lineEditText);
-
     void tagSearchLineEditActivated(QString lineEditText);
     void tagSearchLineEditTextChanged(QString lineEditText);
 
+    void tagChooserIndexChanged(QString lineEditText);
+    void tagChooserReturnPressed(QString lineEditText);
+    
+    void contextMenuRequested(const QPoint &pos);
+    
+    void contextRemoveTagFromResource(KoResource*,QString);
+    void contextAddTagToResource(KoResource*,QString);
+    void contextCreateNewResourceTag(KoResource*,QString);
+    
 private:
     void updateButtonState();
     void updatePreview(KoResource *resource);
+    void updateTaggedResourceView();
+    QString renameTag(QString oldName, QString newName);
+    void addTagToComboBox(QString tagName, bool followEntry);
+    void removeTagFromComboBox();
+    void addResourceTag(KoResource * resource, QString tagName);
+    void removeResourceTag(KoResource * resource, QString tagName);
 
     /// Resource for a given model index
     /// @returns the resource pointer, 0 is index not valid
diff --git a/libs/widgets/KoResourceItemView.cpp b/libs/widgets/KoResourceItemView.cpp
index dfa2ba9..c56ecc5 100644
--- a/libs/widgets/KoResourceItemView.cpp
+++ b/libs/widgets/KoResourceItemView.cpp
@@ -32,6 +32,7 @@ KoResourceItemView::KoResourceItemView( QWidget * parent )
     verticalHeader()->hide();
     horizontalHeader()->hide();
     verticalHeader()->setDefaultSectionSize( 20 );
+    setContextMenuPolicy(Qt::DefaultContextMenu);
     m_viewMode = FIXED_COLUMS;
 }
 
@@ -45,14 +46,14 @@ void KoResourceItemView::resizeEvent( QResizeEvent * event )
 
     if (m_viewMode == FIXED_COLUMS) {
         columnWidth = viewport()->size().width() / columnCount;
-        
+
         for( int i = 0; i < columnCount; ++i ) {
             setColumnWidth( i, columnWidth );
         }
     } else if (m_viewMode == FIXED_ROWS) {
         if (rowCount == 0) return;  // Don't divide by zero
         rowHeight = viewport()->size().height() / rowCount;
-        
+
         for( int i = 0; i < rowCount; ++i ) {
             setRowHeight( i, rowHeight );
         }
@@ -87,4 +88,10 @@ void KoResourceItemView::selectionChanged(const QItemSelection &selected, const
     emit currentResourceChanged(selected.indexes().first());
 }
 
+void KoResourceItemView::contextMenuEvent( QContextMenuEvent * event)
+{
+    QTableView::contextMenuEvent(event);
+    emit contextMenuRequested(event->globalPos());
+}
+
 #include "KoResourceItemView.moc"
diff --git a/libs/widgets/KoResourceItemView.h b/libs/widgets/KoResourceItemView.h
index 63906cd..5a15cb8 100644
--- a/libs/widgets/KoResourceItemView.h
+++ b/libs/widgets/KoResourceItemView.h
@@ -38,27 +38,28 @@ public:
         FIXED_COLUMS,  /// The number of columns is fixed
         FIXED_ROWS     /// The number of rows is fixed
     };
-    
+
     explicit KoResourceItemView(QWidget *parent = 0);
     virtual ~KoResourceItemView() {}
-    
+
     /** reimplemented
     * This will draw a number of rows based on the number of columns if m_viewMode is FIXED_COLUMS
     * And it will draw a number of columns based on the number of rows if m_viewMode is FIXED_ROWS
     */
     virtual void resizeEvent ( QResizeEvent * event );
-    
+
     /// reimplemented
     virtual bool viewportEvent( QEvent * event );
-    
+
     void setViewMode(ViewMode mode);
-    
+
 signals:
 
     void currentResourceChanged(const QModelIndex &);
+    void contextMenuRequested(const QPoint &);
 
 protected:
-
+    virtual void contextMenuEvent( QContextMenuEvent * event);
     void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
 
 private:
diff --git a/libs/widgets/KoResourceModel.cpp b/libs/widgets/KoResourceModel.cpp
index c25be97..a9cb212 100644
--- a/libs/widgets/KoResourceModel.cpp
+++ b/libs/widgets/KoResourceModel.cpp
@@ -29,11 +29,11 @@ KoResourceModel::KoResourceModel( KoAbstractResourceServerAdapter * resourceAdap
 {
     Q_ASSERT( m_resourceAdapter );
     m_resourceAdapter->connectToResourceServer();
-    connect(m_resourceAdapter, SIGNAL(resourceAdded(KoResource*)), 
+    connect(m_resourceAdapter, SIGNAL(resourceAdded(KoResource*)),
             this, SLOT(resourceAdded(KoResource*)));
-    connect(m_resourceAdapter, SIGNAL(removingResource(KoResource*)), 
+    connect(m_resourceAdapter, SIGNAL(removingResource(KoResource*)),
             this, SLOT(resourceRemoved(KoResource*)));
-    connect(m_resourceAdapter, SIGNAL(resourceChanged(KoResource*)), 
+    connect(m_resourceAdapter, SIGNAL(resourceChanged(KoResource*)),
             this, SLOT(resourceChanged(KoResource*)));
 }
 
@@ -63,8 +63,15 @@ QVariant KoResourceModel::data( const QModelIndex &index, int role ) const
             KoResource * resource = static_cast<KoResource*>(index.internalPointer());
             if( ! resource )
                 return QVariant();
-
-            return QVariant( i18n( resource->name().toUtf8().data() ) );
+            QString resName = i18n( resource->name().toUtf8().data());
+            
+           
+            if (m_resourceAdapter->getAssignedTagsList(resource).count()) {
+                QString taglist = m_resourceAdapter->getAssignedTagsList(resource).join("] , [");
+                QString tagListToolTip = QString(" - %1: [%2]").arg(i18n("Tags"), taglist);
+                return QVariant( resName + tagListToolTip );
+            }
+            return QVariant( resName );
         }
         case Qt::DecorationRole:
         {
@@ -144,7 +151,7 @@ void KoResourceModel::resourceChanged(KoResource* resource)
     if (!modelIndex.isValid()) {
         return;
     }
-    
+
     emit dataChanged(modelIndex, modelIndex);
 }
 
@@ -153,7 +160,7 @@ QModelIndex KoResourceModel::indexFromResource(KoResource* resource)
     int resourceIndex = m_resourceAdapter->resources().indexOf(resource);
     int row = resourceIndex / columnCount();
     int column = resourceIndex % columnCount();
-    return index(row, column);    
+    return index(row, column);
 }
 
 QString KoResourceModel::extensions()
@@ -206,9 +213,14 @@ QStringList KoResourceModel::searchTag(const QString& lineEditText)
     return m_resourceAdapter->searchTag(lineEditText);
 }
 
-void KoResourceModel::setTagSearch(bool tagSearch)
+void KoResourceModel::searchTextChanged(const QString& searchString)
 {
-    m_resourceAdapter->setTagSearch(tagSearch);
+    m_resourceAdapter->searchTextChanged(searchString);
+}
+
+void KoResourceModel::enableResourceFiltering(bool enable)
+{
+    m_resourceAdapter->enableResourceFiltering(enable);
 }
 
 void KoResourceModel::setTaggedResourceFileNames(const QStringList& resourceFileNames)
@@ -221,10 +233,13 @@ void KoResourceModel::updateServer()
     m_resourceAdapter->updateServer();
 }
 
-
 int KoResourceModel::resourcesCount() const
 {
     return m_resourceAdapter->resources().count();
 }
 
+QList<KoResource *> KoResourceModel::currentlyVisibleResources()
+{
+  return m_resourceAdapter->resources();
+}
 #include <KoResourceModel.moc>
diff --git a/libs/widgets/KoResourceModel.h b/libs/widgets/KoResourceModel.h
index d63d32a..3ccb28b 100644
--- a/libs/widgets/KoResourceModel.h
+++ b/libs/widgets/KoResourceModel.h
@@ -64,10 +64,12 @@ public:
     void deleteTag( KoResource* resource, const QString& tag);
     QStringList getTagNamesList();
     QStringList searchTag(const QString& lineEditText);
-    void setTagSearch(bool tagSearch);
+    void enableResourceFiltering(bool enable);
     void setTaggedResourceFileNames(const QStringList& resourceFileNames);
+    void searchTextChanged(const QString& searchString);
     void updateServer();
     int resourcesCount() const;
+    QList<KoResource *> currentlyVisibleResources();
 
 private slots:
     void resourceAdded(KoResource *resource);
diff --git a/libs/widgets/KoResourceServer.h b/libs/widgets/KoResourceServer.h
index b363684..1ab4ad6 100644
--- a/libs/widgets/KoResourceServer.h
+++ b/libs/widgets/KoResourceServer.h
@@ -434,6 +434,11 @@ public:
     {
         return m_tagObject->searchTag(lineEditText);
     }
+    
+    KoResourceTagging * tagObject() 
+    {
+        return m_tagObject;
+    }
 
 
 #ifdef NEPOMUK
diff --git a/libs/widgets/KoResourceServerAdapter.h b/libs/widgets/KoResourceServerAdapter.h
index bb5c414..02ab31e 100644
--- a/libs/widgets/KoResourceServerAdapter.h
+++ b/libs/widgets/KoResourceServerAdapter.h
@@ -24,6 +24,7 @@
 
 #include "KoResourceServer.h"
 #include <KoResource.h>
+#include <KoResourceFiltering.h>
 
 #include "kowidgets_export.h"
 
@@ -43,12 +44,13 @@ public:
     virtual void importResourceFile(const QString & filename, bool fileCreation=true) = 0;
     virtual QString extensions() = 0;
     virtual void setTaggedResourceFileNames(const QStringList& resourceFileNames)=0;
-    virtual void setTagSearch(bool tagSearch)=0;
+    virtual void enableResourceFiltering(bool tagSearch)=0;
     virtual void updateServer()=0;
     virtual QStringList getAssignedTagsList( KoResource* resource )=0;
     virtual QStringList getTagNamesList()=0;
     virtual void addTag( KoResource* resource,const QString& tag)=0;
     virtual void deleteTag( KoResource* resource,const QString& tag)=0;
+    virtual void searchTextChanged(const QString& searchString)=0;
     virtual QStringList searchTag(const QString& lineEditText)=0;
 
 signals:
@@ -73,7 +75,9 @@ public:
         : KoAbstractResourceServerAdapter(parent)
         , m_resourceServer(resourceServer)
     {
-        m_tagSearch=false;
+        m_changeCounter = 0;
+        m_oldChangeCounter = 0;
+        m_enableFiltering=false;
     }
 
     virtual ~KoResourceServerAdapter()
@@ -88,28 +92,22 @@ public:
             m_resourceServer->addObserver(this);
     }
 
-    virtual QList<KoResource*> resources() 
+    virtual QList<KoResource*> resources()
     {
         if( ! m_resourceServer )
             return QList<KoResource*>();
 
-        QList<T*> serverResources = m_resourceServer->resources();
-
-        QList<KoResource*> resources;
-
-        foreach( T* resource, serverResources ) {
-            resources.append( resource );
+        bool cacheDirty = serverResourceCacheInvalid();
+        if(cacheDirty) {
+            cacheServerResources(m_resourceServer->resources());
         }
-
-        if(m_tagSearch) {
-            foreach(KoResource* resource, resources) {
-                if(!m_resourceFileNames.contains(resource->filename())) {
-                    resources.removeAll(resource);
-                }
+        if ( m_enableFiltering) {
+            if (m_presetFilter.filtersHaveChanged() || cacheDirty) {
+                m_filteredResources = m_presetFilter.filterResources( m_serverResources );
             }
+            return m_filteredResources;
         }
-
-        return resources;
+        return m_serverResources;
     }
 
     bool addResource(KoResource* resource)
@@ -150,21 +148,23 @@ public:
         }
 
         m_resourceServer->removeResourceFile(filename);
-
     }
 
     void resourceAdded(T* resource)
     {
+        serverResourceCacheInvalid(true);
         emitResourceAdded(resource);
     }
 
     void removingResource(T* resource)
     {
+        serverResourceCacheInvalid(true);
         emitRemovingResource(resource);
     }
-    
+
     void resourceChanged(T* resource)
     {
+        serverResourceCacheInvalid(true);
         emitResourceChanged(resource);
     }
 
@@ -175,15 +175,16 @@ public:
 
         return m_resourceServer->extensions();
     }
-    
+
     void setTaggedResourceFileNames(const QStringList& resourceFileNames)
     {
-        m_resourceFileNames = resourceFileNames;
+        serverResourceCacheInvalid(true);
+        m_presetFilter.setRootResourceFilenames(resourceFileNames);
     }
 
-    void setTagSearch(bool tagSearch )
+    void enableResourceFiltering(bool enable )
     {
-        m_tagSearch = tagSearch;
+        m_enableFiltering = enable;
     }
 
     void updateServer()
@@ -211,6 +212,12 @@ public:
         m_resourceServer->delTag(resource,tag);
     }
 
+    void searchTextChanged(const QString& searchString)
+    {
+        m_presetFilter.setFilters(searchString, resourceServer()->tagObject());
+        serverResourceCacheInvalid(true);
+    }
+
     QStringList searchTag(const QString& lineEditText)
     {
         return m_resourceServer->searchTag(lineEditText);
@@ -221,11 +228,40 @@ protected:
     {
         return m_resourceServer;
     }
-
+protected:
+    KoResourceFiltering m_presetFilter;
 private:
+    bool serverResourceCacheInvalid()
+    {
+        return m_changeCounter != m_oldChangeCounter;
+    }
+
+    void serverResourceCacheInvalid(bool yes)
+    {
+        if (yes) {
+            ++m_changeCounter;
+        }
+        else {
+            m_oldChangeCounter = m_changeCounter;
+        }
+    }
+
+    void cacheServerResources(QList< T* > serverResources)
+    {
+        m_serverResources.clear();
+
+        foreach( T* resource, serverResources ) {
+            m_serverResources.append( resource );
+        }
+        serverResourceCacheInvalid (false);
+    }
+
     KoResourceServer<T>* m_resourceServer;
-    QStringList m_resourceFileNames;
-    bool m_tagSearch;
+    unsigned int m_changeCounter;
+    unsigned int m_oldChangeCounter;
+    QList<KoResource*> m_serverResources;
+    QList<KoResource*> m_filteredResources;
+    bool m_enableFiltering;
 };
 
 #endif // KO_RESOURCESERVER_ADAPTER_H_


More information about the kimageshop mailing list