Make the grouping of global search results configurable

This commit is contained in:
David Sansome 2012-06-17 16:20:40 +01:00
parent 3e410021a5
commit 57865f82c2
9 changed files with 172 additions and 84 deletions

View File

@ -215,3 +215,37 @@ void GlobalSearchModel::GetChildResults(const QStandardItem* item,
QMimeData* GlobalSearchModel::mimeData(const QModelIndexList& indexes) const {
return engine_->LoadTracks(GetChildResults(indexes));
}
namespace {
void GatherResults(const QStandardItem* parent,
QMap<SearchProvider*, SearchProvider::ResultList>* results) {
QVariant result_variant = parent->data(GlobalSearchModel::Role_Result);
if (result_variant.isValid()) {
SearchProvider::Result result = result_variant.value<SearchProvider::Result>();
(*results)[result.provider_].append(result);
}
for (int i=0 ; i<parent->rowCount() ; ++i) {
GatherResults(parent->child(i), results);
}
}
}
void GlobalSearchModel::SetGroupBy(const LibraryModel::Grouping& grouping,
bool regroup_now) {
const LibraryModel::Grouping old_group_by = group_by_;
group_by_ = grouping;
if (regroup_now && group_by_ != old_group_by) {
// Walk the tree gathering the results we have already
QMap<SearchProvider*, SearchProvider::ResultList> results;
GatherResults(invisibleRootItem(), &results);
// Reset the model and re-add all the results using the new grouping.
Clear();
foreach (const SearchProvider::ResultList& result_list, results) {
AddResults(result_list);
}
}
}

View File

@ -46,6 +46,7 @@ public:
void set_use_pretty_covers(bool pretty) { use_pretty_covers_ = pretty; }
void set_provider_order(const QStringList& provider_order) { provider_order_ = provider_order; }
void SetGroupBy(const LibraryModel::Grouping& grouping, bool regroup_now);
void Clear();

View File

@ -28,7 +28,9 @@
#include "core/logging.h"
#include "core/mimedata.h"
#include "core/timeconstants.h"
#include "library/libraryfilterwidget.h"
#include "library/librarymodel.h"
#include "library/groupbydialog.h"
#include <QMenu>
#include <QSortFilterProxyModel>
@ -64,6 +66,8 @@ GlobalSearchView::GlobalSearchView(Application* app, QWidget* parent)
ui_->search->installEventFilter(this);
ui_->results_stack->installEventFilter(this);
ui_->settings->setIcon(IconLoader::Load("configure"));
// Must be a queued connection to ensure the GlobalSearch handles it first.
connect(app_, SIGNAL(SettingsChanged()), SLOT(ReloadSettings()), Qt::QueuedConnection);
@ -122,6 +126,17 @@ GlobalSearchView::GlobalSearchView(Application* app, QWidget* parent)
update_suggestions_timer_->setInterval(kUpdateSuggestionsTimeoutMsec);
connect(update_suggestions_timer_, SIGNAL(timeout()), SLOT(UpdateSuggestions()));
// Add actions to the settings menu
group_by_actions_ = LibraryFilterWidget::CreateGroupByActions(this);
QMenu* settings_menu = new QMenu(this);
settings_menu->addActions(group_by_actions_->actions());
settings_menu->addSeparator();
settings_menu->addAction(IconLoader::Load("configure"),
tr("Configure global search..."), this, SLOT(OpenSettingsDialog()));
ui_->settings->setMenu(settings_menu);
connect(group_by_actions_, SIGNAL(triggered(QAction*)), SLOT(GroupByClicked(QAction*)));
// These have to be queued connections because they may get emitted before
// our call to Search() (or whatever) returns and we add the ID to the map.
connect(engine_, SIGNAL(ResultsAvailable(int,SearchProvider::ResultList)),
@ -159,6 +174,10 @@ void GlobalSearchView::ReloadSettings() {
back_model_->set_provider_order(provider_order);
show_providers_ = s.value("show_providers", true).toBool();
show_suggestions_ = s.value("show_suggestions", true).toBool();
SetGroupBy(LibraryModel::Grouping(
LibraryModel::GroupBy(s.value("group_by1", int(LibraryModel::GroupBy_Artist)).toInt()),
LibraryModel::GroupBy(s.value("group_by2", int(LibraryModel::GroupBy_Album)).toInt()),
LibraryModel::GroupBy(s.value("group_by3", int(LibraryModel::GroupBy_None)).toInt())));
s.endGroup();
// Delete any old status widgets
@ -398,6 +417,7 @@ bool GlobalSearchView::ResultsContextMenuEvent(QContextMenuEvent* event) {
tr("Queue track"), this, SLOT(AddSelectedToPlaylistEnqueue()));
context_menu_->addSeparator();
context_menu_->addMenu(tr("Group by"))->addActions(group_by_actions_->actions());
context_menu_->addAction(IconLoader::Load("configure"),
tr("Configure global search..."), this, SLOT(OpenSettingsDialog()));
}
@ -474,3 +494,45 @@ void GlobalSearchView::FocusOnFilter(QKeyEvent* event) {
void GlobalSearchView::OpenSettingsDialog() {
app_->OpenSettingsDialogAtPage(SettingsDialog::Page_GlobalSearch);
}
void GlobalSearchView::GroupByClicked(QAction* action) {
if (action->property("group_by").isNull()) {
if (!group_by_dialog_) {
group_by_dialog_.reset(new GroupByDialog);
connect(group_by_dialog_.data(), SIGNAL(Accepted(LibraryModel::Grouping)),
SLOT(SetGroupBy(LibraryModel::Grouping)));
}
group_by_dialog_->show();
return;
}
SetGroupBy(action->property("group_by").value<LibraryModel::Grouping>());
}
void GlobalSearchView::SetGroupBy(const LibraryModel::Grouping& g) {
// Update the models
front_model_->SetGroupBy(g, true);
back_model_->SetGroupBy(g, false);
// Save the setting
QSettings s;
s.beginGroup(GlobalSearch::kSettingsGroup);
s.setValue("group_by1", int(g.first));
s.setValue("group_by2", int(g.second));
s.setValue("group_by3", int(g.third));
// Make sure the correct action is checked.
foreach (QAction* action, group_by_actions_->actions()) {
if (action->property("group_by").isNull())
continue;
if (g == action->property("group_by").value<LibraryModel::Grouping>()) {
action->setChecked(true);
return;
}
}
// Check the advanced action
group_by_actions_->actions().last()->setChecked(true);
}

View File

@ -26,10 +26,12 @@
class Application;
class GlobalSearchModel;
class GroupByDialog;
class SearchProviderStatusWidget;
class SuggestionWidget;
class Ui_GlobalSearchView;
class QActionGroup;
class QMimeData;
class QSortFilterProxyModel;
class QStandardItem;
@ -80,6 +82,9 @@ private slots:
void OpenSelectedInNewPlaylist();
void AddSelectedToPlaylistEnqueue();
void GroupByClicked(QAction* action);
void SetGroupBy(const LibraryModel::Grouping& grouping);
private:
MimeData* SelectedMimeData();
@ -90,9 +95,11 @@ private:
Application* app_;
GlobalSearch* engine_;
Ui_GlobalSearchView* ui_;
QScopedPointer<GroupByDialog> group_by_dialog_;
QMenu* context_menu_;
QList<QAction*> context_actions_;
QActionGroup* group_by_actions_;
int last_search_id_;

View File

@ -18,16 +18,33 @@
<number>0</number>
</property>
<item>
<widget class="LineEdit" name="search">
<property name="hint" stdset="0">
<string>Search for anything</string>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
</widget>
<item>
<widget class="LineEdit" name="search">
<property name="hint" stdset="0">
<string>Search for anything</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="settings">
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
<property name="autoRaise">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="results_stack">
<property name="currentIndex">
<number>1</number>
<number>0</number>
</property>
<widget class="QWidget" name="results_page">
<layout class="QVBoxLayout" name="verticalLayout_3">
@ -80,7 +97,7 @@
<x>0</x>
<y>0</y>
<width>435</width>
<height>605</height>
<height>603</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">

View File

@ -78,27 +78,7 @@ LibraryFilterWidget::LibraryFilterWidget(QWidget *parent)
connect(ui_->filter_age_year, SIGNAL(triggered()), filter_age_mapper_, SLOT(map()));
// "Group by ..."
ui_->group_by_artist->setProperty("group_by", QVariant::fromValue(
LibraryModel::Grouping(LibraryModel::GroupBy_Artist)));
ui_->group_by_artist_album->setProperty("group_by", QVariant::fromValue(
LibraryModel::Grouping(LibraryModel::GroupBy_Artist, LibraryModel::GroupBy_Album)));
ui_->group_by_artist_yearalbum->setProperty("group_by", QVariant::fromValue(
LibraryModel::Grouping(LibraryModel::GroupBy_Artist, LibraryModel::GroupBy_YearAlbum)));
ui_->group_by_album->setProperty("group_by", QVariant::fromValue(
LibraryModel::Grouping(LibraryModel::GroupBy_Album)));
ui_->group_by_genre_album->setProperty("group_by", QVariant::fromValue(
LibraryModel::Grouping(LibraryModel::GroupBy_Genre, LibraryModel::GroupBy_Album)));
ui_->group_by_genre_artist_album->setProperty("group_by", QVariant::fromValue(
LibraryModel::Grouping(LibraryModel::GroupBy_Genre, LibraryModel::GroupBy_Artist, LibraryModel::GroupBy_Album)));
group_by_group_ = new QActionGroup(this);
group_by_group_->addAction(ui_->group_by_artist);
group_by_group_->addAction(ui_->group_by_artist_album);
group_by_group_->addAction(ui_->group_by_artist_yearalbum);
group_by_group_->addAction(ui_->group_by_album);
group_by_group_->addAction(ui_->group_by_genre_album);
group_by_group_->addAction(ui_->group_by_genre_artist_album);
group_by_group_->addAction(ui_->group_by_advanced);
group_by_group_ = CreateGroupByActions(this);
group_by_menu_ = new QMenu(tr("Group by"), this);
group_by_menu_->addActions(group_by_group_->actions());
@ -131,6 +111,38 @@ LibraryFilterWidget::~LibraryFilterWidget() {
delete ui_;
}
QActionGroup* LibraryFilterWidget::CreateGroupByActions(QObject* parent) {
QActionGroup* ret = new QActionGroup(parent);
ret->addAction(CreateGroupByAction(tr("Group by Artist"), parent,
LibraryModel::Grouping(LibraryModel::GroupBy_Artist)));
ret->addAction(CreateGroupByAction(tr("Group by Artist/Album"), parent,
LibraryModel::Grouping(LibraryModel::GroupBy_Artist, LibraryModel::GroupBy_Album)));
ret->addAction(CreateGroupByAction(tr("Group by Artist/Year - Album"), parent,
LibraryModel::Grouping(LibraryModel::GroupBy_Artist, LibraryModel::GroupBy_YearAlbum)));
ret->addAction(CreateGroupByAction(tr("Group by Album"), parent,
LibraryModel::Grouping(LibraryModel::GroupBy_Album)));
ret->addAction(CreateGroupByAction(tr("Group by Genre/Album"), parent,
LibraryModel::Grouping(LibraryModel::GroupBy_Genre, LibraryModel::GroupBy_Album)));
ret->addAction(CreateGroupByAction(tr("Group by Genre/Artist/Album"), parent,
LibraryModel::Grouping(LibraryModel::GroupBy_Genre, LibraryModel::GroupBy_Artist, LibraryModel::GroupBy_Album)));
ret->addAction(CreateGroupByAction(tr("Advanced grouping..."), parent,
LibraryModel::Grouping()));
return ret;
}
QAction* LibraryFilterWidget::CreateGroupByAction(
const QString& text, QObject* parent, const LibraryModel::Grouping& grouping) {
QAction* ret = new QAction(text, parent);
ret->setCheckable(true);
if (grouping.first != LibraryModel::GroupBy_None) {
ret->setProperty("group_by", QVariant::fromValue(grouping));
}
return ret;
}
void LibraryFilterWidget::FocusOnFilter(QKeyEvent *event) {
ui_->filter->set_focus();
QApplication::sendEvent(ui_->filter, event);
@ -196,7 +208,9 @@ void LibraryFilterWidget::GroupingChanged(const LibraryModel::Grouping& g) {
return;
}
}
ui_->group_by_advanced->setChecked(true);
// Check the advanced action
group_by_group_->actions().last()->setChecked(true);
}
void LibraryFilterWidget::SetFilterHint(const QString& hint) {

View File

@ -50,6 +50,8 @@ class LibraryFilterWidget : public QWidget {
AlwaysDelayed,
};
static QActionGroup* CreateGroupByActions(QObject* parent);
void SetFilterHint(const QString& hint);
void SetApplyFilterToLibrary(bool filter_applies_to_model) { filter_applies_to_model_ = filter_applies_to_model; }
void SetDelayBehaviour(DelayBehaviour behaviour) { delay_behaviour_ = behaviour; }
@ -82,6 +84,10 @@ class LibraryFilterWidget : public QWidget {
void FilterTextChanged(const QString& text);
void FilterDelayTimeout();
private:
static QAction* CreateGroupByAction(const QString& text, QObject* parent,
const LibraryModel::Grouping& grouping);
private:
Ui_LibraryFilterWidget* ui_;
LibraryModel* model_;

View File

@ -95,62 +95,6 @@
<string>Added this month</string>
</property>
</action>
<action name="group_by_artist">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Group by Artist</string>
</property>
</action>
<action name="group_by_artist_album">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Group by Artist/Album</string>
</property>
</action>
<action name="group_by_artist_yearalbum">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Group by Artist/Year - Album</string>
</property>
</action>
<action name="group_by_album">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Group by Album</string>
</property>
</action>
<action name="group_by_genre_album">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Group by Genre/Album</string>
</property>
</action>
<action name="group_by_genre_artist_album">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Group by Genre/Artist/Album</string>
</property>
</action>
<action name="group_by_advanced">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Advanced grouping...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -99,6 +99,9 @@ class LibraryModel : public SimpleTreeModel<LibraryItem> {
second == other.second &&
third == other.third;
}
bool operator !=(const Grouping& other) const {
return ! (*this == other);
}
};
LibraryBackend* backend() const { return backend_; }