add a proxy model for filtering/searching

parent 4c37d9a9
......@@ -58,6 +58,7 @@ set(juk_SRCS ${tunepimp_SRCS}
playlist/playlistsearch.cpp
playlist/playlistview.cpp
playlist/playlistheaderview.cpp
playlist/playlistsortfilterproxymodel.cpp
playlistbox.cpp
playlistsplitter.cpp
......
......@@ -72,33 +72,7 @@ void PlaylistSearch::search()
bool PlaylistSearch::checkItem(PlaylistItem *item)
{
m_items.append(item);
// set our default
bool match = bool(m_mode);
ComponentList::Iterator componentIt = m_components.begin();
for(; componentIt != m_components.end(); ++componentIt) {
bool componentMatches = (*componentIt).matches(item);
if(componentMatches && m_mode == MatchAny) {
match = true;
break;
}
if(!componentMatches && m_mode == MatchAll) {
match = false;
break;
}
}
if(match)
m_matchedItems.append(item);
else
m_unmatchedItems.append(item);
return match;
return true;
}
void PlaylistSearch::addComponent(const Component &c)
......@@ -179,75 +153,62 @@ PlaylistSearch::Component::Component(const QRegExp &query, const ColumnList& col
}
bool PlaylistSearch::Component::matches(PlaylistItem *item) const
bool PlaylistSearch::Component::matches(QString item) const
{
if((m_re && m_queryRe.isEmpty()) || (!m_re && m_query.isEmpty()))
return false;
if(m_columns.isEmpty()) {
Playlist *p = static_cast<Playlist *>(item->playlist());
for(int i = 0; i < p->columnCount(); i++) {
// if(p->isColumnVisible(i))
m_columns.append(i);
}
if(m_re) {
if(item.contains(m_queryRe))
return true;
else
return false;
}
// for(ColumnList::Iterator it = m_columns.begin(); it != m_columns.end(); ++it) {
//
// if(m_re) {
// if(item->text(*it).contains(m_queryRe))
// return true;
// else
// break;
// }
//
// switch(m_mode) {
// case Contains:
// if(item->text(*it).contains(m_query, m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive))
// return true;
// break;
// case Exact:
// if(item->text(*it).length() == m_query.length()) {
// if(m_caseSensitive) {
// if(item->text(*it) == m_query)
// return true;
// }
// else if(item->text(*it).toLower() == m_query.toLower())
// return true;
// }
// break;
// case ContainsWord:
// {
// QString s = item->text(*it);
// int i = s.indexOf(m_query, 0, m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
//
// if(i >= 0) {
//
// // If we found the pattern and the lengths are the same, then
// // this is a match.
//
// if(s.length() == m_query.length())
// return true;
//
// // First: If the match starts at the beginning of the text or the
// // character before the match is not a word character
//
// // AND
//
// // Second: Either the pattern was found at the end of the text,
// // or the text following the match is a non-word character
//
// // ...then we have a match
//
// if((i == 0 || !s.at(i - 1).isLetterOrNumber()) &&
// (i + m_query.length() == s.length() || !s.at(i + m_query.length()).isLetterOrNumber()))
// return true;
// break;
// }
// }
// }
// }
switch(m_mode) {
case Contains:
if(item.contains(m_query, m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive))
return true;
else
return false;
case Exact:
if(item.length() == m_query.length()) {
if(m_caseSensitive) {
if(item == m_query)
return true;
}
else if(item.toLower() == m_query.toLower())
return true;
} else
return false;
case ContainsWord:
{
int i = item.indexOf(m_query, 0, m_caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive );
if(i >= 0) {
// If we found the pattern and the lengths are the same, then
// this is a match.
if(item.length() == m_query.length())
return true;
// First: If the match starts at the beginning of the text or the
// character before the match is not a word character
// AND
// Second: Either the pattern was found at the end of the text,
// or the text following the match is a non-word character
// ...then we have a match
if((item == 0 || !item.at(i - 1).isLetterOrNumber()) &&
(i + m_query.length() == item.length() || !item.at(i + m_query.length()).isLetterOrNumber()))
return true;
else
return false;
}
}
}
return false;
}
......@@ -299,7 +260,7 @@ QDataStream &operator<<(QDataStream &s, const PlaylistSearch::Component &c)
<< (c.isPatternSearch() ? c.pattern().pattern() : c.query())
<< c.isCaseSensitive()
<< c.columns()
<< qint32(c.matchMode());
<< qint32(c.mode());
return s;
}
......
......@@ -67,6 +67,8 @@ public:
* requiring invalidating the search.
*/
void clearItem(PlaylistItem *item);
SearchMode mode() const { return m_mode; }
private:
PlaylistList m_playlists;
......@@ -110,13 +112,18 @@ public:
QString query() const { return m_query; }
QRegExp pattern() const { return m_queryRe; }
ColumnList columns() const { return m_columns; }
void setColumns(const ColumnList &columns) { m_columns = columns; }
bool matches(PlaylistItem *item) const;
bool matches(QString item) const;
bool isPatternSearch() const { return m_re; }
bool isCaseSensitive() const { return m_caseSensitive; }
MatchMode matchMode() const { return m_mode; }
MatchMode mode() const { return m_mode; }
const QRegExp &queryRe() const { return m_queryRe; }
bool isEmpty() const { return ((m_re && m_queryRe.isEmpty()) || (!m_re && m_query.isEmpty())); }
bool operator==(const Component &v) const;
bool re() { return m_re; }
private:
QString m_query;
......
#include "playlistsortfilterproxymodel.h"
PlaylistSortFilterProxyModel::PlaylistSortFilterProxyModel(QObject *parent) :
QSortFilterProxyModel(parent)
{
}
void PlaylistSortFilterProxyModel::setSearch(const PlaylistSearch& search)
{
if (!m_searchEnabled)
return;
m_search = search;
}
bool PlaylistSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
{
if (!m_searchEnabled)
return true;
// set our default
bool match = bool(m_search.mode());
Q_FOREACH (const PlaylistSearch::Component &component, m_search.components()) {
bool componentMatches = true;
if (!component.isEmpty()) {
ColumnList columns = component.columns();
if (columns.isEmpty()) {
for(int i=0; i<sourceParent.model()->columnCount(); i++)
columns.append(i);
// component.setColumns(columns);
}
Q_FOREACH(int column, columns) {
const QModelIndex &index = sourceModel()->index(sourceRow, column, sourceParent);
QString text = sourceModel()->data(index).toString();
if (!component.matches(text)) {
componentMatches = false;
break;
}
}
}
if(componentMatches && m_search.mode() == PlaylistSearch::MatchAny) {
match = true;
break;
}
if(!componentMatches && m_search.mode() == PlaylistSearch::MatchAll) {
match = false;
break;
}
}
return match;
}
void PlaylistSortFilterProxyModel::setSearchEnabled(bool enable)
{
m_searchEnabled = enable;
}
#ifndef PLAYLISTSORTFILTERPROXYMODEL_H
#define PLAYLISTSORTFILTERPROXYMODEL_H
#include <QSortFilterProxyModel>
#include "playlist/playlistsearch.h"
class PlaylistSortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
PlaylistSortFilterProxyModel(QObject *parent=0);
void setSearch(const PlaylistSearch&);
void setSearchEnabled(bool);
protected:
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
private:
PlaylistSearch m_search;
bool m_searchEnabled;
};
#endif // PLAYLISTSORTFILTERPROXYMODEL_H
......@@ -15,6 +15,8 @@
#include <KIO/NetAccess>
#include <KMimeType>
#include "playlist/playlistheaderview.h"
#include "playlist/playlistsortfilterproxymodel.h"
#include "tracksequencemanager.h"
using namespace ActionCollection;
......@@ -23,7 +25,8 @@ PlaylistView::PlaylistView(QWidget* parent):
QTreeView(parent),
m_contextMenu(0),
m_editAction(0),
m_currentColumn(0)
m_currentColumn(0),
m_proxyModel(new PlaylistSortFilterProxyModel(this))
{
setHeader(new PlaylistHeaderView(Qt::Horizontal, this));
......@@ -207,6 +210,52 @@ void PlaylistView::decode(const QMimeData *s, const QModelIndex &index)
playlist()->addFiles(fileList, playlist()->items()[index.row()]);
}
void PlaylistView::setModel(QAbstractItemModel* newModel)
{
if (!model())
QTreeView::setModel(m_proxyModel);
m_proxyModel->setSourceModel(newModel);
}
QAbstractItemModel* PlaylistView::model()
{
return m_proxyModel->sourceModel();
}
void PlaylistView::setSearch(const PlaylistSearch &s)
{
m_proxyModel->setSearch(s);
// m_search = s;
//
// if(!m_searchEnabled)
// return;
//
// setItemsVisible(s.matchedItems(), true);
// setItemsVisible(s.unmatchedItems(), false);
//
// TrackSequenceManager::instance()->iterator()->playlistChanged();
}
void PlaylistView::setSearchEnabled(bool enabled)
{
m_proxyModel->setSearchEnabled(enabled);
// if(m_searchEnabled == enabled)
// return;
//
// m_searchEnabled = enabled;
//
// if(enabled) {
// setItemsVisible(m_search.matchedItems(), true);
// setItemsVisible(m_search.unmatchedItems(), false);
// }
// else
// setItemsVisible(items(), true);
}
// ### TODO: View
// PlaylistItemList Playlist::visibleItems()
// {
......@@ -232,34 +281,6 @@ void PlaylistView::decode(const QMimeData *s, const QModelIndex &index)
// playlistItem->setVisible(visible);
// }
// ### TODO: View, move to a proxy model
// void Playlist::setSearch(const PlaylistSearch &s)
// {
// m_search = s;
//
// if(!m_searchEnabled)
// return;
//
// setItemsVisible(s.matchedItems(), true);
// setItemsVisible(s.unmatchedItems(), false);
//
// TrackSequenceManager::instance()->iterator()->playlistChanged();
// }
//
// void Playlist::setSearchEnabled(bool enabled)
// {
// if(m_searchEnabled == enabled)
// return;
//
// m_searchEnabled = enabled;
//
// if(enabled) {
// setItemsVisible(m_search.matchedItems(), true);
// setItemsVisible(m_search.unmatchedItems(), false);
// }
// else
// setItemsVisible(items(), true);
// }
// ### TODO: View
// void Playlist::markItemSelected(PlaylistItem *item, bool selected)
......
......@@ -5,12 +5,17 @@
#include "playlist/playlists/playlist.h"
class PlaylistSortFilterProxyModel;
class PlaylistView : public QTreeView
{
Q_OBJECT
public:
PlaylistView(QWidget *parent);
virtual void setModel(QAbstractItemModel *model);
virtual QAbstractItemModel *model();
void setSearch(const PlaylistSearch &s);
void setSearchEnabled(bool);
public slots:
void copy();
......@@ -30,6 +35,7 @@ private:
KMenu *m_contextMenu;
QAction *m_editAction;
int m_currentColumn;
PlaylistSortFilterProxyModel *m_proxyModel;
// private slots:
// void slotPopulateBackMenu() const;
// void slotPlayFromBackMenu(QAction *) const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment