Make the grouping of global search results configurable
This commit is contained in:
parent
3e410021a5
commit
57865f82c2
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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_;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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_; }
|
||||
|
|
Loading…
Reference in New Issue