1 /* This file is part of Clementine.
2 Copyright 2010, David Sansome <me@davidsansome.com>
3
4 Clementine is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 Clementine is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Clementine. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "searchpreview.h"
19 #include "ui_searchpreview.h"
20
21 #include <memory>
22
23 #include <QtConcurrentRun>
24
25 #include "querygenerator.h"
26 #include "playlist/playlist.h"
27
28 namespace smart_playlists {
29
SearchPreview(QWidget * parent)30 SearchPreview::SearchPreview(QWidget* parent)
31 : QWidget(parent), ui_(new Ui_SmartPlaylistSearchPreview), model_(nullptr) {
32 ui_->setupUi(this);
33
34 // Prevent editing songs and saving settings (like header columns and
35 // geometry)
36 ui_->tree->setEditTriggers(QAbstractItemView::NoEditTriggers);
37 ui_->tree->SetReadOnlySettings(true);
38
39 QFont bold_font;
40 bold_font.setBold(true);
41 ui_->preview_label->setFont(bold_font);
42 ui_->busy_container->hide();
43 }
44
~SearchPreview()45 SearchPreview::~SearchPreview() { delete ui_; }
46
set_application(Application * app)47 void SearchPreview::set_application(Application* app) {
48 ui_->tree->SetApplication(app);
49 }
50
set_library(LibraryBackend * backend)51 void SearchPreview::set_library(LibraryBackend* backend) {
52 backend_ = backend;
53
54 model_ = new Playlist(nullptr, nullptr, backend_, -1, QString(), false, this);
55 ui_->tree->setModel(model_);
56 ui_->tree->SetPlaylist(model_);
57 ui_->tree->SetItemDelegates(backend_);
58 }
59
Update(const Search & search)60 void SearchPreview::Update(const Search& search) {
61 if (search == last_search_) {
62 // This search was the same as the last one we did
63 return;
64 }
65
66 if (generator_ || isHidden()) {
67 // It's busy generating something already, or the widget isn't visible
68 pending_search_ = search;
69 return;
70 }
71
72 RunSearch(search);
73 }
74
showEvent(QShowEvent * e)75 void SearchPreview::showEvent(QShowEvent* e) {
76 if (pending_search_.is_valid() && !generator_) {
77 // There was a search waiting while we were hidden, so run it now
78 RunSearch(pending_search_);
79 pending_search_ = Search();
80 }
81
82 QWidget::showEvent(e);
83 }
84
DoRunSearch(GeneratorPtr gen)85 PlaylistItemList DoRunSearch(GeneratorPtr gen) { return gen->Generate(); }
86
RunSearch(const Search & search)87 void SearchPreview::RunSearch(const Search& search) {
88 generator_.reset(new QueryGenerator);
89 generator_->set_library(backend_);
90 std::dynamic_pointer_cast<QueryGenerator>(generator_)->Load(search);
91
92 ui_->busy_container->show();
93 ui_->count_label->hide();
94 QFuture<PlaylistItemList> future = QtConcurrent::run(DoRunSearch, generator_);
95 NewClosure(future, this, SLOT(SearchFinished(QFuture<PlaylistItemList>)),
96 future);
97 }
98
SearchFinished(QFuture<PlaylistItemList> future)99 void SearchPreview::SearchFinished(QFuture<PlaylistItemList> future) {
100 last_search_ =
101 std::dynamic_pointer_cast<QueryGenerator>(generator_)->search();
102 generator_.reset();
103
104 if (pending_search_.is_valid() && pending_search_ != last_search_) {
105 // There was another search done while we were running - throw away these
106 // results and do that one now instead
107 RunSearch(pending_search_);
108 pending_search_ = Search();
109 return;
110 }
111
112 PlaylistItemList all_items = future.result();
113 PlaylistItemList displayed_items = all_items.mid(0, Generator::kDefaultLimit);
114
115 model_->Clear();
116 model_->InsertItems(displayed_items);
117
118 if (displayed_items.count() < all_items.count()) {
119 ui_->count_label->setText(tr("%1 songs found (showing %2)")
120 .arg(all_items.count())
121 .arg(displayed_items.count()));
122 } else {
123 ui_->count_label->setText(tr("%1 songs found").arg(all_items.count()));
124 }
125
126 ui_->busy_container->hide();
127 ui_->count_label->show();
128 }
129
130 } // namespace
131