[prev in list] [next in list] [prev in thread] [next in thread] 

List:       nepomuk
Subject:    [Nepomuk] Nepomuk Facets - next generation (or previous generation?)
From:       Sebastian_Trüg <trueg () kde ! org>
Date:       2010-09-06 20:18:59
Message-ID: 4C854CB3.8040106 () kde ! org
[Download RAW message or body]

Good evening (or whatever),

after a lot of thinking, several setbacks, and some discussion, I went
back to Alessandro's original base design where each Facet is a QWidget.
Sounds stupid but sometimes I need to go all the way myself to see it. :P
Anyway, I was not able to solve all the problems with the previous
attempts and finally:
- Facets are a GUI-centric thing and make not much sense without a GUI.
- Does a Model really make sense (I know I was the one fighting for it
  before)? I don't think so anymore for several reasons:
  * It is very unlikely that we ever use the facets in different views.
  * Not all facets can be displayed in a list (rating makes more sense
    as stars)
  * Several facets need buttons for custom ranges or similar which also
    do not make much sense in views.
- The new approach allows to use Facets separately or through the
  FacetWidgetController. And extending should be very easy by using one
  of the base classes.

Attached you find a patch for kdelibs and kdebase (dolphin) for playing
around.

Comments?

Cheers,
Sebastian

["kdebase-apps-dolphin-facets.diff" (text/plain)]

commit 522480164c1717c07cc8b458ca019b6105370bd1
Author: Sebastian Trueg <trueg@kde.org>
Date:   Mon Sep 6 21:53:55 2010 +0200

    Test version of the new facet panel.

diff --git a/apps/dolphin/src/CMakeLists.txt b/apps/dolphin/src/CMakeLists.txt
index 0f51f29..f69e057 100644
--- a/apps/dolphin/src/CMakeLists.txt
+++ b/apps/dolphin/src/CMakeLists.txt
@@ -112,6 +112,7 @@ set(dolphin_SRCS
     panels/folders/treeviewcontextmenu.cpp
     panels/folders/folderspanel.cpp
     panels/folders/paneltreeview.cpp
+    panels/facets/facetpanel.cpp
     search/dolphinsearchbox.cpp
     settings/general/behaviorsettingspage.cpp
     settings/general/contextmenusettingspage.cpp
diff --git a/apps/dolphin/src/dolphinmainwindow.cpp \
b/apps/dolphin/src/dolphinmainwindow.cpp index e58b817..10dff1d 100644
--- a/apps/dolphin/src/dolphinmainwindow.cpp
+++ b/apps/dolphin/src/dolphinmainwindow.cpp
@@ -31,6 +31,7 @@
 #include "panels/folders/folderspanel.h"
 #include "panels/places/placespanel.h"
 #include "panels/information/informationpanel.h"
+#include "panels/facets/facetpanel.h"
 #include "settings/dolphinsettings.h"
 #include "settings/dolphinsettingsdialog.h"
 #include "statusbar/dolphinstatusbar.h"
@@ -1519,6 +1520,21 @@ void DolphinMainWindow::setupDockWidgets()
     connect(this, SIGNAL(requestItemInfo(KFileItem)),
             infoPanel, SLOT(requestDelayedItemInfo(KFileItem)));
 
+    // setup "Facets"
+    QDockWidget* facetDock = new QDockWidget(i18nc("@title:window", "Filter"));
+    facetDock->setObjectName("facetDock");
+    facetDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
+    Panel* facetPanel = new FacetPanel(facetDock);
+    connect(facetPanel, SIGNAL(urlActivated(KUrl)), this, SLOT(handleUrl(KUrl)));
+    facetDock->setWidget(facetPanel);
+
+    QAction* facetAction = facetDock->toggleViewAction();
+    facetAction->setIcon(KIcon("dialog-facet"));
+
+    addDockWidget(Qt::RightDockWidgetArea, facetDock);
+    connect(this, SIGNAL(urlChanged(KUrl)),
+            facetPanel, SLOT(setUrl(KUrl)));
+
     // setup "Folders"
     QDockWidget* foldersDock = new QDockWidget(i18nc("@title:window", "Folders"));
     foldersDock->setObjectName("foldersDock");
@@ -1590,6 +1606,7 @@ void DolphinMainWindow::setupDockWidgets()
     panelsMenu->addAction(placesAction);
     panelsMenu->addAction(infoAction);
     panelsMenu->addAction(foldersAction);
+    panelsMenu->addAction(facetAction);
 #ifndef Q_OS_WIN
     panelsMenu->addAction(terminalAction);
 #endif
diff --git a/apps/dolphin/src/panels/facets/facetpanel.cpp \
b/apps/dolphin/src/panels/facets/facetpanel.cpp new file mode 100644
index 0000000..6153da3
--- /dev/null
+++ b/apps/dolphin/src/panels/facets/facetpanel.cpp
@@ -0,0 +1,135 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Sebastian Trueg <trueg@kde.org>                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#include "facetpanel.h"
+
+#include <nepomuk/filequery.h>
+#include <nepomuk/facetwidget.h>
+#include <nepomuk/facetwidgetcontroller.h>
+
+#include <kfileitem.h>
+#include <kio/jobclasses.h>
+#include <kio/job.h>
+
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QTreeView>
+#include <QtGui/QPushButton>
+#include <kdebug.h>
+
+
+FacetPanel::FacetPanel(QWidget* parent)
+    : Panel(parent)
+{
+    QVBoxLayout* layout = new QVBoxLayout(this);
+    m_buttonRemoveFolderRestriction = new QPushButton( i18n( "Remove folder \
restriction" ), this ); +    connect( m_buttonRemoveFolderRestriction, SIGNAL( \
clicked() ), SLOT( slotRemoveFolderRestrictionClicked() ) ); +
+    layout->addWidget(m_buttonRemoveFolderRestriction);
+
+    Nepomuk::Query::FacetWidget* dateFacet = \
Nepomuk::Query::FacetWidget::createDateFacet( this ); +    \
Nepomuk::Query::FacetWidget* typeFacet = \
Nepomuk::Query::FacetWidget::createFileTypeFacet( this ); +    \
Nepomuk::Query::FacetWidget* prioFacet = \
Nepomuk::Query::FacetWidget::createPriorityFacet( this ); +    \
Nepomuk::Query::FacetWidget* tagFacet = Nepomuk::Query::FacetWidget::createTagFacet( \
this ); +    layout->addWidget( dateFacet );
+    layout->addWidget( typeFacet );
+    layout->addWidget( prioFacet );
+    layout->addWidget( tagFacet );
+
+    m_facetController = new Nepomuk::Query::FacetWidgetController( this );
+    m_facetController->addFacetWidget( dateFacet );
+    m_facetController->addFacetWidget( typeFacet );
+    m_facetController->addFacetWidget( prioFacet );
+    m_facetController->addFacetWidget( tagFacet );
+    connect(m_facetController, SIGNAL(queryChanged(Nepomuk::Query::Query)), \
SLOT(slotQueryChanged(Nepomuk::Query::Query)) ); +
+    // init to empty panel
+    setQuery(Nepomuk::Query::Query());
+}
+
+
+FacetPanel::~FacetPanel()
+{
+}
+
+void FacetPanel::setUrl(const KUrl& url)
+{
+    kDebug() << url;
+    Panel::setUrl(url);
+
+    // disable us
+    setQuery(Nepomuk::Query::Query());
+
+    // get the query from the item
+    m_lastSetUrlStatJob = KIO::stat(url, KIO::HideProgressInfo);
+    connect(m_lastSetUrlStatJob, SIGNAL(result(KJob*)),
+            this, SLOT(slotSetUrlStatFinished(KJob*)));
+}
+
+
+void FacetPanel::setQuery(const Nepomuk::Query::Query& query)
+{
+    kDebug() << query << query.isValid();
+
+    if (query.isValid()) {
+        m_buttonRemoveFolderRestriction->setVisible( query.isFileQuery() && \
!query.toFileQuery().includeFolders().isEmpty() ); +        \
m_facetController->setQuery( query ); +        kDebug() << "Rest query after facets:" \
<< m_facetController->baseQuery(); +        setEnabled(true);
+    }
+    else {
+        setEnabled(false);
+    }
+}
+
+
+void FacetPanel::slotSetUrlStatFinished(KJob* job)
+{
+    m_lastSetUrlStatJob = 0;
+    kDebug() << url();
+    const KIO::UDSEntry uds = static_cast<KIO::StatJob*>(job)->statResult();
+    const QString nepomukQueryStr = uds.stringValue( \
KIO::UDSEntry::UDS_NEPOMUK_QUERY ); +    kDebug() << nepomukQueryStr;
+    Nepomuk::Query::FileQuery nepomukQuery;
+    if ( !nepomukQueryStr.isEmpty() ) {
+        nepomukQuery = Nepomuk::Query::Query::fromString( nepomukQueryStr );
+    }
+    else if ( url().isLocalFile() ) {
+        // fallback query for local file URLs
+        nepomukQuery.addIncludeFolder(url());
+    }
+    kDebug() << nepomukQuery;
+    setQuery(nepomukQuery);
+}
+
+
+void FacetPanel::slotQueryChanged(const Nepomuk::Query::Query& query)
+{
+     kDebug() << query;
+     emit urlActivated(query.toSearchUrl());
+}
+
+
+void FacetPanel::slotRemoveFolderRestrictionClicked()
+{
+    Nepomuk::Query::FileQuery query = m_facetController->baseQuery();
+    query.setIncludeFolders( KUrl::List() );
+    query.setExcludeFolders( KUrl::List() );
+    m_facetController->setBaseQuery( query );
+    slotQueryChanged(m_facetController->constructQuery());
+}
diff --git a/apps/dolphin/src/panels/facets/facetpanel.h \
b/apps/dolphin/src/panels/facets/facetpanel.h new file mode 100644
index 0000000..c326e42
--- /dev/null
+++ b/apps/dolphin/src/panels/facets/facetpanel.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Sebastian Trueg <trueg@kde.org>                  *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA            *
+ ***************************************************************************/
+
+#ifndef FACETPANEL_H
+#define FACETPANEL_H
+
+#include "../panel.h"
+#include <nepomuk/query.h>
+
+class KJob;
+class QPushButton;
+
+namespace Nepomuk {
+    namespace Query {
+        class FacetWidgetController;
+    }
+}
+
+class FacetPanel : public Panel
+{
+    Q_OBJECT
+
+public:
+    FacetPanel(QWidget* parent = 0);
+    ~FacetPanel();
+
+public slots:
+    void setUrl(const KUrl& url);
+    void setQuery(const Nepomuk::Query::Query& query);
+
+private Q_SLOTS:
+    void slotSetUrlStatFinished(KJob*);
+    void slotQueryChanged(const Nepomuk::Query::Query&);
+    void slotRemoveFolderRestrictionClicked();
+
+private:
+    KJob* m_lastSetUrlStatJob;
+
+    QPushButton* m_buttonRemoveFolderRestriction;
+    Nepomuk::Query::FacetWidgetController* m_facetController;
+};
+
+#endif // FACETPANEL_H


["kdelibs-nepomuk-query-facets.diff" (text/plain)]

commit 4716d19171e4308bb23dc94d5bf34e33d4254d8b
Author: Sebastian Trueg <trueg@kde.org>
Date:   Mon Sep 6 21:47:48 2010 +0200

    Finally a facet API:
    A facet is a widget which provides a Term.
    These terms will be combined through the FacetWidgetController.
    A bunch of specialized FacetWidgets and static FacetWidget creation
    methods make the life easier for app developers.

diff --git a/nepomuk/query/CMakeLists.txt b/nepomuk/query/CMakeLists.txt
index 86b7376..e4a5185 100644
--- a/nepomuk/query/CMakeLists.txt
+++ b/nepomuk/query/CMakeLists.txt
@@ -36,6 +36,14 @@ set(nepomukquery_SRC
   ../core/dbusconnectionpool.cpp
   queryserializer.cpp
   standardqueries.cpp
+  facetwidget.cpp
+  listfacetwidget.cpp
+  rangedfacetwidget.cpp
+  simplelistfacetwidget.cpp
+  dynamiclistfacetwidget.cpp
+  daterange.cpp
+  daterangeselectionwidget.cpp
+  facetwidgetcontroller.cpp
 )
 
 soprano_add_ontology(nepomukquery_SRC \
"${SHAREDDESKTOPONTOLOGIES_ROOT_DIR}/nie/nie.trig" "NIE" "Nepomuk::Vocabulary" \
"trig") @@ -59,6 +67,8 @@ qt4_add_dbus_interface(nepomukquery_SRC
   org.kde.nepomuk.Query.xml
   queryinterface)
 
+kde4_add_ui_files(nepomukquery_SRC daterangeselectionwidget.ui)
+
 kde4_add_library(nepomukquery ${LIBRARY_TYPE} ${nepomukquery_SRC})
 
 set_target_properties(nepomukquery PROPERTIES VERSION ${GENERIC_LIB_VERSION} \
SOVERSION ${GENERIC_LIB_SOVERSION}) @@ -67,6 +77,7 @@ \
target_link_libraries(nepomukquery  ${QT_QTCORE_LIBRARY}
   ${SOPRANO_LIBRARIES}
   kdecore
+  kdeui
   nepomuk
   )
 
@@ -91,5 +102,11 @@ install(FILES
   standardqueries.h
   nepomukquery_export.h
   standardqueries.h
+  facetwidget.h
+  listfacetwidget.h
+  rangedfacetwidget.h
+  simplelistfacetwidget.h
+  dynamiclistfacetwidget.h
+  facetwidgetcontroller.h
   DESTINATION ${INCLUDE_INSTALL_DIR}/nepomuk COMPONENT Devel
 )
diff --git a/nepomuk/query/daterange.cpp b/nepomuk/query/daterange.cpp
new file mode 100644
index 0000000..123d62b
--- /dev/null
+++ b/nepomuk/query/daterange.cpp
@@ -0,0 +1,151 @@
+/*
+   Copyright (c) 2009-2010 Sebastian Trueg <trueg@kde.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License or (at your option) version 3 or any later version
+   accepted by the membership of KDE e.V. (or its successor approved
+   by the membership of KDE e.V.), which shall act as a proxy
+   defined in Section 14 of version 3 of the license.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "daterange.h"
+
+#include "kglobal.h"
+#include "klocale.h"
+#include "kcalendarsystem.h"
+
+#include <QtCore/QSharedData>
+
+
+class DateRange::Private : public QSharedData
+{
+public:
+    QDate m_start;
+    QDate m_end;
+};
+
+
+DateRange::DateRange( const QDate& s,
+                      const QDate& e )
+    : d(new Private())
+{
+    d->m_start = s;
+    d->m_end = e;
+}
+
+
+DateRange::DateRange( const DateRange& other )
+{
+    d = other.d;
+}
+
+
+DateRange::~DateRange()
+{
+}
+
+
+DateRange& DateRange::operator=( const DateRange& other )
+{
+    d = other.d;
+    return *this;
+}
+
+
+QDate DateRange::start() const
+{
+    return d->m_start;
+}
+
+
+QDate DateRange::end() const
+{
+    return d->m_end;
+}
+
+
+bool DateRange::isValid() const
+{
+    return d->m_start.isValid() && d->m_end.isValid() && d->m_start <= d->m_end;
+}
+
+
+// static
+DateRange DateRange::today()
+{
+    return DateRange( QDate::currentDate(), QDate::currentDate() );
+}
+
+
+namespace {
+    /**
+     * Put \p day into the week range 1...7
+     */
+    int dateModulo( int day ) {
+        day = day%7;
+        if ( day == 0 )
+            return 7;
+        else
+            return day;
+    }
+}
+
+// static
+DateRange DateRange::thisWeek()
+{
+    return weekOf( QDate::currentDate() );
+}
+
+
+// static
+DateRange DateRange::weekOf( const QDate& date )
+{
+    const int weekStartDay = KGlobal::locale()->weekStartDay();
+    const int weekEndDay = dateModulo( weekStartDay+6 );
+
+    DateRange range;
+
+    if ( weekStartDay > date.dayOfWeek() )
+        range.d->m_start = date.addDays( - (date.dayOfWeek() + 7 - weekStartDay) );
+    else
+        range.d->m_start = date.addDays( - (date.dayOfWeek() - weekStartDay) );
+
+    if ( weekEndDay < date.dayOfWeek() )
+        range.d->m_end = date.addDays( weekEndDay + 7 - date.dayOfWeek() );
+    else
+        range.d->m_end = date.addDays( weekEndDay - date.dayOfWeek() );
+
+    return range;
+}
+
+
+// static
+DateRange DateRange::thisMonth()
+{
+    return monthOf( QDate::currentDate() );
+}
+
+
+// static
+DateRange DateRange::monthOf( const QDate& date )
+{
+    return DateRange( QDate( date.year(), date.month(), 1 ),
+                      QDate( date.year(), date.month(), \
KGlobal::locale()->calendar()->daysInMonth( date ) ) ); +}
+
+
+bool operator==( const DateRange& r1, const DateRange& r2 )
+{
+    return r1.start() == r2.start() && r1.end() == r2.end();
+}
diff --git a/nepomuk/query/daterange.h b/nepomuk/query/daterange.h
new file mode 100644
index 0000000..5c00de2
--- /dev/null
+++ b/nepomuk/query/daterange.h
@@ -0,0 +1,104 @@
+/*
+   Copyright (c) 2009-2010 Sebastian Trueg <trueg@kde.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License or (at your option) version 3 or any later version
+   accepted by the membership of KDE e.V. (or its successor approved
+   by the membership of KDE e.V.), which shall act as a proxy
+   defined in Section 14 of version 3 of the license.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _DATE_RANGE_H_
+#define _DATE_RANGE_H_
+
+#include <QtCore/QDate>
+#include <QtCore/QSharedDataPointer>
+
+/**
+ * \brief A simple data structure storing a start and an end date.
+ *
+ * \author Sebastian Trueg <trueg@kde.org>
+ */
+class DateRange
+{
+public:
+    /**
+     * Create a new range
+     */
+    DateRange( const QDate& s = QDate(),
+               const QDate& e = QDate() );
+
+    /**
+     * Copy constructor
+     */
+    DateRange( const DateRange& other );
+
+    /**
+     * Destructor
+     */
+    ~DateRange();
+
+    /**
+     * Make this range a copy of \p other
+     */
+    DateRange& operator=( const DateRange& other );
+
+    /**
+     * Start date of the range.
+     */
+    QDate start() const;
+
+    /**
+     * End date of the range.
+     */
+    QDate end() const;
+
+    /**
+     * Checks if both start and end are valid dates
+     * and if end is after start.
+     */
+    bool isValid() const;
+
+    /**
+     * \returns a DateRange with both start and end
+     * dates set to QDate::currentDate()
+     */
+    static DateRange today();
+
+    /**
+     * Takes KLocale::weekStartDay() into account.
+     */
+    static DateRange thisWeek();
+
+    /**
+     * Takes KLocale::weekStartDay() into account.
+     */
+    static DateRange weekOf( const QDate& date );
+
+    static DateRange thisMonth();
+    static DateRange monthOf( const QDate& date );
+
+private:
+    class Private;
+    QSharedDataPointer<Private> d;
+};
+
+/**
+ * Comparison operator
+ *
+ * \related DateRange
+ */
+bool operator==( const DateRange& r1, const DateRange& r2 );
+
+#endif
diff --git a/nepomuk/query/daterangeselectionwidget.cpp \
b/nepomuk/query/daterangeselectionwidget.cpp new file mode 100644
index 0000000..41c1934
--- /dev/null
+++ b/nepomuk/query/daterangeselectionwidget.cpp
@@ -0,0 +1,336 @@
+/*
+   Copyright (c) 2009 Sebastian Trueg <trueg@kde.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License or (at your option) version 3 or any later version
+   accepted by the membership of KDE e.V. (or its successor approved
+   by the membership of KDE e.V.), which shall act as a proxy
+   defined in Section 14 of version 3 of the license.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "daterangeselectionwidget.h"
+#include "ui_daterangeselectionwidget.h"
+#include "daterange.h"
+
+#include <QtGui/QToolButton>
+#include <QtGui/QCalendarWidget>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QDateEdit>
+#include <QtGui/QTextCharFormat>
+#include <QtGui/QPalette>
+#include <QtGui/QAction>
+#include <QtGui/QMenu>
+#include <QtCore/QHash>
+
+
+class DateRangeSelectionWidget::Private : public Ui::DateRangeSelectionWidgetBase
+{
+public:
+    void _k_anytimeClicked();
+    void _k_beforeClicked();
+    void _k_afterClicked();
+    void _k_rangeClicked();
+    void _k_rangeClicked( QAction* );
+    void _k_rangeStartEdited( const QDate& date );
+    void _k_rangeEndEdited( const QDate& date );
+    void _k_calendarDateClicked( const QDate& date );
+
+    void checkButton( QAbstractButton* button );
+    void setupPopupMenus();
+
+    void updateCalendar( const DateRange& range );
+    void updateEditBoxes( const DateRange& range );
+
+    void setRange( const DateRange& range );
+
+    QAction* findRangeAction( const DateRange& range );
+
+    DateRange m_range;
+
+    QAction* m_currentRangeAction;
+    QHash<QAction*, DateRange> m_rangeActionMap;
+
+    DateRangeSelectionWidget* q;
+};
+
+
+void DateRangeSelectionWidget::Private::_k_anytimeClicked()
+{
+    checkButton( m_anytimeButton );
+    setRange( DateRange() );
+
+    emit q->rangeChanged( m_range );
+}
+
+
+void DateRangeSelectionWidget::Private::_k_beforeClicked()
+{
+    if ( m_range.end().isValid() )
+        setRange( DateRange( QDate(), m_range.end() ) );
+    else if ( m_range.start().isValid() )
+        setRange( DateRange( QDate(), m_range.start() ) );
+    else
+        setRange( DateRange( QDate(), QDate::currentDate() ) );
+
+    emit q->rangeChanged( m_range );
+}
+
+
+void DateRangeSelectionWidget::Private::_k_afterClicked()
+{
+    if ( m_range.start().isValid() )
+        setRange( DateRange( m_range.start(), QDate() ) );
+    else if ( m_range.end().isValid() )
+        setRange( DateRange( m_range.end(), QDate() ) );
+    else
+        setRange( DateRange( QDate::currentDate(), QDate() ) );
+
+    emit q->rangeChanged( m_range );
+}
+
+
+void DateRangeSelectionWidget::Private::_k_rangeClicked()
+{
+    _k_rangeClicked( m_currentRangeAction );
+}
+
+
+void DateRangeSelectionWidget::Private::_k_rangeClicked( QAction* action )
+{
+    m_currentRangeAction = action;
+    m_rangesButton->setText( action->text() );
+    setRange( m_rangeActionMap[action] );
+
+    emit q->rangeChanged( m_range );
+}
+
+
+void DateRangeSelectionWidget::Private::_k_rangeStartEdited( const QDate& date )
+{
+    if ( date > m_range.end() )
+        setRange( DateRange( date, date ) );
+    else
+        setRange( DateRange( date, m_range.end() ) );
+
+    emit q->rangeChanged( m_range );
+}
+
+
+void DateRangeSelectionWidget::Private::_k_rangeEndEdited( const QDate& date )
+{
+    if ( date < m_range.start() )
+        setRange( DateRange( date, date ) );
+    else
+        setRange( DateRange( m_range.start(), date ) );
+
+    emit q->rangeChanged( m_range );
+}
+
+
+void DateRangeSelectionWidget::Private::_k_calendarDateClicked( const QDate& date )
+{
+    if ( QApplication::keyboardModifiers() & Qt::ShiftModifier ) {
+        if ( m_range.start().isValid() &&
+             date < m_range.start() ) {
+            setRange( DateRange( date, m_range.end().isValid() ? m_range.end() : \
m_range.start() ) ); +            emit q->rangeChanged( m_range );
+        }
+        else if ( m_range.end().isValid() &&
+                  date < m_range.end() ) {
+            setRange( DateRange( date, m_range.end() ) );
+            emit q->rangeChanged( m_range );
+        }
+        else if ( m_range.end().isValid() &&
+                  date > m_range.end() ) {
+            setRange( DateRange( m_range.start().isValid() ? m_range.start() : \
m_range.end(), date ) ); +            emit q->rangeChanged( m_range );
+        }
+        else if ( m_range.start().isValid() &&
+                  date > m_range.start() ) {
+            setRange( DateRange( m_range.start(), date ) );
+            emit q->rangeChanged( m_range );
+        }
+    }
+    else if ( m_beforeButton->isChecked() ) {
+        setRange( DateRange( QDate(), date ) );
+        emit q->rangeChanged( m_range );
+    }
+    else if ( m_afterButton->isChecked() ) {
+        setRange( DateRange( date, QDate() ) );
+        emit q->rangeChanged( m_range );
+    }
+    else {
+        setRange( DateRange( date, date ) );
+        emit q->rangeChanged( m_range );
+    }
+}
+
+
+void DateRangeSelectionWidget::Private::checkButton( QAbstractButton* button )
+{
+    foreach( QAbstractButton* b, m_buttonGroup->buttons() ) {
+        b->setChecked( b == button );
+    }
+}
+
+
+void DateRangeSelectionWidget::Private::setupPopupMenus()
+{
+    QMenu* menu = new QMenu(m_rangesButton);
+
+    QAction* a = new QAction( menu );
+    a->setText( i18n( "Today" ) );
+    m_rangeActionMap.insert( a, DateRange::today() );
+    menu->addAction( a );
+
+    // today is the default
+    m_currentRangeAction = a;
+
+    a = new QAction( menu );
+    a->setText( i18n( "This Week" ) );
+    m_rangeActionMap.insert( a, DateRange::thisWeek() );
+    menu->addAction( a );
+
+    a = new QAction( menu );
+    a->setText( i18n( "This Month" ) );
+    m_rangeActionMap.insert( a, DateRange::thisMonth() );
+    menu->addAction( a );
+
+    m_rangesButton->setMenu( menu );
+}
+
+
+void DateRangeSelectionWidget::Private::updateCalendar( const DateRange& range )
+{
+    m_calendar->setDateTextFormat( QDate(), QTextCharFormat() );
+    if ( range.start().isValid() )
+        m_calendar->setSelectedDate( range.start() );
+    else if ( range.end().isValid() )
+        m_calendar->setSelectedDate( range.end() );
+    else
+        m_calendar->setSelectedDate( QDate::currentDate() );
+    if ( range.isValid() ) {
+        QTextCharFormat selectedFormat;
+        selectedFormat.setBackground( q->palette().color( QPalette::Highlight ) );
+        selectedFormat.setForeground( q->palette().color( QPalette::HighlightedText \
) ); +        for ( QDate date = range.start(); date <= range.end(); date = \
date.addDays( 1 ) ) { +            m_calendar->setDateTextFormat( date, \
selectedFormat ); +        }
+    }
+}
+
+
+void DateRangeSelectionWidget::Private::updateEditBoxes( const DateRange& range )
+{
+    m_rangeStartEdit->blockSignals( true );
+    m_rangeEndEdit->blockSignals( true );
+
+    m_rangeStartEdit->setDate( range.start() );
+    m_rangeEndEdit->setDate( range.end() );
+    m_rangeStartEdit->setEnabled( range.start().isValid() );
+    m_rangeEndEdit->setEnabled( range.end().isValid() );
+
+    m_rangeStartEdit->blockSignals( false );
+    m_rangeEndEdit->blockSignals( false );
+}
+
+
+void DateRangeSelectionWidget::Private::setRange( const DateRange& range )
+{
+    m_range = range;
+
+    if ( range.isValid() ) {
+        if ( QAction* a = findRangeAction( range ) ) {
+            m_currentRangeAction = a;
+            m_rangesButton->setText( a->text() );
+            checkButton( m_rangesButton );
+        }
+        else {
+            checkButton( 0 );
+        }
+    }
+    else if ( range.start().isValid() ) {
+        checkButton( m_afterButton );
+    }
+    else if ( range.end().isValid() ) {
+        checkButton( m_beforeButton );
+    }
+    else {
+        checkButton( m_anytimeButton );
+    }
+
+    updateCalendar( range );
+    updateEditBoxes( range );
+}
+
+
+QAction* DateRangeSelectionWidget::Private::findRangeAction( const DateRange& range \
) +{
+    // We have only 3 elements in here, thus, looping over them is ok
+    for ( QHash<QAction*, DateRange>::const_iterator it = \
m_rangeActionMap.constBegin(); +          it != m_rangeActionMap.constEnd(); ++it ) {
+        if ( it.value() == range )
+            return it.key();
+    }
+    return 0;
+}
+
+
+DateRangeSelectionWidget::DateRangeSelectionWidget( QWidget* parent )
+    : QWidget( parent ),
+      d( new Private() )
+{
+    d->q = this;
+    d->setupUi( this );
+    d->setupPopupMenus();
+
+    d->m_calendar->setFirstDayOfWeek( Qt::DayOfWeek( \
KGlobal::locale()->weekStartDay() ) ); +    connect( d->m_anytimeButton, SIGNAL( \
clicked() ), +             this, SLOT( _k_anytimeClicked() ) );
+    connect( d->m_beforeButton, SIGNAL( clicked() ),
+             this, SLOT( _k_beforeClicked() ) );
+    connect( d->m_afterButton, SIGNAL( clicked() ),
+             this, SLOT( _k_afterClicked() ) );
+    connect( d->m_rangesButton, SIGNAL( clicked() ),
+             this, SLOT( _k_rangeClicked() ) );
+    connect( d->m_rangesButton, SIGNAL( triggered(QAction*) ),
+             this, SLOT( _k_rangeClicked(QAction*) ) );
+    connect( d->m_rangeStartEdit, SIGNAL( dateChanged( QDate ) ),
+             this, SLOT( _k_rangeStartEdited( QDate ) ) );
+    connect( d->m_rangeEndEdit, SIGNAL( dateChanged( QDate ) ),
+             this, SLOT( _k_rangeEndEdited( QDate ) ) );
+    connect( d->m_calendar, SIGNAL( clicked( QDate ) ),
+             this, SLOT( _k_calendarDateClicked( QDate ) ) );
+
+    setRange( DateRange() );
+}
+
+
+DateRangeSelectionWidget::~DateRangeSelectionWidget()
+{
+}
+
+
+DateRange DateRangeSelectionWidget::range() const
+{
+    return d->m_range;
+}
+
+
+void DateRangeSelectionWidget::setRange( const DateRange& range )
+{
+    d->setRange( range );
+}
+
+#include "daterangeselectionwidget.moc"
diff --git a/nepomuk/query/daterangeselectionwidget.h \
b/nepomuk/query/daterangeselectionwidget.h new file mode 100644
index 0000000..d99a432
--- /dev/null
+++ b/nepomuk/query/daterangeselectionwidget.h
@@ -0,0 +1,68 @@
+/*
+   Copyright (c) 2009 Sebastian Trueg <trueg@kde.org>
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License or (at your option) version 3 or any later version
+   accepted by the membership of KDE e.V. (or its successor approved
+   by the membership of KDE e.V.), which shall act as a proxy
+   defined in Section 14 of version 3 of the license.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef _DATE_RANGE_SELECTION_WIDGET_H_
+#define _DATE_RANGE_SELECTION_WIDGET_H_
+
+#include <QtGui/QWidget>
+#include <QtCore/QDate>
+
+class DateRange;
+class QAction;
+
+class DateRangeSelectionWidget : public QWidget
+{
+    Q_OBJECT
+
+public:
+    DateRangeSelectionWidget( QWidget* parent = 0 );
+    ~DateRangeSelectionWidget();
+
+    /**
+     * One of:
+     * \li a range between two valid dates
+     * \li only a valid end date: all dates before that date
+     * \li only a valid start date: all dates after that date
+     * \li invalid range: anytime
+     */
+    DateRange range() const;
+
+public Q_SLOTS:
+    void setRange( const DateRange& range );
+
+Q_SIGNALS:
+    void rangeChanged( const DateRange& range );
+
+private:
+    class Private;
+    Private* const d;
+
+    Q_PRIVATE_SLOT( d, void _k_anytimeClicked() )
+    Q_PRIVATE_SLOT( d, void _k_beforeClicked() )
+    Q_PRIVATE_SLOT( d, void _k_afterClicked() )
+    Q_PRIVATE_SLOT( d, void _k_rangeClicked() )
+    Q_PRIVATE_SLOT( d, void _k_rangeClicked( QAction* ) )
+    Q_PRIVATE_SLOT( d, void _k_rangeStartEdited( const QDate& date ) )
+    Q_PRIVATE_SLOT( d, void _k_rangeEndEdited( const QDate& date ) )
+    Q_PRIVATE_SLOT( d, void _k_calendarDateClicked( const QDate& date ) )
+};
+
+#endif
diff --git a/nepomuk/query/daterangeselectionwidget.ui \
b/nepomuk/query/daterangeselectionwidget.ui new file mode 100644
index 0000000..30a3b62
--- /dev/null
+++ b/nepomuk/query/daterangeselectionwidget.ui
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <author>Sebastian Trueg &lt;trueg@kde.org&gt;</author>
+ <class>DateRangeSelectionWidgetBase</class>
+ <widget class="QWidget" name="DateRangeSelectionWidgetBase">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>364</width>
+    <height>240</height>
+   </rect>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>0</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QToolButton" name="m_anytimeButton">
+       <property name="text">
+        <string>Anytime</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <property name="autoRaise">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string>m_buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="m_beforeButton">
+       <property name="text">
+        <string>Before</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <property name="autoRaise">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string>m_buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="m_afterButton">
+       <property name="text">
+        <string>After</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <property name="autoRaise">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string>m_buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+     <item>
+      <widget class="QToolButton" name="m_rangesButton">
+       <property name="text">
+        <string>Today</string>
+       </property>
+       <property name="checkable">
+        <bool>true</bool>
+       </property>
+       <property name="popupMode">
+        <enum>QToolButton::MenuButtonPopup</enum>
+       </property>
+       <property name="autoRaise">
+        <bool>true</bool>
+       </property>
+       <attribute name="buttonGroup">
+        <string>m_buttonGroup</string>
+       </attribute>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QCalendarWidget" name="m_calendar"/>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <widget class="QDateEdit" name="m_rangeStartEdit"/>
+     </item>
+     <item>
+      <widget class="QDateEdit" name="m_rangeEndEdit"/>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+ <buttongroups>
+  <buttongroup name="m_buttonGroup">
+   <property name="exclusive">
+    <bool>false</bool>
+   </property>
+  </buttongroup>
+ </buttongroups>
+</ui>
diff --git a/nepomuk/query/dynamiclistfacetwidget.cpp \
b/nepomuk/query/dynamiclistfacetwidget.cpp new file mode 100644
index 0000000..8133152
--- /dev/null
+++ b/nepomuk/query/dynamiclistfacetwidget.cpp
@@ -0,0 +1,154 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "dynamiclistfacetwidget.h"
+#include "resource.h"
+#include "resourcemanager.h"
+#include "resourceterm.h"
+
+#include "query.h"
+#include "comparisonterm.h"
+
+#include <Soprano/Util/AsyncQuery>
+#include <Soprano/BindingSet>
+#include <Soprano/Node>
+
+#include <QtCore/QVariant>
+
+#include "kdebug.h"
+
+
+Q_DECLARE_METATYPE(Soprano::BindingSet)
+
+
+class Nepomuk::Query::DynamicListFacetWidget::Private
+{
+public:
+    Query m_populationQuery;
+    int m_limit;
+
+    int m_moreButtonId;
+
+    Soprano::Util::AsyncQuery* m_lastQuery;
+
+    void _k_populateNextResult(Soprano::Util::AsyncQuery*);
+    void _k_populateFinished(Soprano::Util::AsyncQuery*);
+
+    DynamicListFacetWidget* q;
+};
+
+
+void Nepomuk::Query::DynamicListFacetWidget::Private::_k_populateNextResult( \
Soprano::Util::AsyncQuery* query ) +{
+    kDebug();
+    if( q->count() == m_limit ) {
+        // TODO: add the more... button
+    }
+    else {
+        q->addButton( q->titleForResult( query->currentBindings() ), \
QVariant::fromValue( query->currentBindings() ) ); +    }
+    query->next();
+}
+
+
+void Nepomuk::Query::DynamicListFacetWidget::Private::_k_populateFinished( \
Soprano::Util::AsyncQuery* query ) +{
+    kDebug();
+    // TODO: disable the busy thingi (once we have one)
+}
+
+
+Nepomuk::Query::DynamicListFacetWidget::DynamicListFacetWidget( QWidget* parent )
+    : ListFacetWidget( parent ),
+      d(new Private())
+{
+    d->q = this;
+    d->m_lastQuery = 0;
+    d->m_limit = 6; // TODO: make configurable
+    d->m_moreButtonId = -1;
+}
+
+
+Nepomuk::Query::DynamicListFacetWidget::~DynamicListFacetWidget()
+{
+    delete d;
+}
+
+
+void Nepomuk::Query::DynamicListFacetWidget::setPopulationQuery( const \
Nepomuk::Query::Query& query ) +{
+    d->m_populationQuery = query;
+}
+
+
+void Nepomuk::Query::DynamicListFacetWidget::populate()
+{
+    kDebug();
+    clear();
+    if( d->m_lastQuery ) {
+        d->m_lastQuery->disconnect();
+        d->m_lastQuery = 0;
+    }
+
+    // TODO: show some busy thingi
+
+    Query query( d->m_populationQuery );
+    query.setLimit( d->m_limit+1 );
+    kDebug() << query.toSparqlQuery();
+    d->m_lastQuery = Soprano::Util::AsyncQuery::executeQuery( \
ResourceManager::instance()->mainModel(), +                                           \
query.toSparqlQuery(), +                                                              \
Soprano::Query::QueryLanguageSparql ); +    connect( d->m_lastQuery, \
SIGNAL(nextReady(Soprano::Util::AsyncQuery*)), +             this, \
SLOT(_k_populateNextResult(Soprano::Util::AsyncQuery*)) ); +    connect( \
d->m_lastQuery, SIGNAL(finished(Soprano::Util::AsyncQuery*)), +             this, \
SLOT(_k_populateFinished(Soprano::Util::AsyncQuery*)) ); +}
+
+
+QString Nepomuk::Query::DynamicListFacetWidget::titleForResult( const \
Soprano::BindingSet& bindings ) const +{
+    return Resource( bindings[0].uri() ).genericLabel();
+}
+
+
+Nepomuk::Query::Term Nepomuk::Query::DynamicListFacetWidget::termForResult( const \
Soprano::BindingSet& bindings ) const +{
+    return ComparisonTerm( Types::Property(), ResourceTerm( bindings[0].uri() ) );
+}
+
+
+Nepomuk::Query::Term Nepomuk::Query::DynamicListFacetWidget::termForButton( int \
button, const QVariant& data ) const +{
+    Q_UNUSED(button);
+    return termForResult( data.value<Soprano::BindingSet>() );
+}
+
+
+void Nepomuk::Query::DynamicListFacetWidget::buttonClicked( int button, const \
QVariant& data ) +{
+    if( button == d->m_moreButtonId ) {
+        // TODO: open dialog
+    }
+
+    ListFacetWidget::buttonClicked( button, data );
+}
+
+#include "dynamiclistfacetwidget.moc"
diff --git a/nepomuk/query/dynamiclistfacetwidget.h \
b/nepomuk/query/dynamiclistfacetwidget.h new file mode 100644
index 0000000..bcc806c
--- /dev/null
+++ b/nepomuk/query/dynamiclistfacetwidget.h
@@ -0,0 +1,68 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NEPOMUK_QUERY_DYNAMIC_LIST_FACET_WIDGET_H_
+#define _NEPOMUK_QUERY_DYNAMIC_LIST_FACET_WIDGET_H_
+
+#include "listfacetwidget.h"
+#include "nepomukquery_export.h"
+
+namespace Soprano {
+    class BindingSet;
+    namespace Util {
+        class AsyncQuery;
+    }
+}
+
+namespace Nepomuk {
+    namespace Query {
+        class Query;
+
+        class NEPOMUKQUERY_EXPORT DynamicListFacetWidget : public ListFacetWidget
+        {
+            Q_OBJECT
+
+        public:
+            DynamicListFacetWidget( QWidget* parent = 0 );
+            virtual ~DynamicListFacetWidget();
+
+        public Q_SLOTS:
+            void setPopulationQuery( const Nepomuk::Query::Query& query );
+            void populate();
+
+        protected:
+            virtual QString titleForResult( const Soprano::BindingSet& bindings ) \
const; +            virtual Term termForResult( const Soprano::BindingSet& bindings ) \
const; +
+        private:
+            Term termForButton( int button, const QVariant& data ) const;
+            void buttonClicked( int button, const QVariant& data );
+
+            class Private;
+            Private* const d;
+
+            Q_PRIVATE_SLOT( d, void \
_k_populateNextResult(Soprano::Util::AsyncQuery*) ) +            Q_PRIVATE_SLOT( d, \
void _k_populateFinished(Soprano::Util::AsyncQuery*) ) +        };
+    }
+}
+
+#endif
diff --git a/nepomuk/query/facetwidget.cpp b/nepomuk/query/facetwidget.cpp
new file mode 100644
index 0000000..c2e961b
--- /dev/null
+++ b/nepomuk/query/facetwidget.cpp
@@ -0,0 +1,252 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "facetwidget.h"
+#include "simplelistfacetwidget.h"
+#include "rangedfacetwidget.h"
+#include "dynamiclistfacetwidget.h"
+#include "daterangeselectionwidget.h"
+#include "daterange.h"
+#include "query.h"
+
+#include <QtCore/QDate>
+#include <QtGui/QCursor>
+
+#include <Soprano/Vocabulary/NAO>
+#include <Soprano/BindingSet>
+
+#include "andterm.h"
+#include "orterm.h"
+#include "comparisonterm.h"
+#include "literalterm.h"
+#include "resourceterm.h"
+#include "resourcetypeterm.h"
+#include "standardqueries.h"
+#include "query.h"
+
+#include "tag.h"
+#include "property.h"
+#include "resource.h"
+
+#include "tmo.h"
+#include "nmo.h"
+#include "nco.h"
+#include "nfo.h"
+#include "nie.h"
+
+#include "kdebug.h"
+#include "kglobal.h"
+#include "klocale.h"
+#include "kcalendarsystem.h"
+#include "kdialog.h"
+
+
+class Nepomuk::Query::FacetWidget::Private
+{
+public:
+};
+
+
+Nepomuk::Query::FacetWidget::FacetWidget( QWidget* parent )
+    : QWidget( parent ),
+      d(new Private())
+{
+}
+
+
+Nepomuk::Query::FacetWidget::~FacetWidget()
+{
+    delete d;
+}
+
+
+bool Nepomuk::Query::FacetWidget::selectFromTerm( const Term& term )
+{
+    return doSelectFromTerm( term );
+}
+
+
+void Nepomuk::Query::FacetWidget::clearSelection()
+{
+    return doClearSelection();
+}
+
+
+void Nepomuk::Query::FacetWidget::setTermChanged()
+{
+    emit termChanged( term() );
+}
+
+
+// static
+Nepomuk::Query::FacetWidget* Nepomuk::Query::FacetWidget::createFileTypeFacet( \
QWidget* parent ) +{
+    SimpleListFacetWidget* w = new SimpleListFacetWidget( parent );
+    w->setSelectionMode( ListFacetWidget::MatchOne );
+    w->addTerm( i18n("Documents"),
+                ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Document()) );
+
+    // need to check the mimetype as well since strigi is still not perfect
+    w->addTerm( i18n("Media"),
+                ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Audio()) ||
+                ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Video()) ||
+                ComparisonTerm(Nepomuk::Vocabulary::NIE::mimeType(), \
LiteralTerm(QLatin1String("video"))) || +                \
ComparisonTerm(Nepomuk::Vocabulary::NIE::mimeType(), \
LiteralTerm(QLatin1String("audio"))) ); +
+    w->addTerm( i18n("Images"),
+                ResourceTypeTerm(Nepomuk::Vocabulary::NFO::Image()) );
+    return w;
+}
+
+
+// static
+Nepomuk::Query::FacetWidget* Nepomuk::Query::FacetWidget::createTypeFacet( QWidget* \
parent ) +{
+    SimpleListFacetWidget* w = new SimpleListFacetWidget( parent );
+    w->setSelectionMode( ListFacetWidget::MatchOne );
+    w->addTerm(i18n("Files"),
+               ResourceTypeTerm(Nepomuk::Vocabulary::NFO::FileDataObject()) );
+    w->addTerm(i18n("Contacts"),
+               ResourceTypeTerm(Nepomuk::Vocabulary::NCO::Contact()));
+    w->addTerm(i18n("Emails"),
+               ResourceTypeTerm(Nepomuk::Vocabulary::NMO::Email()));
+    w->addTerm(i18n("Tasks"),
+               ResourceTypeTerm(Nepomuk::Vocabulary::TMO::Task()));
+    w->addTerm(i18n("Tags"),
+               ResourceTypeTerm(Soprano::Vocabulary::NAO::Tag()));
+    return w;
+}
+
+
+namespace {
+    class DateRangeFacetWidget : public Nepomuk::Query::RangedFacetWidget
+    {
+    public:
+        DateRangeFacetWidget( QWidget* parent )
+            : RangedFacetWidget( parent ) {
+            setProperty( Nepomuk::Vocabulary::NIE::lastModified() );
+        }
+
+    protected:
+        Nepomuk::Query::Term buildRangeTerm( const QVariant& start, const QVariant& \
end ) const { +            if( start.isValid() ) {
+                return Nepomuk::Query::dateRangeQuery( start.toDate(), end.toDate() \
).term(); +            }
+            else {
+                return Nepomuk::Query::Term();
+            }
+        }
+
+        Nepomuk::Query::RangedFacetWidget::Range getCustomRange() const {
+            KDialog dlg;
+            dlg.setWindowFlags(Qt::Popup);
+            dlg.setButtons( KDialog::Ok );
+            DateRangeSelectionWidget* drw = new DateRangeSelectionWidget( &dlg );
+            drw->setRange( currentDateRange() );
+            dlg.setMainWidget( drw );
+            dlg.move(QCursor::pos());
+            dlg.exec();
+            DateRange range = drw->range();
+            return qMakePair( QVariant(range.start()), QVariant(range.end()) );
+        }
+
+    private:
+        DateRange currentDateRange() const {
+            Range range = currentRange();
+            return DateRange( range.first.toDate(), range.second.toDate() );
+        }
+    };
+}
+
+// static
+// FIXME: a dolphin instance which is running more than a day will have wrong date \
facets! +//        We could add a special DateTerm which takes that into account and \
always uses the current datetime +Nepomuk::Query::FacetWidget* \
Nepomuk::Query::FacetWidget::createDateFacet( QWidget* parent ) +{
+    DateRangeFacetWidget* w = new DateRangeFacetWidget( parent );
+    const QDate today = QDate::currentDate();
+
+    w->addFixedValue( QDate(), i18n("Anytime") );
+    w->addFixedValue( today, i18n("Today") );
+    w->addFixedRange( today.addDays(-1), today.addDays(-1), i18n("Yesterday") );
+    const DateRange thisWeek = DateRange::thisWeek();
+    w->addFixedRange( thisWeek.start(),
+                      thisWeek.end(),
+                      i18n("This week") );
+    const DateRange thisMonth = DateRange::thisMonth();
+    w->addFixedRange( thisMonth.start(),
+                      thisMonth.end(),
+                      i18n("This month") );
+    w->addFixedRange( QDate( QDate::currentDate().year(), 1, 1 ),
+                      QDate( QDate::currentDate().year(), 12, 31),
+                      i18n("This year") );
+    w->addCustomRangeButton( i18n("Other date...") );
+    return w;
+}
+
+
+namespace {
+    class TagFacetWidget : public Nepomuk::Query::DynamicListFacetWidget
+    {
+    public:
+        TagFacetWidget( QWidget* parent )
+            : Nepomuk::Query::DynamicListFacetWidget( parent ) {
+
+            setSelectionMode(ListFacetWidget::MatchAll);
+
+            // get the most used tags
+            Nepomuk::Query::ComparisonTerm term( Soprano::Vocabulary::NAO::hasTag(), \
Nepomuk::Query::Term() ); +            term.setSortWeight( 1, Qt::DescendingOrder );
+            term.setAggregateFunction( Nepomuk::Query::ComparisonTerm::Count );
+            setPopulationQuery( Nepomuk::Query::Query( \
Nepomuk::Query::ResourceTypeTerm( Soprano::Vocabulary::NAO::Tag() ) && \
term.inverted() ) ); +        }
+        ~TagFacetWidget() {
+        }
+
+    private:
+        Nepomuk::Query::Term termForResult( const Soprano::BindingSet& bindings ) \
const { +            return Soprano::Vocabulary::NAO::hasTag() == \
Nepomuk::Query::ResourceTerm( bindings[0].uri() ); +        }
+    };
+}
+
+// static
+Nepomuk::Query::FacetWidget* Nepomuk::Query::FacetWidget::createTagFacet( QWidget* \
parent ) +{
+    TagFacetWidget* w = new TagFacetWidget( parent );
+    w->populate();
+    return w;
+}
+
+
+// static
+Nepomuk::Query::FacetWidget* Nepomuk::Query::FacetWidget::createPriorityFacet( \
QWidget* parent ) +{
+    SimpleListFacetWidget* w = new SimpleListFacetWidget( parent );
+    w->setSelectionMode(ListFacetWidget::Exclusive);
+    w->addTerm(i18n("No priority"), Term());
+    w->addTerm( i18n("Last modified"), standardQuery( LastModifiedFilesQuery \
).term() ); +    w->addTerm( i18n("Most important"), standardQuery( \
MostImportantResourcesQuery ).term() ); +    w->addTerm( i18n("Never opened"), \
standardQuery( NeverOpenedFilesQuery ).term() ); +    return w;
+}
+
+#include "facetwidget.moc"
diff --git a/nepomuk/query/facetwidget.h b/nepomuk/query/facetwidget.h
new file mode 100644
index 0000000..cd67c08
--- /dev/null
+++ b/nepomuk/query/facetwidget.h
@@ -0,0 +1,77 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NEPOMUK_QUERY_FACET_WIDGET_H_
+#define _NEPOMUK_QUERY_FACET_WIDGET_H_
+
+#include <QtGui/QWidget>
+
+#include "term.h"
+#include "nepomukquery_export.h"
+
+namespace Nepomuk {
+    namespace Query {
+        class NEPOMUKQUERY_EXPORT FacetWidget : public QWidget
+        {
+            Q_OBJECT
+
+        public:
+            FacetWidget( QWidget* parent = 0 );
+            ~FacetWidget();
+
+            virtual Term term() const = 0;
+
+            static FacetWidget* createFileTypeFacet( QWidget* parent = 0 );
+            static FacetWidget* createTypeFacet( QWidget* parent = 0 );
+            static FacetWidget* createDateFacet( QWidget* parent = 0 );
+            static FacetWidget* createTagFacet( QWidget* parent = 0 );
+            static FacetWidget* createPriorityFacet( QWidget* parent = 0 );
+
+        public Q_SLOTS:
+            bool selectFromTerm( const Term& term );
+            void clearSelection();
+
+        Q_SIGNALS:
+            void termChanged( const Nepomuk::Query::Term& term );
+
+        protected Q_SLOTS:
+            /**
+             * Use this instead of emitting the termChanged() signal.
+             */
+            void setTermChanged();
+
+        protected:
+            /**
+             * Make \p term the term in the widget if possible.
+             * In other words: if this method returns \p true a subsequent call
+             * to term() has to return \p term.
+             */
+            virtual bool doSelectFromTerm( const Term& term ) = 0;
+            virtual void doClearSelection() = 0;
+
+        private:
+            class Private;
+            Private* d;
+        };
+    }
+}
+
+#endif
diff --git a/nepomuk/query/facetwidgetcontroller.cpp \
b/nepomuk/query/facetwidgetcontroller.cpp new file mode 100644
index 0000000..2399706
--- /dev/null
+++ b/nepomuk/query/facetwidgetcontroller.cpp
@@ -0,0 +1,169 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "facetwidgetcontroller.h"
+#include "facetwidget.h"
+
+#include "query.h"
+#include "andterm.h"
+
+
+class Nepomuk::Query::FacetWidgetController::Private
+{
+public:
+    QList<FacetWidget*> m_widgets;
+    Query m_baseQuery;
+
+    bool m_interalFacetUpdate;
+
+    QList<Nepomuk::Query::Term> selectedTerms() const;
+
+    void _k_termChanged( const Nepomuk::Query::Term& );
+
+    FacetWidgetController* q;
+};
+
+
+QList<Nepomuk::Query::Term> \
Nepomuk::Query::FacetWidgetController::Private::selectedTerms() const +{
+    QList<Nepomuk::Query::Term> terms;
+    Q_FOREACH( FacetWidget* w, m_widgets ) {
+        terms.append(w->term());
+    }
+    return terms;
+}
+
+
+void Nepomuk::Query::FacetWidgetController::Private::_k_termChanged( const \
Nepomuk::Query::Term& ) +{
+    if( !m_interalFacetUpdate ) {
+        emit q->queryChanged( q->constructQuery() );
+    }
+}
+
+
+Nepomuk::Query::FacetWidgetController::FacetWidgetController( QObject* parent )
+    : QObject( parent ),
+      d(new Private())
+{
+    d->q = this;
+    d->m_interalFacetUpdate = false;
+}
+
+
+Nepomuk::Query::FacetWidgetController::~FacetWidgetController()
+{
+    delete d;
+}
+
+
+Nepomuk::Query::Query Nepomuk::Query::FacetWidgetController::constructQuery() const
+{
+    Query query( d->m_baseQuery );
+    Q_FOREACH( const Term& term, d->selectedTerms() ) {
+        query.setTerm( query.term() && term );
+    }
+    return query.optimized();
+}
+
+
+Nepomuk::Query::Query Nepomuk::Query::FacetWidgetController::baseQuery() const
+{
+    return d->m_baseQuery;
+}
+
+
+Nepomuk::Query::Query Nepomuk::Query::FacetWidgetController::setQuery( const Query& \
query ) +{
+    d->m_interalFacetUpdate = true;
+
+    // reset all facets in the model
+    // ================================
+    Q_FOREACH( FacetWidget* w, d->m_widgets ) {
+        w->clearSelection();
+    }
+
+    // we extract all facets we can find and leave the rest in the query
+    // ================================
+    d->m_baseQuery = query.optimized();
+
+    // first we check if the main term is already a facet term
+    // (this way we can also handle facets that use AndTerms)
+    // ================================
+    Term term = d->m_baseQuery.term();
+    // if any of the facets contains the term, set it to selected
+    Q_FOREACH( FacetWidget* w, d->m_widgets ) {
+        if( w->selectFromTerm( term ) ) {
+            d->m_baseQuery.setTerm( Term() );
+            break;
+        }
+    }
+
+    // now go into an AndTerm and check each sub term for facet
+    // ================================
+    if( d->m_baseQuery.term().isAndTerm() ) {
+        AndTerm restAndTerm;
+        foreach( const Term& term, d->m_baseQuery.term().toAndTerm().subTerms() ) {
+            bool termFound = false;
+
+            // FIXME: we cannot use an exclusive widget twice!
+            //        Example: we have an exclusive widget that can handle both term \
A and B +            //                 we now call selectFromTerm(A) and \
selectFromTerm(B) +            //                 both return true but only the \
latter is the one that sticks. +            //                 thus, we implicitely \
drop A from the query! +
+            Q_FOREACH( FacetWidget* w, d->m_widgets ) {
+                if( w->selectFromTerm( term ) ) {
+                    termFound = true;
+                    break;
+                }
+            }
+
+            // we did not find a matching facet
+            if( !termFound )
+                restAndTerm.addSubTerm( term );
+        }
+
+        d->m_baseQuery.setTerm( restAndTerm );
+    }
+
+    d->m_interalFacetUpdate = false;
+
+    d->m_baseQuery = d->m_baseQuery.optimized();
+
+    return d->m_baseQuery;
+}
+
+
+void Nepomuk::Query::FacetWidgetController::setBaseQuery( const Query& query )
+{
+    d->m_baseQuery = query;
+}
+
+
+void Nepomuk::Query::FacetWidgetController::addFacetWidget( FacetWidget* widget )
+{
+    d->m_widgets << widget;
+    connect( widget, SIGNAL(termChanged(Nepomuk::Query::Term)),
+             this, SLOT(_k_termChanged(Nepomuk::Query::Term)) );
+}
+
+#include "facetwidgetcontroller.moc"
diff --git a/nepomuk/query/facetwidgetcontroller.h \
b/nepomuk/query/facetwidgetcontroller.h new file mode 100644
index 0000000..c6dda57
--- /dev/null
+++ b/nepomuk/query/facetwidgetcontroller.h
@@ -0,0 +1,88 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NEPOMUK_QUERY_FACET_WIDGET_CONTROLLER_H_
+#define _NEPOMUK_QUERY_FACET_WIDGET_CONTROLLER_H_
+
+#include <QtCore/QObject>
+
+#include "nepomukquery_export.h"
+
+namespace Nepomuk {
+    namespace Query {
+
+        class Query;
+        class FacetWidget;
+
+        /**
+         * \brief Manages a set of FacetWidget instances.
+         *
+         * \author Sebastian Trueg <trueg@kde.org>
+         */
+        class NEPOMUKQUERY_EXPORT FacetWidgetController : public QObject
+        {
+            Q_OBJECT
+
+        public:
+            FacetWidgetController( QObject* parent = 0 );
+            ~FacetWidgetController();
+
+            /**
+             * \sa setBaseQuery()
+             */
+            Nepomuk::Query::Query baseQuery() const;
+
+            /**
+             * Construct a query from the selected facets in this model and \p \
baseQuery. +             *
+             * \return A new query which combines the facets in this model with \p \
baseQuery. +             */
+            Query constructQuery() const;
+
+            /**
+             * Extract as many facets from a query as possible. This method is not \
able to handle all +             * kinds of queries but works well on queries created \
via constructQuery(). +             *
+             * Facets supported by this model will be extracted from the \p query \
and configured +             * accordingly in the model.
+             *
+             * \return The rest query after facets have been extracted. This is also \
saved as baseQuery(). +             */
+            Nepomuk::Query::Query setQuery( const Query& query );
+
+        public Q_SLOTS:
+            void setBaseQuery( const Query& query );
+            void addFacetWidget( FacetWidget* widget );
+
+        Q_SIGNALS:
+            void queryChanged( const Nepomuk::Query::Query& query );
+
+        private:
+            class Private;
+            Private* const d;
+
+            Q_PRIVATE_SLOT( d, void _k_termChanged(const Nepomuk::Query::Term&) )
+        };
+    }
+}
+
+#endif
+
diff --git a/nepomuk/query/listfacetwidget.cpp b/nepomuk/query/listfacetwidget.cpp
new file mode 100644
index 0000000..c633ff9
--- /dev/null
+++ b/nepomuk/query/listfacetwidget.cpp
@@ -0,0 +1,410 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "listfacetwidget.h"
+#include "andterm.h"
+#include "orterm.h"
+
+#include <QtCore/QSet>
+#include <QtCore/QHash>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QVBoxLayout>
+#include <QtGui/QRadioButton>
+#include <QtGui/QCheckBox>
+
+#include "kdebug.h"
+
+namespace {
+    class Button
+    {
+    public:
+        Button()
+            : button(0) {
+        }
+
+        ~Button() {
+        }
+
+        /// the title used for the button
+        QString title;
+
+        /// id used by ListFacetWidget - this is not the id in the button group
+        int id;
+
+        /// used data set in addButton
+        QVariant data;
+
+        /// the currently representing button instance
+        QAbstractButton* button;
+    };
+}
+
+class Nepomuk::Query::ListFacetWidget::Private
+{
+public:
+    Private()
+        : m_buttonIdCnt(0),
+          m_selectionMode(Exclusive) {
+    }
+
+    int indexOf( const Term& term ) const;
+    void rebuildButtons();
+    QAbstractButton* createButton( const QString& title );
+
+    void _k_buttonClicked( int );
+
+    QList<Nepomuk::Query::Term> m_terms;
+    QStringList m_titles;
+
+    QButtonGroup m_buttonGroup;
+    QVBoxLayout* m_layout;
+
+    /// all existing buttons
+    QList<Button> m_buttons;
+
+    /// a mapping from ids to indexes in m_buttons
+    QHash<int, int> m_buttonIdMap;
+
+    /// a mapping from m_buttonGroup ids to indexes in m_buttons
+    QHash<int, int> m_buttonGroupIdMap;
+
+    /// counter to create unique ids
+    int m_buttonIdCnt;
+
+    SelectionMode m_selectionMode;
+
+    ListFacetWidget* q;
+};
+
+
+int Nepomuk::Query::ListFacetWidget::Private::indexOf( const Term& term ) const
+{
+    for( int i = 0; i < m_buttons.count(); ++i ) {
+        const Button& button = m_buttons[i];
+        if( term == q->termForButton( button.id, button.data ) )
+            return i;
+    }
+    return -1;
+}
+
+
+void Nepomuk::Query::ListFacetWidget::Private::rebuildButtons()
+{
+    m_buttonGroupIdMap.clear();
+    Q_FOREACH( const Button& button, m_buttons ) {
+        delete button.button;
+    }
+    for( int i = 0; i < m_buttons.count(); ++i ) {
+        m_buttons[i].button = createButton( m_buttons[i].title );
+        m_buttonGroupIdMap[m_buttonGroup.id(m_buttons[i].button)] = i;
+    }
+    if( !m_buttons.isEmpty() && q->isExclusive() )
+        m_buttons.first().button->setChecked(true);
+}
+
+
+QAbstractButton* Nepomuk::Query::ListFacetWidget::Private::createButton( const \
QString& title ) +{
+    QAbstractButton* button = 0;
+    if( m_buttonGroup.exclusive() )
+        button = new QRadioButton( q );
+    else
+        button = new QCheckBox( q );
+    button->setText( title );
+    m_buttonGroup.addButton( button );
+    m_layout->addWidget( button );
+    return button;
+}
+
+
+void Nepomuk::Query::ListFacetWidget::Private::_k_buttonClicked( int id )
+{
+    kDebug() << id << m_buttonGroupIdMap[id] << \
m_buttons[m_buttonGroupIdMap[id]].id; +    q->buttonClicked( \
m_buttons[m_buttonGroupIdMap[id]].id, m_buttons[m_buttonGroupIdMap[id]].data ); +}
+
+
+Nepomuk::Query::ListFacetWidget::ListFacetWidget( QWidget* parent )
+    : FacetWidget( parent ),
+      d(new Private())
+{
+    d->q = this;
+    d->m_layout = new QVBoxLayout( this );
+    connect( &d->m_buttonGroup, SIGNAL(buttonClicked(int)),
+             this, SLOT(_k_buttonClicked(int)) );
+}
+
+
+Nepomuk::Query::ListFacetWidget::~ListFacetWidget()
+{
+    delete d;
+}
+
+
+Nepomuk::Query::Term Nepomuk::Query::ListFacetWidget::term() const
+{
+    QList<Term> terms;
+    Q_FOREACH( const Button& button, d->m_buttons ) {
+        if( button.button->isChecked() )
+            terms << termForButton( button.id, button.data );
+    }
+
+    if( terms.isEmpty() ) {
+        return Term();
+    }
+    else if( terms.count() == 1 ) {
+        return terms.first();
+    }
+    else if( d->m_selectionMode == MatchAll ) {
+        AndTerm andTerm;
+        Q_FOREACH( const Term& term, terms ) {
+            andTerm.addSubTerm( term );
+        }
+        return andTerm;
+    }
+    else {
+        OrTerm andTerm;
+        Q_FOREACH( const Term& term, terms ) {
+            andTerm.addSubTerm( term );
+        }
+        return andTerm;
+    }
+}
+
+
+bool Nepomuk::Query::ListFacetWidget::isSelected( int index ) const
+{
+    return d->m_buttons[index].button->isChecked();
+}
+
+
+bool Nepomuk::Query::ListFacetWidget::isExclusive() const
+{
+    return d->m_buttonGroup.exclusive();
+}
+
+
+int Nepomuk::Query::ListFacetWidget::count() const
+{
+    return d->m_buttons.count();
+}
+
+
+Nepomuk::Query::Term Nepomuk::Query::ListFacetWidget::termAt( int i ) const
+{
+    return termForButton( d->m_buttons[i].id, d->m_buttons[i].data );
+}
+
+
+QString Nepomuk::Query::ListFacetWidget::titleAt( int i ) const
+{
+    return d->m_buttons.at(i).title;
+}
+
+Nepomuk::Query::ListFacetWidget::SelectionMode \
Nepomuk::Query::ListFacetWidget::selectionMode() const +{
+    return d->m_selectionMode;
+}
+
+
+void Nepomuk::Query::ListFacetWidget::clear()
+{
+    d->m_buttonIdMap.clear();
+    d->m_buttonGroupIdMap.clear();
+    Q_FOREACH( const Button& button, d->m_buttons ) {
+        delete button.button;
+    }
+    d->m_buttons.clear();
+    setTermChanged();
+}
+
+
+void Nepomuk::Query::ListFacetWidget::setSelected( int index, bool selected )
+{
+    if( d->m_buttons[index].button->isChecked() != selected ) {
+        d->m_buttons[index].button->setChecked( selected );
+        setTermChanged();
+    }
+}
+
+
+QSet<int> Nepomuk::Query::ListFacetWidget::selectedButtons() const
+{
+    QSet<int> buttons;
+    Q_FOREACH( const Button& button, d->m_buttons ) {
+        if( button.button->isChecked() )
+            buttons << button.id;
+    }
+    return buttons;
+}
+
+
+QAbstractButton* Nepomuk::Query::ListFacetWidget::button( int id ) const
+{
+    return d->m_buttons[d->m_buttonIdMap[id]].button;
+}
+
+
+QVariant Nepomuk::Query::ListFacetWidget::buttonData( int id ) const
+{
+    return d->m_buttons[d->m_buttonIdMap[id]].data;
+}
+
+
+int Nepomuk::Query::ListFacetWidget::addButton( const QString& title, const \
QVariant& data ) +{
+    Button button;
+    button.title = title;
+    button.id = ++d->m_buttonIdCnt;
+    button.data = data;
+    button.button = d->createButton( title );
+    d->m_buttonIdMap[button.id] = d->m_buttons.count();
+    d->m_buttonGroupIdMap[d->m_buttonGroup.id(button.button)] = \
d->m_buttons.count(); +    d->m_buttons << button;
+    if( isExclusive() && selectedButtons().isEmpty() )
+        button.button->setChecked(true);
+    return button.id;
+}
+
+
+void Nepomuk::Query::ListFacetWidget::setButtonTitle( int id, const QString& title )
+{
+    if( d->m_buttonIdMap.contains( id ) ) {
+        d->m_buttons[d->m_buttonIdMap[id]].title = title;
+        d->m_buttons[d->m_buttonIdMap[id]].button->setText( title );
+    }
+    else {
+        kError() << "Unknown button id:" << id;
+    }
+}
+
+
+void Nepomuk::Query::ListFacetWidget::setButtonData( int id, const QVariant& data )
+{
+    if( d->m_buttonIdMap.contains( id ) ) {
+        d->m_buttons[d->m_buttonIdMap[id]].data = data;
+    }
+    else {
+        kError() << "Unknown button id:" << id;
+    }
+}
+
+
+void Nepomuk::Query::ListFacetWidget::setSelectionMode( SelectionMode mode )
+{
+    if( mode != d->m_selectionMode ) {
+        d->m_selectionMode = mode;
+        d->m_buttonGroup.setExclusive( mode == Exclusive );
+        d->rebuildButtons();
+        setTermChanged();
+    }
+}
+
+
+bool Nepomuk::Query::ListFacetWidget::doSelectFromTerm( const Term& term )
+{
+    // 1. check if term is in our list of terms
+    const int i = d->indexOf( term );
+    if( i >= 0 ) {
+        kDebug() << "Found term at" << i << term;
+        setSelected( i, true );
+        return true;
+    }
+
+    // 2. an OrTerm may be a set of terms in a MatchOne facet
+    // 3. an AndTerm may be a set of terms in a MatchAll facet
+    if( ( term.isOrTerm() &&
+          selectionMode() == MatchOne ) ||
+        ( term.isAndTerm() &&
+          selectionMode() == MatchAll ) ) {
+
+        QSet<int> selectedTerms;
+
+        // since single terms could consist of OrTerms or AndTerms as well
+        // and thus, could be "merged" into the surrounding term, we check
+        // every sensible combination of terms instead of only single ones
+
+        QList<Term> subTerms;
+        if( term.isAndTerm() )
+            subTerms = term.toAndTerm().subTerms();
+        else
+            subTerms = term.toOrTerm().subTerms();
+
+        while( !subTerms.isEmpty() ) {
+            bool found = false;
+            for( int len = 1; len <= subTerms.count(); ++len ) {
+                const QList<Term> excerpt = subTerms.mid( 0, len );
+                Term subTerm;
+                if( term.isAndTerm() )
+                    subTerm = AndTerm(excerpt).optimized();
+                else
+                    subTerm = OrTerm(excerpt).optimized();
+                const int i = d->indexOf( subTerm );
+                if( i >= 0 ) {
+                    kDebug() << "Found term at" << i << subTerm;
+                    selectedTerms << i;
+                    subTerms = subTerms.mid(len);
+                    found = true;
+                    break;
+                }
+            }
+            if( !found ) {
+                kDebug() << "Term not found (not even as subterm):" << subTerms;
+                return false;
+            }
+        }
+
+        Q_FOREACH( int i, selectedTerms )
+            setSelected( i );
+
+        return true;
+    }
+
+    else {
+        kDebug() << "Term not found" << term;
+        return false;
+    }
+}
+
+
+void Nepomuk::Query::ListFacetWidget::doClearSelection()
+{
+    if( isExclusive() ) {
+        setSelected( 0, true );
+    }
+    else {
+        Q_FOREACH( const Button& button, d->m_buttons ) {
+            button.button->setChecked( false );
+        }
+        setTermChanged();
+    }
+}
+
+
+void Nepomuk::Query::ListFacetWidget::buttonClicked( int button, const QVariant& \
data ) +{
+    kDebug() << button;
+    Q_UNUSED( button );
+    Q_UNUSED( data );
+    setTermChanged();
+}
+
+#include "listfacetwidget.moc"
diff --git a/nepomuk/query/listfacetwidget.h b/nepomuk/query/listfacetwidget.h
new file mode 100644
index 0000000..d6095f7
--- /dev/null
+++ b/nepomuk/query/listfacetwidget.h
@@ -0,0 +1,100 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NEPOMUK_QUERY_LIST_FACET_WIDGET_H_
+#define _NEPOMUK_QUERY_LIST_FACET_WIDGET_H_
+
+#include "facetwidget.h"
+#include "nepomukquery_export.h"
+
+#include <QtCore/QSet>
+
+class QAbstractButton;
+
+namespace Nepomuk {
+    namespace Query {
+        class NEPOMUKQUERY_EXPORT ListFacetWidget : public FacetWidget
+        {
+            Q_OBJECT
+
+        public:
+            ListFacetWidget( QWidget* parent = 0 );
+            virtual ~ListFacetWidget();
+
+            Term term() const;
+
+            bool isSelected( int index ) const;
+
+            bool isExclusive() const;
+
+            int count() const;
+
+            Term termAt( int i ) const;
+
+            QString titleAt( int i ) const;
+
+            enum SelectionMode {
+                Exclusive,
+                MatchOne,
+                MatchAll
+            };
+
+            SelectionMode selectionMode() const;
+
+        public Q_SLOTS:
+            void clear();
+            void setSelected( int index, bool selected = true );
+            void setSelectionMode( SelectionMode mode );
+
+        protected:
+            /**
+             * \return A set of buttons ids.
+             */
+            QSet<int> selectedButtons() const;
+
+            QAbstractButton* button( int id ) const;
+            QVariant buttonData( int id ) const;
+
+            /**
+             * \return An id to identify the button.
+             */
+            int addButton( const QString& title, const QVariant& data = QVariant() \
); +            void setButtonTitle( int id, const QString& title );
+            void setButtonData( int id, const QVariant& data );
+            bool doSelectFromTerm( const Term& term );
+            virtual void doClearSelection();
+
+            /**
+             * Default implementation calls setTermChanged()
+             */
+            virtual void buttonClicked( int button, const QVariant& data );
+            virtual Term termForButton( int button, const QVariant& data ) const = \
0; +
+        private:
+            class Private;
+            Private* const d;
+
+            Q_PRIVATE_SLOT( d, void _k_buttonClicked(int) )
+        };
+    }
+}
+
+#endif
diff --git a/nepomuk/query/rangedfacetwidget.cpp \
b/nepomuk/query/rangedfacetwidget.cpp new file mode 100644
index 0000000..bee1595
--- /dev/null
+++ b/nepomuk/query/rangedfacetwidget.cpp
@@ -0,0 +1,178 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "rangedfacetwidget.h"
+#include "property.h"
+#include "variant.h"
+#include "term.h"
+#include "comparisonterm.h"
+
+#include <QtGui/QAbstractButton>
+
+#include "kdebug.h"
+
+Q_DECLARE_METATYPE(Nepomuk::Query::RangedFacetWidget::Range)
+
+class Nepomuk::Query::RangedFacetWidget::Private
+{
+public:
+    Private()
+        : m_lastCheckedButton(-1),
+          m_cutomRangeButtonId(-1) {
+    }
+
+    Types::Property m_property;
+    int m_lastCheckedButton;
+    int m_cutomRangeButtonId;
+};
+
+
+Nepomuk::Query::RangedFacetWidget::RangedFacetWidget( QWidget* parent )
+    : ListFacetWidget( parent ),
+      d(new Private())
+{
+    setSelectionMode( Exclusive );
+}
+
+
+Nepomuk::Query::RangedFacetWidget::~RangedFacetWidget()
+{
+    delete d;
+}
+
+
+Nepomuk::Types::Property Nepomuk::Query::RangedFacetWidget::property() const
+{
+    return d->m_property;
+}
+
+
+Nepomuk::Query::RangedFacetWidget::Range \
Nepomuk::Query::RangedFacetWidget::currentRange() const +{
+    return buttonData( d->m_lastCheckedButton ).value<Range>();
+}
+
+
+void Nepomuk::Query::RangedFacetWidget::setProperty( const Nepomuk::Types::Property& \
p ) +{
+    d->m_property = p;
+    setTermChanged();
+}
+
+
+void Nepomuk::Query::RangedFacetWidget::addFixedValue( const QVariant& value, const \
QString& customTitle ) +{
+    addFixedRange( value, value, customTitle );
+}
+
+
+void Nepomuk::Query::RangedFacetWidget::addFixedRange( const QVariant& start, const \
QVariant& end, const QString& customTitle ) +{
+    QString title( customTitle );
+    if( title.isEmpty() ) {
+        if( start == end )
+            title = start.toString();
+        else
+            title = start.toString() + '-' + end.toString();
+    }
+    int id = addButton( title, QVariant::fromValue( qMakePair( start, end ) ) );
+    if( d->m_lastCheckedButton < 0 )
+        d->m_lastCheckedButton = id;
+}
+
+
+void Nepomuk::Query::RangedFacetWidget::addCustomRangeButton( const QString& title )
+{
+    d->m_cutomRangeButtonId = addButton( title );
+    kDebug() << d->m_cutomRangeButtonId;
+    if( d->m_lastCheckedButton < 0 )
+        d->m_lastCheckedButton = d->m_cutomRangeButtonId;
+}
+
+
+Nepomuk::Query::Term Nepomuk::Query::RangedFacetWidget::buildRangeTerm( const \
QVariant& start, const QVariant& end ) const +{
+    if( start == end )
+        return d->m_property == Term::fromVariant( Variant( start ) );
+    else
+        return ( d->m_property >= Term::fromVariant( Variant( start ) ) && \
d->m_property <= Term::fromVariant( Variant( end ) ) ); +}
+
+
+Nepomuk::Query::RangedFacetWidget::Range \
Nepomuk::Query::RangedFacetWidget::getCustomRange() const +{
+    kDebug();
+    // FIXME
+    return qMakePair(QVariant(), QVariant());
+}
+
+
+void Nepomuk::Query::RangedFacetWidget::buttonClicked( int buttonId, const QVariant& \
data ) +{
+    kDebug() << buttonId;
+    if( buttonId == d->m_cutomRangeButtonId ) {
+        Range range = getCustomRange();
+        if( range.first.isValid() ) {
+            setButtonData( d->m_cutomRangeButtonId, QVariant::fromValue(range) );
+            d->m_lastCheckedButton = d->m_cutomRangeButtonId;
+
+            // check the appropriate button in case the user manually specified one \
of the fixed ranges +            Term term = buildRangeTerm( range.first, \
range.second ); +            for( int i = 0; i < count(); ++i ) {
+                if( termAt(i) == term ) {
+                    setSelected( i );
+                    break;
+                }
+            }
+        }
+        else {
+            kDebug() << "Invalid range. Restoring old:" << d->m_lastCheckedButton;
+            // restore previous selection
+            button( d->m_lastCheckedButton )->setChecked(true);
+        }
+        setTermChanged();
+    }
+    else {
+        d->m_lastCheckedButton = buttonId;
+        ListFacetWidget::buttonClicked( buttonId, data );
+    }
+}
+
+
+Nepomuk::Query::Term Nepomuk::Query::RangedFacetWidget::termForButton( int, const \
QVariant& data ) const +{
+    if( data.userType() == qMetaTypeId<Range>() ) {
+        Range range = data.value<Range>();
+        return buildRangeTerm( range.first, range.second );
+    }
+    else {
+        return Term();
+    }
+}
+
+
+void Nepomuk::Query::RangedFacetWidget::doClearSelection()
+{
+    ListFacetWidget::doClearSelection();
+    d->m_lastCheckedButton = *selectedButtons().begin();
+}
+
+#include "rangedfacetwidget.moc"
diff --git a/nepomuk/query/rangedfacetwidget.h b/nepomuk/query/rangedfacetwidget.h
new file mode 100644
index 0000000..ad21d3a
--- /dev/null
+++ b/nepomuk/query/rangedfacetwidget.h
@@ -0,0 +1,76 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NEPOMUK_QUERY_RANGED_FACET_WIDGET_H_
+#define _NEPOMUK_QUERY_RANGED_FACET_WIDGET_H_
+
+#include "listfacetwidget.h"
+#include "nepomukquery_export.h"
+
+#include <QtCore/QPair>
+#include <QtCore/QVariant>
+
+
+namespace Nepomuk {
+    namespace Types {
+        class Property;
+    }
+
+    namespace Query {
+        class NEPOMUKQUERY_EXPORT RangedFacetWidget : public ListFacetWidget
+        {
+            Q_OBJECT
+
+        public:
+            RangedFacetWidget( QWidget* parent = 0 );
+            virtual ~RangedFacetWidget();
+
+            Types::Property property() const;
+
+            typedef QPair<QVariant, QVariant> Range;
+
+            Range currentRange() const;
+
+        public Q_SLOTS:
+            /**
+             * Only used when buildRangeTerm() is not reimplemented.
+             */
+            void setProperty( const Nepomuk::Types::Property& p );
+            void addFixedValue( const QVariant& value, const QString& customTitle = \
QString() ); +            void addFixedRange( const QVariant& start, const QVariant& \
end, const QString& customTitle = QString() ); +            void \
addCustomRangeButton( const QString& title = QString() ); +
+        protected:
+            virtual Term buildRangeTerm( const QVariant& start, const QVariant& end \
) const; +            virtual Range getCustomRange() const;
+
+        private:
+            void buttonClicked( int button, const QVariant& data );
+            Term termForButton( int button, const QVariant& data ) const;
+            void doClearSelection();
+
+            class Private;
+            Private* const d;
+        };
+    }
+}
+
+#endif
diff --git a/nepomuk/query/simplefacet.cpp b/nepomuk/query/simplefacet.cpp
new file mode 100644
index 0000000..6652076
--- /dev/null
+++ b/nepomuk/query/simplefacet.cpp
@@ -0,0 +1,177 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "simplefacet.h"
+#include "andterm.h"
+
+#include <QtCore/QSet>
+
+
+class Nepomuk::Query::SimpleFacet::Private
+{
+public:
+    Private()
+        : m_isExclusive(true) {
+    }
+
+    bool m_isExclusive;
+    QString m_title;
+
+    QList<Nepomuk::Query::Term> m_terms;
+    QList<QString> m_titles;
+
+    QSet<int> m_selectedFacets;
+};
+
+
+Nepomuk::Query::SimpleFacet::SimpleFacet( QObject* parent )
+    : Facet(parent),
+      d(new Private())
+{
+}
+
+
+Nepomuk::Query::SimpleFacet::~SimpleFacet()
+{
+    delete d;
+}
+
+
+QString Nepomuk::Query::SimpleFacet::title() const
+{
+    return d->m_title;
+}
+
+
+Nepomuk::Query::Term Nepomuk::Query::SimpleFacet::term() const
+{
+    if( d->m_terms.isEmpty() ||
+        d->m_selectedFacets.isEmpty() ) {
+        return Term();
+    }
+    else if( isExclusive() ) {
+        return termAt( *d->m_selectedFacets.constBegin() );
+    }
+    else {
+        AndTerm andTerm;
+        Q_FOREACH( int i, m_selectedFacets ) {
+            andTerm.addSubTerm( termAt(i) );
+        }
+        return andTerm;
+    }
+}
+
+
+void Nepomuk::Query::SimpleFacet::setTitle( const QString& title )
+{
+    d->m_title = title;
+}
+
+
+bool Nepomuk::Query::SimpleFacet::exclusive() const
+{
+    return d->m_isExclusive;
+}
+
+
+void Nepomuk::Query::SimpleFacet::setExclusive( bool exclusive )
+{
+    d->m_isExclusive = exclusive;
+    clearSelection();
+}
+
+
+int Nepomuk::Query::SimpleFacet::count() const
+{
+    return d->m_terms.count();
+}
+
+
+QList<Nepomuk::Query::Term> Nepomuk::Query::SimpleFacet::terms() const
+{
+    return d->m_terms;
+}
+
+
+Nepomuk::Query::Term Nepomuk::Query::SimpleFacet::termAt( int index ) const
+{
+    return d->m_terms[index];
+}
+
+
+QString Nepomuk::Query::SimpleFacet::titleAt( int index ) const
+{
+    return d->m_titles[index];
+}
+
+
+QString Nepomuk::Query::SimpleFacet::termTitle( const Term& term ) const
+{
+    return d->m_titles[d->m_terms.indexOf(term)];
+}
+
+
+void Nepomuk::Query::SimpleFacet::setTerms( const QMap<QString, \
Nepomuk::Query::Term>& terms ) +{
+    d->m_titles = terms.keys();
+    d->m_terms = terms.values();
+    clearSelection();
+}
+
+
+void Nepomuk::Query::SimpleFacet::addTerm( const QString& title, const \
Nepomuk::Query::Term& term ) +{
+    d->m_titles.append( title );
+    d->m_terms.append( term );
+    clearSelection();
+}
+
+
+void Nepomuk::Query::SimpleFacet::selectTerm( int index, bool selected = true )
+{
+    if( d->m_isExclusive ) {
+        if( d->m_selectedFacets.contains(index) && !selected ) {
+            clearSelection();
+        }
+        else if( selected ) {
+            d->m_selectedFacets.clear();
+            d->m_selectedFacets.append(index);
+        }
+    }
+    else if( selected ) {
+        d->m_selectedFacets.append(index);
+    }
+    else {
+        d->m_selectedFacets.removeAll(index);
+    }
+    setTermChanged();
+}
+
+
+void Nepomuk::Query::SimpleFacet::clearSelection()
+{
+    d->m_selectedFacets.clear();
+    if( d->m_isExclusive )
+        d->m_selectedFacets.append(0);
+    setTermChanged();
+}
+
+#include "simplefacet.moc"
diff --git a/nepomuk/query/simplefacet.h b/nepomuk/query/simplefacet.h
new file mode 100644
index 0000000..4d0e161
--- /dev/null
+++ b/nepomuk/query/simplefacet.h
@@ -0,0 +1,77 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NEPOMUK_QUERY_SIMPLE_FACET_H_
+#define _NEPOMUK_QUERY_SIMPLE_FACET_H_
+
+#include "facet.h"
+
+#include "nepomukquery_export.h"
+
+#include <QtCore/QMap>
+
+
+namespace Nepomuk {
+    namespace Query {
+        /**
+         * A simple facet using a list of terms.
+         *
+         * \author Sebastian Trueg <trueg@kde.org>
+         */
+        class NEPOMUKQUERY_EXPORT SimpleFacet : public Facet
+        {
+            Q_OBJECT
+
+        public:
+            SimpleFacet( QObject* parent );
+            virtual ~SimpleFacet();
+
+            virtual QString title() const;
+            virtual Term term() const;
+
+            void setTitle( const QString& title );
+
+            bool exclusive() const;
+            void setExclusive( bool exclusive );
+
+            virtual int count() const;
+
+            QList<Term> terms() const;
+
+            Term termAt( int index ) const;
+            QString titleAt( int index ) const;
+            QString termTitle( const Term& term ) const;
+
+        public Q_SLOTS:
+            void setTerms( const QMap<QString, Nepomuk::Query::Term>& terms );
+            void addTerm( const QString& title, const Nepomuk::Query::Term& term );
+
+            virtual void selectTerm( int index, bool selected = true );
+            virtual void clearSelection();
+
+        private:
+            class Private;
+            Private* d;
+        };
+    }
+}
+
+#endif
diff --git a/nepomuk/query/simplelistfacetwidget.cpp \
b/nepomuk/query/simplelistfacetwidget.cpp new file mode 100644
index 0000000..d8c84de
--- /dev/null
+++ b/nepomuk/query/simplelistfacetwidget.cpp
@@ -0,0 +1,57 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "simplelistfacetwidget.h"
+
+Q_DECLARE_METATYPE(Nepomuk::Query::Term)
+
+class Nepomuk::Query::SimpleListFacetWidget::Private
+{
+public:
+};
+
+
+Nepomuk::Query::SimpleListFacetWidget::SimpleListFacetWidget( QWidget* parent )
+    : ListFacetWidget( parent ),
+      d(new Private())
+{
+}
+
+
+Nepomuk::Query::SimpleListFacetWidget::~SimpleListFacetWidget()
+{
+    delete d;
+}
+
+
+void Nepomuk::Query::SimpleListFacetWidget::addTerm( const QString& title, const \
Nepomuk::Query::Term& term ) +{
+    addButton( title, QVariant::fromValue(term) );
+}
+
+
+Nepomuk::Query::Term Nepomuk::Query::SimpleListFacetWidget::termForButton( int \
button, const QVariant& data ) const +{
+    Q_UNUSED(button);
+    return data.value<Term>();
+}
+
+#include "simplelistfacetwidget.moc"
diff --git a/nepomuk/query/simplelistfacetwidget.h \
b/nepomuk/query/simplelistfacetwidget.h new file mode 100644
index 0000000..40cacbd
--- /dev/null
+++ b/nepomuk/query/simplelistfacetwidget.h
@@ -0,0 +1,51 @@
+/*
+   This file is part of the Nepomuk KDE project.
+   Copyright (C) 2010 Sebastian Trueg <trueg@kde.org>
+
+   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.1 of the License, or (at your option) version 3, or any
+   later version accepted by the membership of KDE e.V. (or its
+   successor approved by the membership of KDE e.V.), which shall
+   act as a proxy defined in Section 6 of version 3 of the license.
+
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _NEPOMUK_QUERY_SIMPLE_LIST_FACET_WIDGET_H_
+#define _NEPOMUK_QUERY_SIMPLE_LIST_FACET_WIDGET_H_
+
+#include "listfacetwidget.h"
+#include "nepomukquery_export.h"
+
+namespace Nepomuk {
+    namespace Query {
+        class NEPOMUKQUERY_EXPORT SimpleListFacetWidget : public ListFacetWidget
+        {
+            Q_OBJECT
+
+        public:
+            SimpleListFacetWidget( QWidget* parent = 0 );
+            ~SimpleListFacetWidget();
+
+        public Q_SLOTS:
+            void addTerm( const QString& title, const Nepomuk::Query::Term& term );
+
+        protected:
+            Term termForButton( int button, const QVariant& data ) const;
+
+        private:
+            class Private;
+            Private* const d;
+        };
+    }
+}
+
+#endif



_______________________________________________
Nepomuk mailing list
Nepomuk@kde.org
https://mail.kde.org/mailman/listinfo/nepomuk


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic