From 9fa96846fb4bb089a8174c31f6bd44b99c4caf5d Mon Sep 17 00:00:00 2001 From: "craig.p.drummond" Date: Wed, 9 Oct 2013 18:45:01 +0000 Subject: [PATCH] Dont hide other online services / streams when searching. --- ChangeLog | 7 +++-- models/musiclibraryproxymodel.cpp | 10 +++---- models/musiclibraryproxymodel.h | 5 ---- models/proxymodel.cpp | 31 +++++++++++++++++++++ models/proxymodel.h | 7 +++-- models/streamsmodel.cpp | 6 +++++ models/streamsmodel.h | 2 ++ models/streamsproxymodel.cpp | 10 +++++++ online/onlineservicespage.cpp | 7 +++-- online/podcastservice.h | 2 +- streams/streamspage.cpp | 45 ++++++++++++++++++++++++------- widgets/itemview.h | 2 +- widgets/searchwidget.cpp | 10 +++++-- 13 files changed, 111 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2105216e1..6a39eadda 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,8 +23,7 @@ used. 10. Add ability to 'filter search' stream categories. 11. Add option to prevent system from suspending whilst playing (Linux only). -12. If playqueue is cleared when dynamizer is running, then also stop - dynamizer. +12. If playqueue is cleared when dynamizer is running, then also stop dynamizer. 13. Create a new SizeGrip class, so that we can force the size-grip on the main window to have the same height as toolbuttons - this makes it align to the bottom. @@ -67,6 +66,10 @@ 34. Prompt before clearing playqueue. 35. Only show config pages, and tabs, that are relevant to the enabled views. 36. Show action short-cuts in tooltips. +37. When filtering (i.e. searching) Jamendo, Maganatue, and stream providers + (apart from TuneIn and ShoutCast), then dont hide items from other + services - but only filter the ones on the filtering service. +38. Dont hide other online services / streams when searching. 1.1.4 ----- diff --git a/models/musiclibraryproxymodel.cpp b/models/musiclibraryproxymodel.cpp index 76210e966..ee3bf1127 100644 --- a/models/musiclibraryproxymodel.cpp +++ b/models/musiclibraryproxymodel.cpp @@ -33,7 +33,6 @@ MusicLibraryProxyModel::MusicLibraryProxyModel(QObject *parent) : ProxyModel(parent) - , filter(0) { setDynamicSortFilter(true); setFilterCaseSensitivity(Qt::CaseInsensitive); @@ -100,17 +99,14 @@ bool MusicLibraryProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex & } if (filter) { - if (!sourceParent.isValid()) { - // All top level items are valid + if (item==filter) { // Accept top-level item! return true; } - const MusicLibraryItem *p=item->parentItem(); - while (p->parentItem()) { + while (p && p->parentItem()) { p=p->parentItem(); } - if (p!=filter) { - // If item is not part of 'filter' tree - then we accept it + if (p!=filter) { // Accept all items that are not children of top-level item! return true; } } diff --git a/models/musiclibraryproxymodel.h b/models/musiclibraryproxymodel.h index e79357cb2..b7aecbd97 100644 --- a/models/musiclibraryproxymodel.h +++ b/models/musiclibraryproxymodel.h @@ -39,17 +39,12 @@ public: MusicLibraryProxyModel(QObject *parent = 0); bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; bool lessThan(const QModelIndex &left, const QModelIndex &right) const; - void setFilterItem(const MusicLibraryItem *f) { filter=f; } - const MusicLibraryItem *filterItem() const { return filter; } private: bool filterAcceptsRoot(const MusicLibraryItem *item) const; bool filterAcceptsArtist(const MusicLibraryItem *item) const; bool filterAcceptsAlbum(const MusicLibraryItem *item) const; bool filterAcceptsSong(const MusicLibraryItem *item) const; - -private: - const MusicLibraryItem *filter; }; #endif diff --git a/models/proxymodel.cpp b/models/proxymodel.cpp index 7376b221d..f47a5368a 100644 --- a/models/proxymodel.cpp +++ b/models/proxymodel.cpp @@ -96,6 +96,37 @@ bool ProxyModel::update(const QString &text, const QString &genre) return false; } +bool ProxyModel::updateWithFilter(const QString &text, const QString &genre, const void *f) +{ + bool wasEmpty=isEmpty(); + filterStrings = text.split(' ', QString::SkipEmptyParts, Qt::CaseInsensitive); + unmatchedStrings = 0; + const int n = qMin(filterStrings.count(), (int)sizeof(uint)); + for ( int i = 0; i < n; ++i ) { + unmatchedStrings |= (1<children.indexOf(const_cast(cat)); + return -1==row ? QModelIndex() : createIndex(row, 0, (void *)cat); +} diff --git a/models/streamsmodel.h b/models/streamsmodel.h index e04c32953..a3c29c07a 100644 --- a/models/streamsmodel.h +++ b/models/streamsmodel.h @@ -234,6 +234,8 @@ public: CategoryItem * addXmlCategory(const QString &name, const QIcon &icon, const QString &xmlFileName, bool replace); void removeXmlCategory(const QString &key); + QModelIndex categoryIndex(const CategoryItem *cat) const; + Q_SIGNALS: void loading(); void loaded(); diff --git a/models/streamsproxymodel.cpp b/models/streamsproxymodel.cpp index 23f8db05e..464b84964 100644 --- a/models/streamsproxymodel.cpp +++ b/models/streamsproxymodel.cpp @@ -67,6 +67,13 @@ bool StreamsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourc QModelIndex idx=index.parent(); QStringList strings; + if (filter && item==filter) { // Accept top-level item! + return true; + } + if (filter && !idx.isValid() && item!=filter) { // Accept all items that are not children of top-level item! + return true; + } + // Traverse back up tree, so we get parent strings... while (idx.isValid()) { StreamsModel::Item *i = static_cast(idx.internalPointer()); @@ -75,6 +82,9 @@ bool StreamsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourc } strings << i->name; idx=idx.parent(); + if (filter && !idx.isValid() && i!=filter) { // Accept all items that are not children of top-level item! + return true; + } } if (item->isCategory()) { diff --git a/online/onlineservicespage.cpp b/online/onlineservicespage.cpp index 630378c41..1183daf01 100644 --- a/online/onlineservicespage.cpp +++ b/online/onlineservicespage.cpp @@ -332,7 +332,7 @@ void OnlineServicesPage::controlSearch(bool on) view->setBackgroundImage(srv->icon()); } QModelIndex filterIndex=srv ? OnlineServicesModel::self()->serviceIndex(srv) : QModelIndex(); - proxy.setFilterItem(srv); + proxy.updateWithFilter(QString(), QString(), srv); if (filterIndex.isValid()) { view->showIndex(proxy.mapFromSource(filterIndex), true); } @@ -343,8 +343,7 @@ void OnlineServicesPage::controlSearch(bool on) } genreCombo->setEnabled(true); searchService=QString(); - proxy.setFilterItem(0); - proxy.update(QString(), QString()); + proxy.updateWithFilter(QString(), QString(), 0); view->setBackgroundImage(QIcon()); } } @@ -358,7 +357,7 @@ void OnlineServicesPage::searchItems() OnlineServicesModel::self()->setSearch(searchService, text); } } else { - proxy.update(text, genreCombo->currentIndex()<=0 ? QString() : genreCombo->currentText()); + proxy.updateWithFilter(text, genreCombo->currentIndex()<=0 ? QString() : genreCombo->currentText(), proxy.filterItem()); if (proxy.enabled() && !text.isEmpty()) { view->expandAll(proxy.filterItem() ? proxy.mapFromSource(OnlineServicesModel::self()->serviceIndex(static_cast(proxy.filterItem()))) diff --git a/online/podcastservice.h b/online/podcastservice.h index cccda88c3..bfc3fc468 100644 --- a/online/podcastservice.h +++ b/online/podcastservice.h @@ -75,7 +75,6 @@ public: void cancelAllJobs() { cancelAll(); cancelAllDownloads(); } private: - void loadAll(); void cancelAll(); MusicLibraryItemPodcast * getPodcast(const QUrl &url) const; MusicLibraryItemPodcastEpisode * getEpisode(const MusicLibraryItemPodcast *podcast, const QUrl &episode); @@ -87,6 +86,7 @@ private: void cancelDownload(NetworkJob *job); private Q_SLOTS: + void loadAll(); void rssJobFinished(); void updateRss(); void currentMpdSong(const Song &s); diff --git a/streams/streamspage.cpp b/streams/streamspage.cpp index 3c62b5fa2..921d7a6c3 100644 --- a/streams/streamspage.cpp +++ b/streams/streamspage.cpp @@ -41,7 +41,6 @@ #include #include #endif -#include #include #include #if QT_VERSION >= 0x050000 @@ -65,6 +64,7 @@ StreamsPage::StreamsPage(QWidget *p) // connect(view, SIGNAL(itemsSelected(bool)), addToPlaylist, SLOT(setEnabled(bool))); connect(view, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(itemDoubleClicked(const QModelIndex &))); connect(view, SIGNAL(searchIsActive(bool)), this, SLOT(controlSearch(bool))); + connect(view, SIGNAL(searchItems()), this, SLOT(searchItems())); connect(view, SIGNAL(itemsSelected(bool)), SLOT(controlActions())); connect(searchView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(itemDoubleClicked(const QModelIndex &))); connect(searchView, SIGNAL(searchItems()), this, SLOT(searchItems())); @@ -495,7 +495,17 @@ void StreamsPage::searchItems() if (!searching) { return; } - searchModel.search(searchView->searchText().trimmed(), false); + if (proxy==&searchProxy) { + searchModel.search(searchView->searchText().trimmed(), false); + } else { + QString text=view->searchText().trimmed(); + proxy->updateWithFilter(text, QString(), proxy->filterItem()); + if (proxy->enabled() && !text.isEmpty()) { + view->expandAll(proxy->filterItem() + ? proxy->mapFromSource(StreamsModel::self()->categoryIndex(static_cast(proxy->filterItem()))) + : QModelIndex()); + } + } } StreamsModel::CategoryItem * StreamsPage::getSearchCategory() @@ -530,20 +540,37 @@ void StreamsPage::controlSearch(bool on) ? StreamSearchModel::ShoutCast : StreamSearchModel::Filter; - proxy=&searchProxy; - view->clearSelection(); - searchModel.setCat(searchCat); - searchView->setSearchLabelText(i18n("Search %1:", cat->name)); - searchView->setBackgroundImage(cat->icon); if (StreamSearchModel::Filter==searchCat) { - searchModel.setFilterRoot(cat); + proxy=&streamsProxy; + searchModel.clear(); + viewStack->setCurrentIndex(0); + view->setSearchLabelText(i18n("Search %1:", cat->name)); + view->setBackgroundImage(cat->icon); + proxy->updateWithFilter(QString(), QString(), cat); + QModelIndex filterIndex=cat ? StreamsModel::self()->categoryIndex(cat) : QModelIndex(); + if (filterIndex.isValid()) { + view->showIndex(proxy->mapFromSource(filterIndex), true); + } + // We need to call focusSearch via 'invokeMethod' as we need this to occur at the nex event-loop iteration. + // This is due to the fact that we have 2 views - search (for TuneIn/ShoutCasy) and standard. Our focusSearch() + // calls focusSearch on both - which triggers this controlSearch(). + QMetaObject::invokeMethod(view, "focusSearch", Qt::QueuedConnection); + } else { + proxy=&searchProxy; + searchModel.setCat(searchCat); + viewStack->setCurrentIndex(1); + searchView->setSearchLabelText(i18n("Search %1:", cat->name)); + searchView->setBackgroundImage(cat->icon); } + view->clearSelection(); } else { + proxy->updateWithFilter(QString(), QString(), 0); proxy=&streamsProxy; searchModel.clear(); view->setSearchVisible(false); + viewStack->setCurrentIndex(0); + view->setBackgroundImage(QIcon()); } - viewStack->setCurrentIndex(on ? 1 : 0); controlActions(); } } diff --git a/widgets/itemview.h b/widgets/itemview.h index f21cd5835..e8bcbaec9 100644 --- a/widgets/itemview.h +++ b/widgets/itemview.h @@ -119,7 +119,6 @@ public: void setDeleteAction(QAction *act); void setRootIsDecorated(bool v) { treeView->setRootIsDecorated(v); } void showIndex(const QModelIndex &idx, bool scrollTo); - void focusSearch(); void setSearchLabelText(const QString &text); void setSearchVisible(bool v); bool isSearchActive() const; @@ -133,6 +132,7 @@ public: void setAnimated(bool a); public Q_SLOTS: + void focusSearch(); void showSpinner(bool v=true); void hideSpinner(); void collectionRemoved(quint32 key); diff --git a/widgets/searchwidget.cpp b/widgets/searchwidget.cpp index 725b6ce1e..311d18471 100644 --- a/widgets/searchwidget.cpp +++ b/widgets/searchwidget.cpp @@ -99,16 +99,22 @@ void SearchWidget::toggle() void SearchWidget::activate() { + bool wasActive=widgetIsActive; widgetIsActive=true; show(); setFocus(); - emit active(widgetIsActive); + if (wasActive!=widgetIsActive) { + emit active(widgetIsActive); + } } void SearchWidget::close() { + bool wasActive=widgetIsActive; widgetIsActive=false; setVisible(false); edit->setText(QString()); - emit active(widgetIsActive); + if (wasActive!=widgetIsActive) { + emit active(widgetIsActive); + } }