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