Merge lp:~jamesh/mediascanner2/media-filter into lp:mediascanner2

Proposed by James Henstridge
Status: Merged
Merged at revision: 232
Proposed branch: lp:~jamesh/mediascanner2/media-filter
Merge into: lp:mediascanner2
Prerequisite: lp:~jamesh/mediascanner2/dbus-apparmor
Diff against target: 2163 lines (+1313/-184)
33 files modified
src/mediascanner/CMakeLists.txt (+1/-0)
src/mediascanner/Filter.cc (+154/-0)
src/mediascanner/Filter.hh (+66/-0)
src/mediascanner/MediaStore.cc (+93/-34)
src/mediascanner/MediaStore.hh (+6/-3)
src/ms-dbus/dbus-codec.cc (+45/-0)
src/ms-dbus/dbus-codec.hh (+24/-0)
src/ms-dbus/dbus-interface.hh (+26/-0)
src/ms-dbus/service-skeleton.cc (+64/-14)
src/ms-dbus/service-stub.cc (+30/-15)
src/ms-dbus/service-stub.hh (+6/-3)
src/qml/Ubuntu/MediaScanner/AlbumModelBase.cc (+1/-0)
src/qml/Ubuntu/MediaScanner/AlbumModelBase.hh (+3/-1)
src/qml/Ubuntu/MediaScanner/AlbumsModel.cc (+61/-22)
src/qml/Ubuntu/MediaScanner/AlbumsModel.hh (+11/-7)
src/qml/Ubuntu/MediaScanner/ArtistsModel.cc (+27/-2)
src/qml/Ubuntu/MediaScanner/ArtistsModel.hh (+8/-1)
src/qml/Ubuntu/MediaScanner/CMakeLists.txt (+1/-0)
src/qml/Ubuntu/MediaScanner/GenresModel.cc (+86/-0)
src/qml/Ubuntu/MediaScanner/GenresModel.hh (+71/-0)
src/qml/Ubuntu/MediaScanner/MediaFileModelBase.cc (+1/-0)
src/qml/Ubuntu/MediaScanner/MediaFileModelBase.hh (+3/-1)
src/qml/Ubuntu/MediaScanner/SongsModel.cc (+82/-34)
src/qml/Ubuntu/MediaScanner/SongsModel.hh (+14/-10)
src/qml/Ubuntu/MediaScanner/plugin.cc (+2/-0)
src/qml/Ubuntu/MediaScanner/plugin.qmltypes (+29/-5)
src/qml/Ubuntu/MediaScanner/qmldir (+1/-0)
test/qml/tst_albumsmodel.qml (+91/-0)
test/qml/tst_artistsmodel.qml (+68/-0)
test/qml/tst_genresmodel.qml (+44/-0)
test/qml/tst_songsmodel.qml (+104/-0)
test/test_dbus.cc (+39/-12)
test/test_mediastore.cc (+51/-20)
To merge this branch: bzr merge lp:~jamesh/mediascanner2/media-filter
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Mediascanner Team Pending
Review via email: mp+221335@code.launchpad.net

Commit message

Introduce a mediascanner::Filter type to hold search parameters for the various MediaStore::list*() methods, and expand them to handle genres. The new API also distinguishes between an unset filter and a filter set to "". Make similar changes to the QML API, and add notify signals to the rowCount properties.

Description of the change

Introduce a mediascanner::Filter type to hold search parameters for the various MediaStore::list*() methods, and expand them to handle genres. The new API also distinguishes between an unset filter and a filter set to "". Make similar changes to the QML API, and add notify signals to the rowCount properties.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/mediascanner/CMakeLists.txt'
2--- src/mediascanner/CMakeLists.txt 2014-05-29 09:17:39 +0000
3+++ src/mediascanner/CMakeLists.txt 2014-05-29 09:17:39 +0000
4@@ -2,6 +2,7 @@
5 MediaFile.cc
6 MediaFileBuilder.cc
7 MediaFilePrivate.cc
8+ Filter.cc
9 Album.cc
10 MediaStore.cc
11 utils.cc
12
13=== added file 'src/mediascanner/Filter.cc'
14--- src/mediascanner/Filter.cc 1970-01-01 00:00:00 +0000
15+++ src/mediascanner/Filter.cc 2014-05-29 09:17:39 +0000
16@@ -0,0 +1,154 @@
17+/*
18+ * Copyright (C) 2014 Canonical, Ltd.
19+ *
20+ * Authors:
21+ * James Henstridge <james.henstridge@canonical.com>
22+ *
23+ * This program is free software: you can redistribute it and/or modify
24+ * it under the terms of the GNU Lesser General Public License version 3 as
25+ * published by the Free Software Foundation.
26+ *
27+ * This program is distributed in the hope that it will be useful,
28+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
29+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30+ * GNU Lesser General Public License for more details.
31+ *
32+ * You should have received a copy of the GNU Lesser General Public License
33+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
34+ */
35+
36+#include "Filter.hh"
37+
38+using std::string;
39+
40+namespace mediascanner {
41+
42+struct Filter::Private {
43+ string artist;
44+ string album;
45+ string album_artist;
46+ string genre;
47+
48+ bool have_artist;
49+ bool have_album;
50+ bool have_album_artist;
51+ bool have_genre;
52+
53+ Private() :
54+ have_artist(false), have_album(false), have_album_artist(false),
55+ have_genre(false) {
56+ }
57+};
58+
59+Filter::Filter() : p(new Private) {
60+}
61+
62+Filter::Filter(const Filter &other) : Filter() {
63+ *p = *other.p;
64+}
65+
66+Filter::~Filter() {
67+ delete p;
68+}
69+
70+bool Filter::operator==(const Filter &other) const {
71+ return
72+ p->have_artist == other.p->have_artist &&
73+ p->have_album == other.p->have_album &&
74+ p->have_album_artist == other.p->have_album_artist &&
75+ p->have_genre == other.p->have_genre &&
76+ p->artist == other.p->artist &&
77+ p->album == other.p->album &&
78+ p->album_artist == other.p->album_artist &&
79+ p->genre == other.p->genre;
80+}
81+
82+bool Filter::operator!=(const Filter &other) const {
83+ return !(*this == other);
84+}
85+
86+Filter &Filter::operator=(const Filter &other) {
87+ *p = *other.p;
88+ return *this;
89+}
90+
91+void Filter::clear() {
92+ unsetArtist();
93+ unsetAlbum();
94+ unsetAlbumArtist();
95+ unsetGenre();
96+}
97+
98+void Filter::setArtist(const std::string &artist) {
99+ p->artist = artist;
100+ p->have_artist = true;
101+}
102+
103+void Filter::unsetArtist() {
104+ p->artist = "";
105+ p->have_artist = false;
106+}
107+
108+bool Filter::hasArtist() const {
109+ return p->have_artist;
110+}
111+
112+const std::string &Filter::getArtist() const {
113+ return p->artist;
114+}
115+
116+void Filter::setAlbum(const std::string &album) {
117+ p->album = album;
118+ p->have_album = true;
119+}
120+
121+void Filter::unsetAlbum() {
122+ p->album = "";
123+ p->have_album = false;
124+}
125+
126+bool Filter::hasAlbum() const {
127+ return p->have_album;
128+}
129+
130+const std::string &Filter::getAlbum() const {
131+ return p->album;
132+}
133+
134+void Filter::setAlbumArtist(const std::string &album_artist) {
135+ p->album_artist = album_artist;
136+ p->have_album_artist = true;
137+}
138+
139+void Filter::unsetAlbumArtist() {
140+ p->album_artist = "";
141+ p->have_album_artist = false;
142+}
143+
144+bool Filter::hasAlbumArtist() const {
145+ return p->have_album_artist;
146+}
147+
148+const std::string &Filter::getAlbumArtist() const {
149+ return p->album_artist;
150+}
151+
152+void Filter::setGenre(const std::string &genre) {
153+ p->genre = genre;
154+ p->have_genre = true;
155+}
156+
157+void Filter::unsetGenre() {
158+ p->genre = "";
159+ p->have_genre = false;
160+}
161+
162+bool Filter::hasGenre() const {
163+ return p->have_genre;
164+}
165+
166+const std::string &Filter::getGenre() const {
167+ return p->genre;
168+}
169+
170+}
171
172=== added file 'src/mediascanner/Filter.hh'
173--- src/mediascanner/Filter.hh 1970-01-01 00:00:00 +0000
174+++ src/mediascanner/Filter.hh 2014-05-29 09:17:39 +0000
175@@ -0,0 +1,66 @@
176+/*
177+ * Copyright (C) 2014 Canonical, Ltd.
178+ *
179+ * Authors:
180+ * James Henstridge <james.henstridge@canonical.com>
181+ *
182+ * This program is free software: you can redistribute it and/or modify
183+ * it under the terms of the GNU Lesser General Public License version 3 as
184+ * published by the Free Software Foundation.
185+ *
186+ * This program is distributed in the hope that it will be useful,
187+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
188+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
189+ * GNU Lesser General Public License for more details.
190+ *
191+ * You should have received a copy of the GNU Lesser General Public License
192+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
193+ */
194+
195+#ifndef MEDIAFILTER_H_
196+#define MEDIAFILTER_H_
197+
198+#include <string>
199+
200+namespace mediascanner {
201+
202+class Filter final {
203+public:
204+ Filter();
205+ Filter(const Filter &other);
206+ ~Filter();
207+
208+ Filter &operator=(const Filter &other);
209+ bool operator==(const Filter &other) const;
210+ bool operator!=(const Filter &other) const;
211+
212+ void clear();
213+
214+ void setArtist(const std::string &artist);
215+ void unsetArtist();
216+ bool hasArtist() const;
217+ const std::string &getArtist() const;
218+
219+ void setAlbum(const std::string &album);
220+ void unsetAlbum();
221+ bool hasAlbum() const;
222+ const std::string &getAlbum() const;
223+
224+ void setAlbumArtist(const std::string &album_artist);
225+ void unsetAlbumArtist();
226+ bool hasAlbumArtist() const;
227+ const std::string &getAlbumArtist() const;
228+
229+ void setGenre(const std::string &genre);
230+ void unsetGenre();
231+ bool hasGenre() const;
232+ const std::string &getGenre() const;
233+
234+private:
235+ struct Private;
236+ Private *p;
237+};
238+
239+}
240+
241+#endif
242
243=== modified file 'src/mediascanner/MediaStore.cc'
244--- src/mediascanner/MediaStore.cc 2014-05-29 09:17:39 +0000
245+++ src/mediascanner/MediaStore.cc 2014-05-29 09:17:39 +0000
246@@ -33,6 +33,7 @@
247 #include "MediaFile.hh"
248 #include "MediaFileBuilder.hh"
249 #include "Album.hh"
250+#include "Filter.hh"
251 #include "internal/sqliteutils.hh"
252 #include "internal/utils.hh"
253
254@@ -448,21 +449,24 @@
255 }
256 }
257
258-std::vector<MediaFile> MediaStore::listSongs(const std::string& artist, const std::string& album, const std::string& album_artist, int limit) const {
259+std::vector<MediaFile> MediaStore::listSongs(const Filter &filter, int limit) const {
260 std::string qs(R"(
261 SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, type
262 FROM media
263 WHERE type = ?
264 )");
265- if (!artist.empty()) {
266+ if (filter.hasArtist()) {
267 qs += " AND artist = ?";
268 }
269- if (!album.empty()) {
270+ if (filter.hasAlbum()) {
271 qs += " AND album = ?";
272 }
273- if (!album_artist.empty()) {
274+ if (filter.hasAlbumArtist()) {
275 qs += " AND album_artist = ?";
276 }
277+ if (filter.hasGenre()) {
278+ qs += " AND genre = ?";
279+ }
280 qs += R"(
281 ORDER BY album_artist, album, disc_number, track_number, title
282 LIMIT ?
283@@ -470,31 +474,37 @@
284 Statement query(p->db, qs.c_str());
285 int param = 1;
286 query.bind(param++, (int)AudioMedia);
287- if (!artist.empty()) {
288- query.bind(param++, artist);
289- }
290- if (!album.empty()) {
291- query.bind(param++, album);
292- }
293- if (!album_artist.empty()) {
294- query.bind(param++, album_artist);
295+ if (filter.hasArtist()) {
296+ query.bind(param++, filter.getArtist());
297+ }
298+ if (filter.hasAlbum()) {
299+ query.bind(param++, filter.getAlbum());
300+ }
301+ if (filter.hasAlbumArtist()) {
302+ query.bind(param++, filter.getAlbumArtist());
303+ }
304+ if (filter.hasGenre()) {
305+ query.bind(param++, filter.getGenre());
306 }
307 query.bind(param++, limit);
308
309 return collect_media(query);
310 }
311
312-std::vector<Album> MediaStore::listAlbums(const std::string& artist, const std::string& album_artist, int limit) const {
313+std::vector<Album> MediaStore::listAlbums(const Filter &filter, int limit) const {
314 std::string qs(R"(
315 SELECT album, album_artist FROM media
316 WHERE type = ?
317 )");
318- if (!artist.empty()) {
319+ if (filter.hasArtist()) {
320 qs += " AND artist = ?";
321 }
322- if (!album_artist.empty()) {
323+ if (filter.hasAlbumArtist()) {
324 qs += " AND album_artist = ?";
325 }
326+ if (filter.hasGenre()) {
327+ qs += "AND genre = ?";
328+ }
329 qs += R"(
330 GROUP BY album, album_artist
331 ORDER BY album_artist, album
332@@ -503,37 +513,68 @@
333 Statement query(p->db, qs.c_str());
334 int param = 1;
335 query.bind(param++, (int)AudioMedia);
336- if (!artist.empty()) {
337- query.bind(param++, artist);
338- }
339- if (!album_artist.empty()) {
340- query.bind(param++, album_artist);
341+ if (filter.hasArtist()) {
342+ query.bind(param++, filter.getArtist());
343+ }
344+ if (filter.hasAlbumArtist()) {
345+ query.bind(param++, filter.getAlbumArtist());
346+ }
347+ if (filter.hasGenre()) {
348+ query.bind(param++, filter.getGenre());
349 }
350 query.bind(param++, limit);
351
352 return collect_albums(query);
353 }
354
355-vector<std::string> MediaStore::listArtists(bool album_artists, int limit) const {
356- const char *qs;
357-
358- if (album_artists) {
359- qs = R"(
360+vector<std::string> MediaStore::listArtists(const Filter &filter, int limit) const {
361+ string qs(R"(
362+SELECT artist FROM media
363+ WHERE type = ?
364+)");
365+ if (filter.hasGenre()) {
366+ qs += " AND genre = ?";
367+ }
368+ qs += R"(
369+ GROUP BY artist
370+ ORDER BY artist
371+ LIMIT ?
372+)";
373+ Statement query(p->db, qs.c_str());
374+ int param = 1;
375+ query.bind(param++, (int)AudioMedia);
376+ if (filter.hasGenre()) {
377+ query.bind(param++, filter.getGenre());
378+ }
379+ query.bind(param++, limit);
380+
381+ vector<string> artists;
382+ while (query.step()) {
383+ artists.push_back(query.getText(0));
384+ }
385+ return artists;
386+}
387+
388+vector<std::string> MediaStore::listAlbumArtists(const Filter &filter, int limit) const {
389+ string qs(R"(
390 SELECT album_artist FROM media
391+ WHERE type = ?
392+)");
393+ if (filter.hasGenre()) {
394+ qs += " AND genre = ?";
395+ }
396+ qs += R"(
397 GROUP BY album_artist
398 ORDER BY album_artist
399 LIMIT ?
400 )";
401- } else {
402- qs = R"(
403-SELECT artist FROM media
404- GROUP BY artist
405- ORDER BY artist
406- LIMIT ?
407-)";
408+ Statement query(p->db, qs.c_str());
409+ int param = 1;
410+ query.bind(param++, (int)AudioMedia);
411+ if (filter.hasGenre()) {
412+ query.bind(param++, filter.getGenre());
413 }
414- Statement query(p->db, qs);
415- query.bind(1, limit);
416+ query.bind(param++, limit);
417
418 vector<string> artists;
419 while (query.step()) {
420@@ -542,6 +583,24 @@
421 return artists;
422 }
423
424+vector<std::string> MediaStore::listGenres(int limit) const {
425+ Statement query(p->db, R"(
426+SELECT genre FROM media
427+ WHERE type = ?
428+ GROUP BY genre
429+ ORDER BY genre
430+ LIMIT ?
431+)");
432+ query.bind(1, (int)AudioMedia);
433+ query.bind(2, limit);
434+
435+ vector<string> genres;
436+ while (query.step()) {
437+ genres.push_back(query.getText(0));
438+ }
439+ return genres;
440+}
441+
442 void MediaStorePrivate::pruneDeleted() {
443 vector<string> deleted;
444 Statement query(db, "SELECT filename FROM media");
445
446=== modified file 'src/mediascanner/MediaStore.hh'
447--- src/mediascanner/MediaStore.hh 2014-05-29 09:17:39 +0000
448+++ src/mediascanner/MediaStore.hh 2014-05-29 09:17:39 +0000
449@@ -29,6 +29,7 @@
450 struct MediaStorePrivate;
451 class MediaFile;
452 class Album;
453+class Filter;
454
455 enum OpenType {
456 MS_READ_ONLY,
457@@ -53,9 +54,11 @@
458 std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const;
459 std::vector<MediaFile> getAlbumSongs(const Album& album) const;
460 std::string getETag(const std::string &filename) const;
461- std::vector<MediaFile> listSongs(const std::string& artist="", const std::string& album="", const std::string& album_artist="", int limit=-1) const;
462- std::vector<Album> listAlbums(const std::string& artist="", const std::string& album_artist="", int limit=-1) const;
463- std::vector<std::string> listArtists(bool album_artists, int limit=-1) const;
464+ std::vector<MediaFile> listSongs(const Filter &filter, int limit=-1) const;
465+ std::vector<Album> listAlbums(const Filter &filter, int limit=-1) const;
466+ std::vector<std::string> listArtists(const Filter &filter, int limit=-1) const;
467+ std::vector<std::string>listAlbumArtists(const Filter &filter, int limit=-1) const;
468+ std::vector<std::string>listGenres(int limit=-1) const;
469
470 size_t size() const;
471 void pruneDeleted();
472
473=== modified file 'src/ms-dbus/dbus-codec.cc'
474--- src/ms-dbus/dbus-codec.cc 2014-05-29 09:17:39 +0000
475+++ src/ms-dbus/dbus-codec.cc 2014-05-29 09:17:39 +0000
476@@ -24,6 +24,7 @@
477 #include <mediascanner/MediaFile.hh>
478 #include <mediascanner/MediaFileBuilder.hh>
479 #include <mediascanner/Album.hh>
480+#include <mediascanner/Filter.hh>
481 #include "dbus-codec.hh"
482
483 using core::dbus::Message;
484@@ -32,6 +33,7 @@
485 using mediascanner::MediaFileBuilder;
486 using mediascanner::MediaType;
487 using mediascanner::Album;
488+using mediascanner::Filter;
489 using std::string;
490
491 void Codec<MediaFile>::encode_argument(Message::Writer &out, const MediaFile &file) {
492@@ -88,3 +90,46 @@
493 r >> title >> artist;
494 album = Album(title, artist);
495 }
496+
497+void Codec<Filter>::encode_argument(Message::Writer &out, const Filter &filter) {
498+ auto w = out.open_array(core::dbus::types::Signature("{ss}"));
499+
500+ if (filter.hasArtist()) {
501+ w.close_dict_entry(
502+ w.open_dict_entry() << string("artist") << filter.getArtist());
503+ }
504+ if (filter.hasAlbum()) {
505+ w.close_dict_entry(
506+ w.open_dict_entry() << string("album") << filter.getAlbum());
507+ }
508+ if (filter.hasAlbumArtist()) {
509+ w.close_dict_entry(
510+ w.open_dict_entry() << string("album_artist") << filter.getAlbumArtist());
511+ }
512+ if (filter.hasGenre()) {
513+ w.close_dict_entry(
514+ w.open_dict_entry() << string("genre") << filter.getGenre());
515+ }
516+
517+ out.close_array(std::move(w));
518+}
519+
520+void Codec<Filter>::decode_argument(Message::Reader &in, Filter &filter) {
521+ auto r = in.pop_array();
522+
523+ filter.clear();
524+ while (r.type() != ArgumentType::invalid) {
525+ string key, value;
526+ r.pop_dict_entry() >> key >> value;
527+
528+ if (key == "artist") {
529+ filter.setArtist(value);
530+ } else if (key == "album") {
531+ filter.setAlbum(value);
532+ } else if (key == "album_artist") {
533+ filter.setAlbumArtist(value);
534+ } else if (key == "genre") {
535+ filter.setGenre(value);
536+ }
537+ }
538+}
539
540=== modified file 'src/ms-dbus/dbus-codec.hh'
541--- src/ms-dbus/dbus-codec.hh 2014-05-29 09:17:39 +0000
542+++ src/ms-dbus/dbus-codec.hh 2014-05-29 09:17:39 +0000
543@@ -27,6 +27,7 @@
544 namespace mediascanner {
545 class MediaFile;
546 class Album;
547+class Filter;
548 }
549
550 namespace core {
551@@ -44,6 +45,12 @@
552 static void decode_argument(Message::Reader &in, mediascanner::Album &album);
553 };
554
555+template <>
556+struct Codec<mediascanner::Filter> {
557+ static void encode_argument(Message::Writer &out, const mediascanner::Filter &filter);
558+ static void decode_argument(Message::Reader &in, mediascanner::Filter &filter);
559+};
560+
561 namespace helper {
562
563 template<>
564@@ -80,6 +87,23 @@
565 }
566 };
567
568+template<>
569+struct TypeMapper<mediascanner::Filter> {
570+ constexpr static ArgumentType type_value() {
571+ return ArgumentType::array;
572+ }
573+ constexpr static bool is_basic_type() {
574+ return false;
575+ }
576+ constexpr static bool requires_signature() {
577+ return true;
578+ }
579+ static const std::string &signature() {
580+ static const std::string s = "a{ss}";
581+ return s;
582+ }
583+};
584+
585 }
586
587 }
588
589=== modified file 'src/ms-dbus/dbus-interface.hh'
590--- src/ms-dbus/dbus-interface.hh 2014-05-29 09:17:39 +0000
591+++ src/ms-dbus/dbus-interface.hh 2014-05-29 09:17:39 +0000
592@@ -153,6 +153,32 @@
593 return std::chrono::seconds{1};
594 }
595 };
596+
597+ struct ListAlbumArtists {
598+ typedef MediaStoreInterface Interface;
599+
600+ inline static const std::string& name() {
601+ static std::string s = "ListAlbumArtists";
602+ return s;
603+ }
604+
605+ inline static const std::chrono::milliseconds default_timeout() {
606+ return std::chrono::seconds{1};
607+ }
608+ };
609+
610+ struct ListGenres {
611+ typedef MediaStoreInterface Interface;
612+
613+ inline static const std::string& name() {
614+ static std::string s = "ListGenres";
615+ return s;
616+ }
617+
618+ inline static const std::chrono::milliseconds default_timeout() {
619+ return std::chrono::seconds{1};
620+ }
621+ };
622 };
623
624 }
625
626=== modified file 'src/ms-dbus/service-skeleton.cc'
627--- src/ms-dbus/service-skeleton.cc 2014-05-29 09:17:39 +0000
628+++ src/ms-dbus/service-skeleton.cc 2014-05-29 09:17:39 +0000
629@@ -6,6 +6,7 @@
630 #include <sys/apparmor.h>
631
632 #include <mediascanner/Album.hh>
633+#include <mediascanner/Filter.hh>
634 #include <mediascanner/MediaFile.hh>
635 #include <mediascanner/MediaStore.hh>
636
637@@ -88,6 +89,16 @@
638 &Private::handle_list_artists,
639 this,
640 std::placeholders::_1));
641+ object->install_method_handler<MediaStoreInterface::ListAlbumArtists>(
642+ std::bind(
643+ &Private::handle_list_album_artists,
644+ this,
645+ std::placeholders::_1));
646+ object->install_method_handler<MediaStoreInterface::ListGenres>(
647+ std::bind(
648+ &Private::handle_list_genres,
649+ this,
650+ std::placeholders::_1));
651 }
652
653 std::string get_client_apparmor_context(const Message::Ptr &message) {
654@@ -253,12 +264,12 @@
655 if (!check_access(message, AudioMedia))
656 return;
657
658- std::string artist, album, album_artist;
659+ Filter filter;
660 int32_t limit;
661- message->reader() >> artist >> album >> album_artist >> limit;
662+ message->reader() >> filter >> limit;
663 Message::Ptr reply;
664 try {
665- auto results = store->listSongs(artist, album, album_artist, limit);
666+ auto results = store->listSongs(filter, limit);
667 reply = Message::make_method_return(message);
668 reply->writer() << results;
669 } catch (const std::exception &e) {
670@@ -273,12 +284,12 @@
671 if (!check_access(message, AudioMedia))
672 return;
673
674- std::string artist, album_artist;
675+ Filter filter;
676 int32_t limit;
677- message->reader() >> artist >> album_artist >> limit;
678+ message->reader() >> filter >> limit;
679 Message::Ptr reply;
680 try {
681- auto albums = store->listAlbums(artist, album_artist, limit);
682+ auto albums = store->listAlbums(filter, limit);
683 reply = Message::make_method_return(message);
684 reply->writer() << albums;
685 } catch (const std::exception &e) {
686@@ -293,14 +304,53 @@
687 if (!check_access(message, AudioMedia))
688 return;
689
690- bool album_artists;
691- int32_t limit;
692- message->reader() >> album_artists >> limit;
693- Message::Ptr reply;
694- try {
695- auto artists = store->listArtists(album_artists, limit);
696- reply = Message::make_method_return(message);
697- reply->writer() << artists;
698+ Filter filter;
699+ int32_t limit;
700+ message->reader() >> filter >> limit;
701+ Message::Ptr reply;
702+ try {
703+ auto artists = store->listArtists(filter, limit);
704+ reply = Message::make_method_return(message);
705+ reply->writer() << artists;
706+ } catch (const std::exception &e) {
707+ reply = Message::make_error(
708+ message, MediaStoreInterface::Errors::Error::name(),
709+ e.what());
710+ }
711+ impl->access_bus()->send(reply);
712+ }
713+
714+ void handle_list_album_artists(const Message::Ptr &message) {
715+ if (!check_access(message, AudioMedia))
716+ return;
717+
718+ Filter filter;
719+ int32_t limit;
720+ message->reader() >> filter >> limit;
721+ Message::Ptr reply;
722+ try {
723+ auto artists = store->listAlbumArtists(filter, limit);
724+ reply = Message::make_method_return(message);
725+ reply->writer() << artists;
726+ } catch (const std::exception &e) {
727+ reply = Message::make_error(
728+ message, MediaStoreInterface::Errors::Error::name(),
729+ e.what());
730+ }
731+ impl->access_bus()->send(reply);
732+ }
733+
734+ void handle_list_genres(const Message::Ptr &message) {
735+ if (!check_access(message, AudioMedia))
736+ return;
737+
738+ int32_t limit;
739+ message->reader() >> limit;
740+ Message::Ptr reply;
741+ try {
742+ auto genres = store->listGenres(limit);
743+ reply = Message::make_method_return(message);
744+ reply->writer() << genres;
745 } catch (const std::exception &e) {
746 reply = Message::make_error(
747 message, MediaStoreInterface::Errors::Error::name(),
748
749=== modified file 'src/ms-dbus/service-stub.cc'
750--- src/ms-dbus/service-stub.cc 2014-05-29 09:17:39 +0000
751+++ src/ms-dbus/service-stub.cc 2014-05-29 09:17:39 +0000
752@@ -20,6 +20,7 @@
753 #include <stdexcept>
754
755 #include <mediascanner/Album.hh>
756+#include <mediascanner/Filter.hh>
757 #include <mediascanner/MediaFile.hh>
758 #include "service-stub.hh"
759 #include "dbus-interface.hh"
760@@ -79,21 +80,35 @@
761 return result.value();
762 }
763
764-std::vector<MediaFile> ServiceStub::listSongs(const string &artist, const string &album, const string &album_artist, int limit) const {
765- auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListSongs, std::vector<MediaFile>>(artist, album, album_artist, (int32_t)limit);
766- if (result.is_error())
767- throw std::runtime_error(result.error().print());
768- return result.value();
769-}
770-
771-std::vector<Album> ServiceStub::listAlbums(const string &artist, const string &album_artist, int limit) const {
772- auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListAlbums, std::vector<Album>>(artist, album_artist, (int32_t)limit);
773- if (result.is_error())
774- throw std::runtime_error(result.error().print());
775- return result.value();
776-}
777-std::vector<string> ServiceStub::listArtists(bool album_artists, int limit) const {
778- auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListArtists, std::vector<string>>(album_artists, (int32_t)limit);
779+std::vector<MediaFile> ServiceStub::listSongs(const Filter &filter, int limit) const {
780+ auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListSongs, std::vector<MediaFile>>(filter, (int32_t)limit);
781+ if (result.is_error())
782+ throw std::runtime_error(result.error().print());
783+ return result.value();
784+}
785+
786+std::vector<Album> ServiceStub::listAlbums(const Filter &filter, int limit) const {
787+ auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListAlbums, std::vector<Album>>(filter, (int32_t)limit);
788+ if (result.is_error())
789+ throw std::runtime_error(result.error().print());
790+ return result.value();
791+}
792+std::vector<string> ServiceStub::listArtists(const Filter &filter, int limit) const {
793+ auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListArtists, std::vector<string>>(filter, (int32_t)limit);
794+ if (result.is_error())
795+ throw std::runtime_error(result.error().print());
796+ return result.value();
797+}
798+
799+std::vector<string> ServiceStub::listAlbumArtists(const Filter &filter, int limit) const {
800+ auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListAlbumArtists, std::vector<string>>(filter, (int32_t)limit);
801+ if (result.is_error())
802+ throw std::runtime_error(result.error().print());
803+ return result.value();
804+}
805+
806+std::vector<string> ServiceStub::listGenres(int limit) const {
807+ auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListGenres, std::vector<string>>((int32_t)limit);
808 if (result.is_error())
809 throw std::runtime_error(result.error().print());
810 return result.value();
811
812=== modified file 'src/ms-dbus/service-stub.hh'
813--- src/ms-dbus/service-stub.hh 2014-05-29 09:17:39 +0000
814+++ src/ms-dbus/service-stub.hh 2014-05-29 09:17:39 +0000
815@@ -32,6 +32,7 @@
816 namespace mediascanner {
817
818 class Album;
819+class Filter;
820 class MediaFile;
821
822 namespace dbus {
823@@ -46,9 +47,11 @@
824 std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const;
825 std::vector<MediaFile> getAlbumSongs(const Album& album) const;
826 std::string getETag(const std::string &filename) const;
827- std::vector<MediaFile> listSongs(const std::string& artist="", const std::string& album="", const std::string& album_artist="", int limit=-1) const;
828- std::vector<Album> listAlbums(const std::string& artist="", const std::string& album_artist="", int limit=-1) const;
829- std::vector<std::string> listArtists(bool album_artists, int limit=-1) const;
830+ std::vector<MediaFile> listSongs(const Filter &filter, int limit=-1) const;
831+ std::vector<Album> listAlbums(const Filter &filter, int limit=-1) const;
832+ std::vector<std::string> listArtists(const Filter &filter, int limit=-1) const;
833+ std::vector<std::string> listAlbumArtists(const Filter &filter, int limit=-1) const;
834+ std::vector<std::string> listGenres(int limit=-1) const;
835
836 private:
837 struct Private;
838
839=== modified file 'src/qml/Ubuntu/MediaScanner/AlbumModelBase.cc'
840--- src/qml/Ubuntu/MediaScanner/AlbumModelBase.cc 2014-05-06 09:09:49 +0000
841+++ src/qml/Ubuntu/MediaScanner/AlbumModelBase.cc 2014-05-29 09:17:39 +0000
842@@ -62,4 +62,5 @@
843 beginResetModel();
844 this->results = results;
845 endResetModel();
846+ Q_EMIT rowCountChanged();
847 }
848
849=== modified file 'src/qml/Ubuntu/MediaScanner/AlbumModelBase.hh'
850--- src/qml/Ubuntu/MediaScanner/AlbumModelBase.hh 2014-05-06 09:09:49 +0000
851+++ src/qml/Ubuntu/MediaScanner/AlbumModelBase.hh 2014-05-29 09:17:39 +0000
852@@ -31,7 +31,7 @@
853 class AlbumModelBase : public QAbstractListModel {
854 Q_OBJECT
855 Q_ENUMS(Roles)
856- Q_PROPERTY(int rowCount READ rowCount) // NOTIFY modelReset
857+ Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
858 public:
859 enum Roles {
860 RoleTitle,
861@@ -44,6 +44,8 @@
862 QVariant data(const QModelIndex &index, int role) const override;
863
864 Q_INVOKABLE QVariant get(int row, Roles role) const;
865+Q_SIGNALS:
866+ void rowCountChanged();
867 protected:
868 QHash<int, QByteArray> roleNames() const override;
869 void updateResults(const std::vector<mediascanner::Album> &results);
870
871=== modified file 'src/qml/Ubuntu/MediaScanner/AlbumsModel.cc'
872--- src/qml/Ubuntu/MediaScanner/AlbumsModel.cc 2014-02-27 07:02:21 +0000
873+++ src/qml/Ubuntu/MediaScanner/AlbumsModel.cc 2014-05-29 09:17:39 +0000
874@@ -24,8 +24,6 @@
875 AlbumsModel::AlbumsModel(QObject *parent)
876 : AlbumModelBase(parent),
877 store(nullptr),
878- artist(""),
879- album_artist(""),
880 limit(-1) {
881 }
882
883@@ -40,25 +38,66 @@
884 }
885 }
886
887-QString AlbumsModel::getArtist() {
888- return artist;
889-}
890-
891-void AlbumsModel::setArtist(const QString artist) {
892- if (this->artist != artist) {
893- this->artist = artist;
894- update();
895- }
896-}
897-
898-QString AlbumsModel::getAlbumArtist() {
899- return album_artist;
900-}
901-
902-void AlbumsModel::setAlbumArtist(const QString album_artist) {
903- if (this->album_artist != album_artist) {
904- this->album_artist = album_artist;
905- update();
906+QVariant AlbumsModel::getArtist() {
907+ if (!filter.hasArtist())
908+ return QVariant();
909+ return QString::fromStdString(filter.getArtist());
910+}
911+
912+void AlbumsModel::setArtist(const QVariant artist) {
913+ if (artist.isNull()) {
914+ if (filter.hasArtist()) {
915+ filter.unsetArtist();
916+ update();
917+ }
918+ } else {
919+ const std::string std_artist = artist.value<QString>().toStdString();
920+ if (!filter.hasArtist() || filter.getArtist() != std_artist) {
921+ filter.setArtist(std_artist);
922+ update();
923+ }
924+ }
925+}
926+
927+QVariant AlbumsModel::getAlbumArtist() {
928+ if (!filter.hasAlbumArtist())
929+ return QVariant();
930+ return QString::fromStdString(filter.getAlbumArtist());
931+}
932+
933+void AlbumsModel::setAlbumArtist(const QVariant album_artist) {
934+ if (album_artist.isNull()) {
935+ if (filter.hasAlbumArtist()) {
936+ filter.unsetAlbumArtist();
937+ update();
938+ }
939+ } else {
940+ const std::string std_album_artist = album_artist.value<QString>().toStdString();
941+ if (!filter.hasAlbumArtist() || filter.getAlbumArtist() != std_album_artist) {
942+ filter.setAlbumArtist(std_album_artist);
943+ update();
944+ }
945+ }
946+}
947+
948+QVariant AlbumsModel::getGenre() {
949+ if (!filter.hasGenre())
950+ return QVariant();
951+ return QString::fromStdString(filter.getGenre());
952+}
953+
954+void AlbumsModel::setGenre(const QVariant genre) {
955+ if (genre.isNull()) {
956+ if (filter.hasGenre()) {
957+ filter.unsetGenre();
958+ update();
959+ }
960+ } else {
961+ const std::string std_genre = genre.value<QString>().toStdString();
962+ if (!filter.hasGenre() || filter.getGenre() != std_genre) {
963+ filter.setGenre(std_genre);
964+ update();
965+ }
966 }
967 }
968
969@@ -77,6 +116,6 @@
970 if (store == nullptr) {
971 updateResults(std::vector<mediascanner::Album>());
972 } else {
973- updateResults(store->store.listAlbums(artist.toStdString(), album_artist.toStdString(), limit));
974+ updateResults(store->store.listAlbums(filter, limit));
975 }
976 }
977
978=== modified file 'src/qml/Ubuntu/MediaScanner/AlbumsModel.hh'
979--- src/qml/Ubuntu/MediaScanner/AlbumsModel.hh 2014-02-27 07:02:21 +0000
980+++ src/qml/Ubuntu/MediaScanner/AlbumsModel.hh 2014-05-29 09:17:39 +0000
981@@ -22,6 +22,7 @@
982
983 #include <QString>
984
985+#include <mediascanner/Filter.hh>
986 #include "MediaStoreWrapper.hh"
987 #include "AlbumModelBase.hh"
988
989@@ -31,8 +32,9 @@
990 class AlbumsModel : public AlbumModelBase {
991 Q_OBJECT
992 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)
993- Q_PROPERTY(QString artist READ getArtist WRITE setArtist)
994- Q_PROPERTY(QString albumArtist READ getAlbumArtist WRITE setAlbumArtist)
995+ Q_PROPERTY(QVariant artist READ getArtist WRITE setArtist)
996+ Q_PROPERTY(QVariant albumArtist READ getAlbumArtist WRITE setAlbumArtist)
997+ Q_PROPERTY(QVariant genre READ getGenre WRITE setGenre)
998 Q_PROPERTY(int limit READ getLimit WRITE setLimit)
999 public:
1000 explicit AlbumsModel(QObject *parent=0);
1001@@ -40,17 +42,19 @@
1002 MediaStoreWrapper *getStore();
1003 void setStore(MediaStoreWrapper *store);
1004
1005- QString getArtist();
1006- void setArtist(const QString artist);
1007- QString getAlbumArtist();
1008- void setAlbumArtist(const QString album_artist);
1009+ QVariant getArtist();
1010+ void setArtist(const QVariant artist);
1011+ QVariant getAlbumArtist();
1012+ void setAlbumArtist(const QVariant album_artist);
1013+ QVariant getGenre();
1014+ void setGenre(const QVariant genre);
1015 int getLimit();
1016 void setLimit(int limit);
1017 private:
1018 void update();
1019
1020 MediaStoreWrapper *store;
1021- QString artist, album_artist;
1022+ Filter filter;
1023 int limit;
1024 };
1025
1026
1027=== modified file 'src/qml/Ubuntu/MediaScanner/ArtistsModel.cc'
1028--- src/qml/Ubuntu/MediaScanner/ArtistsModel.cc 2014-05-06 09:09:49 +0000
1029+++ src/qml/Ubuntu/MediaScanner/ArtistsModel.cc 2014-05-29 09:17:39 +0000
1030@@ -75,6 +75,27 @@
1031 }
1032 }
1033
1034+QVariant ArtistsModel::getGenre() {
1035+ if (!filter.hasGenre())
1036+ return QVariant();
1037+ return QString::fromStdString(filter.getGenre());
1038+}
1039+
1040+void ArtistsModel::setGenre(const QVariant genre) {
1041+ if (genre.isNull()) {
1042+ if (filter.hasGenre()) {
1043+ filter.unsetGenre();
1044+ update();
1045+ }
1046+ } else {
1047+ const std::string std_genre = genre.value<QString>().toStdString();
1048+ if (!filter.hasGenre() || filter.getGenre() != std_genre) {
1049+ filter.setGenre(std_genre);
1050+ update();
1051+ }
1052+ }
1053+}
1054+
1055 int ArtistsModel::getLimit() {
1056 return limit;
1057 }
1058@@ -91,8 +112,12 @@
1059 if (store == nullptr) {
1060 this->results.clear();
1061 } else {
1062- this->results = store->store.listArtists(album_artists, limit);
1063+ if (album_artists) {
1064+ this->results = store->store.listAlbumArtists(filter, limit);
1065+ } else {
1066+ this->results = store->store.listArtists(filter, limit);
1067+ }
1068 }
1069- this->results = results;
1070 endResetModel();
1071+ Q_EMIT rowCountChanged();
1072 }
1073
1074=== modified file 'src/qml/Ubuntu/MediaScanner/ArtistsModel.hh'
1075--- src/qml/Ubuntu/MediaScanner/ArtistsModel.hh 2014-05-06 09:09:49 +0000
1076+++ src/qml/Ubuntu/MediaScanner/ArtistsModel.hh 2014-05-29 09:17:39 +0000
1077@@ -24,6 +24,7 @@
1078 #include <QAbstractListModel>
1079 #include <QString>
1080
1081+#include <mediascanner/Filter.hh>
1082 #include "MediaStoreWrapper.hh"
1083
1084 namespace mediascanner {
1085@@ -34,8 +35,9 @@
1086 Q_ENUMS(Roles)
1087 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)
1088 Q_PROPERTY(bool albumArtists READ getAlbumArtists WRITE setAlbumArtists)
1089+ Q_PROPERTY(QVariant genre READ getGenre WRITE setGenre)
1090 Q_PROPERTY(int limit READ getLimit WRITE setLimit)
1091- Q_PROPERTY(int rowCount READ rowCount) // NOTIFY modelReset
1092+ Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
1093 public:
1094 enum Roles {
1095 RoleArtist,
1096@@ -46,6 +48,8 @@
1097 QVariant data(const QModelIndex &index, int role) const override;
1098
1099 Q_INVOKABLE QVariant get(int row, Roles role) const;
1100+Q_SIGNALS:
1101+ void rowCountChanged();
1102 protected:
1103 QHash<int, QByteArray> roleNames() const override;
1104
1105@@ -53,6 +57,8 @@
1106 void setStore(MediaStoreWrapper *store);
1107 bool getAlbumArtists();
1108 void setAlbumArtists(bool album_artists);
1109+ QVariant getGenre();
1110+ void setGenre(QVariant genre);
1111 int getLimit();
1112 void setLimit(int limit);
1113
1114@@ -62,6 +68,7 @@
1115 QHash<int, QByteArray> roles;
1116 std::vector<std::string> results;
1117 MediaStoreWrapper *store;
1118+ Filter filter;
1119 bool album_artists;
1120 int limit;
1121 };
1122
1123=== modified file 'src/qml/Ubuntu/MediaScanner/CMakeLists.txt'
1124--- src/qml/Ubuntu/MediaScanner/CMakeLists.txt 2014-05-29 09:17:39 +0000
1125+++ src/qml/Ubuntu/MediaScanner/CMakeLists.txt 2014-05-29 09:17:39 +0000
1126@@ -12,6 +12,7 @@
1127 AlbumModelBase.cc
1128 AlbumsModel.cc
1129 ArtistsModel.cc
1130+ GenresModel.cc
1131 SongsModel.cc
1132 SongsSearchModel.cc
1133 )
1134
1135=== added file 'src/qml/Ubuntu/MediaScanner/GenresModel.cc'
1136--- src/qml/Ubuntu/MediaScanner/GenresModel.cc 1970-01-01 00:00:00 +0000
1137+++ src/qml/Ubuntu/MediaScanner/GenresModel.cc 2014-05-29 09:17:39 +0000
1138@@ -0,0 +1,86 @@
1139+/*
1140+ * Copyright (C) 2014 Canonical, Ltd.
1141+ *
1142+ * Authors:
1143+ * James Henstridge <james.henstridge@canonical.com>
1144+ *
1145+ * This program is free software: you can redistribute it and/or modify
1146+ * it under the terms of the GNU Lesser General Public License version 3 as
1147+ * published by the Free Software Foundation.
1148+ *
1149+ * This program is distributed in the hope that it will be useful,
1150+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1151+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1152+ * GNU Lesser General Public License for more details.
1153+ *
1154+ * You should have received a copy of the GNU Lesser General Public License
1155+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1156+ */
1157+
1158+#include "GenresModel.hh"
1159+
1160+using namespace mediascanner::qml;
1161+
1162+GenresModel::GenresModel(QObject *parent)
1163+ : QAbstractListModel(parent),
1164+ store(nullptr),
1165+ limit(-1) {
1166+ roles[Roles::RoleGenre] = "genre";
1167+}
1168+
1169+int GenresModel::rowCount(const QModelIndex &) const {
1170+ return results.size();
1171+}
1172+
1173+QVariant GenresModel::data(const QModelIndex &index, int role) const {
1174+ if (index.row() < 0 || index.row() >= (ptrdiff_t)results.size()) {
1175+ return QVariant();
1176+ }
1177+ switch (role) {
1178+ case RoleGenre:
1179+ return QString::fromStdString(results[index.row()]);
1180+ default:
1181+ return QVariant();
1182+ }
1183+}
1184+
1185+QVariant GenresModel::get(int row, GenresModel::Roles role) const {
1186+ return data(index(row, 0), role);
1187+}
1188+
1189+QHash<int, QByteArray> GenresModel::roleNames() const {
1190+ return roles;
1191+}
1192+
1193+MediaStoreWrapper *GenresModel::getStore() {
1194+ return store;
1195+}
1196+
1197+void GenresModel::setStore(MediaStoreWrapper *store) {
1198+ if (this->store != store) {
1199+ this->store = store;
1200+ update();
1201+ }
1202+}
1203+
1204+int GenresModel::getLimit() {
1205+ return limit;
1206+}
1207+
1208+void GenresModel::setLimit(int limit) {
1209+ if (this->limit != limit) {
1210+ this->limit = limit;
1211+ update();
1212+ }
1213+}
1214+
1215+void GenresModel::update() {
1216+ beginResetModel();
1217+ if (store == nullptr) {
1218+ this->results.clear();
1219+ } else {
1220+ this->results = store->store.listGenres(limit);
1221+ }
1222+ endResetModel();
1223+ Q_EMIT rowCountChanged();
1224+}
1225
1226=== added file 'src/qml/Ubuntu/MediaScanner/GenresModel.hh'
1227--- src/qml/Ubuntu/MediaScanner/GenresModel.hh 1970-01-01 00:00:00 +0000
1228+++ src/qml/Ubuntu/MediaScanner/GenresModel.hh 2014-05-29 09:17:39 +0000
1229@@ -0,0 +1,71 @@
1230+/*
1231+ * Copyright (C) 2014 Canonical, Ltd.
1232+ *
1233+ * Authors:
1234+ * James Henstridge <james.henstridge@canonical.com>
1235+ *
1236+ * This program is free software: you can redistribute it and/or modify
1237+ * it under the terms of the GNU Lesser General Public License version 3 as
1238+ * published by the Free Software Foundation.
1239+ *
1240+ * This program is distributed in the hope that it will be useful,
1241+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1242+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1243+ * GNU Lesser General Public License for more details.
1244+ *
1245+ * You should have received a copy of the GNU Lesser General Public License
1246+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1247+ */
1248+
1249+#ifndef MEDIASCANNER_QML_GENRESMODEL_H
1250+#define MEDIASCANNER_QML_GENRESMODEL_H
1251+
1252+#include <string>
1253+#include <QAbstractListModel>
1254+#include <QString>
1255+
1256+#include <mediascanner/Filter.hh>
1257+#include "MediaStoreWrapper.hh"
1258+
1259+namespace mediascanner {
1260+namespace qml {
1261+
1262+class GenresModel : public QAbstractListModel {
1263+ Q_OBJECT
1264+ Q_ENUMS(Roles)
1265+ Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)
1266+ Q_PROPERTY(int limit READ getLimit WRITE setLimit)
1267+ Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
1268+public:
1269+ enum Roles {
1270+ RoleGenre,
1271+ };
1272+
1273+ explicit GenresModel(QObject *parent = 0);
1274+ int rowCount(const QModelIndex &parent=QModelIndex()) const override;
1275+ QVariant data(const QModelIndex &index, int role) const override;
1276+
1277+ Q_INVOKABLE QVariant get(int row, Roles role) const;
1278+Q_SIGNALS:
1279+ void rowCountChanged();
1280+protected:
1281+ QHash<int, QByteArray> roleNames() const override;
1282+
1283+ MediaStoreWrapper *getStore();
1284+ void setStore(MediaStoreWrapper *store);
1285+ int getLimit();
1286+ void setLimit(int limit);
1287+
1288+private:
1289+ void update();
1290+
1291+ QHash<int, QByteArray> roles;
1292+ std::vector<std::string> results;
1293+ MediaStoreWrapper *store;
1294+ int limit;
1295+};
1296+
1297+}
1298+}
1299+
1300+#endif
1301
1302=== modified file 'src/qml/Ubuntu/MediaScanner/MediaFileModelBase.cc'
1303--- src/qml/Ubuntu/MediaScanner/MediaFileModelBase.cc 2014-05-06 09:09:49 +0000
1304+++ src/qml/Ubuntu/MediaScanner/MediaFileModelBase.cc 2014-05-29 09:17:39 +0000
1305@@ -99,4 +99,5 @@
1306 beginResetModel();
1307 this->results = results;
1308 endResetModel();
1309+ Q_EMIT rowCountChanged();
1310 }
1311
1312=== modified file 'src/qml/Ubuntu/MediaScanner/MediaFileModelBase.hh'
1313--- src/qml/Ubuntu/MediaScanner/MediaFileModelBase.hh 2014-05-06 09:09:49 +0000
1314+++ src/qml/Ubuntu/MediaScanner/MediaFileModelBase.hh 2014-05-29 09:17:39 +0000
1315@@ -31,7 +31,7 @@
1316 class MediaFileModelBase : public QAbstractListModel {
1317 Q_OBJECT
1318 Q_ENUMS(Roles)
1319- Q_PROPERTY(int rowCount READ rowCount) // NOTIFY modelReset
1320+ Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
1321 public:
1322 enum Roles {
1323 RoleModelData,
1324@@ -56,6 +56,8 @@
1325 QVariant data(const QModelIndex &index, int role) const override;
1326
1327 Q_INVOKABLE QVariant get(int row, Roles role) const;
1328+Q_SIGNALS:
1329+ void rowCountChanged();
1330 protected:
1331 QHash<int, QByteArray> roleNames() const override;
1332 void updateResults(const std::vector<mediascanner::MediaFile> &results);
1333
1334=== modified file 'src/qml/Ubuntu/MediaScanner/SongsModel.cc'
1335--- src/qml/Ubuntu/MediaScanner/SongsModel.cc 2014-02-27 05:37:36 +0000
1336+++ src/qml/Ubuntu/MediaScanner/SongsModel.cc 2014-05-29 09:17:39 +0000
1337@@ -24,9 +24,6 @@
1338 SongsModel::SongsModel(QObject *parent)
1339 : MediaFileModelBase(parent),
1340 store(nullptr),
1341- artist(""),
1342- album(""),
1343- album_artist(""),
1344 limit(-1) {
1345 }
1346
1347@@ -41,36 +38,87 @@
1348 }
1349 }
1350
1351-QString SongsModel::getArtist() {
1352- return artist;
1353-}
1354-
1355-void SongsModel::setArtist(const QString artist) {
1356- if (this->artist != artist) {
1357- this->artist = artist;
1358- update();
1359- }
1360-}
1361-
1362-QString SongsModel::getAlbum() {
1363- return album;
1364-}
1365-
1366-void SongsModel::setAlbum(const QString album) {
1367- if (this->album != album) {
1368- this->album = album;
1369- update();
1370- }
1371-}
1372-
1373-QString SongsModel::getAlbumArtist() {
1374- return album_artist;
1375-}
1376-
1377-void SongsModel::setAlbumArtist(const QString album_artist) {
1378- if (this->album_artist != album_artist) {
1379- this->album_artist = album_artist;
1380- update();
1381+QVariant SongsModel::getArtist() {
1382+ if (!filter.hasArtist())
1383+ return QVariant();
1384+ return QString::fromStdString(filter.getArtist());
1385+}
1386+
1387+void SongsModel::setArtist(const QVariant artist) {
1388+ if (artist.isNull()) {
1389+ if (filter.hasArtist()) {
1390+ filter.unsetArtist();
1391+ update();
1392+ }
1393+ } else {
1394+ const std::string std_artist = artist.value<QString>().toStdString();
1395+ if (!filter.hasArtist() || filter.getArtist() != std_artist) {
1396+ filter.setArtist(std_artist);
1397+ update();
1398+ }
1399+ }
1400+}
1401+
1402+QVariant SongsModel::getAlbum() {
1403+ if (!filter.hasAlbum())
1404+ return QVariant();
1405+ return QString::fromStdString(filter.getAlbum());
1406+}
1407+
1408+void SongsModel::setAlbum(const QVariant album) {
1409+ if (album.isNull()) {
1410+ if (filter.hasAlbum()) {
1411+ filter.unsetAlbum();
1412+ update();
1413+ }
1414+ } else {
1415+ const std::string std_album = album.value<QString>().toStdString();
1416+ if (!filter.hasAlbum() || filter.getAlbum() != std_album) {
1417+ filter.setAlbum(std_album);
1418+ update();
1419+ }
1420+ }
1421+}
1422+
1423+QVariant SongsModel::getAlbumArtist() {
1424+ if (!filter.hasAlbumArtist())
1425+ return QVariant();
1426+ return QString::fromStdString(filter.getAlbumArtist());
1427+}
1428+
1429+void SongsModel::setAlbumArtist(const QVariant album_artist) {
1430+ if (album_artist.isNull()) {
1431+ if (filter.hasAlbumArtist()) {
1432+ filter.unsetAlbumArtist();
1433+ update();
1434+ }
1435+ } else {
1436+ const std::string std_album_artist = album_artist.value<QString>().toStdString();
1437+ if (!filter.hasAlbumArtist() || filter.getAlbumArtist() != std_album_artist) {
1438+ filter.setAlbumArtist(std_album_artist);
1439+ update();
1440+ }
1441+ }
1442+}
1443+
1444+QVariant SongsModel::getGenre() {
1445+ if (!filter.hasGenre())
1446+ return QVariant();
1447+ return QString::fromStdString(filter.getGenre());
1448+}
1449+
1450+void SongsModel::setGenre(const QVariant genre) {
1451+ if (genre.isNull()) {
1452+ if (filter.hasGenre()) {
1453+ filter.unsetGenre();
1454+ update();
1455+ }
1456+ } else {
1457+ const std::string std_genre = genre.value<QString>().toStdString();
1458+ if (!filter.hasGenre() || filter.getGenre() != std_genre) {
1459+ filter.setGenre(std_genre);
1460+ update();
1461+ }
1462 }
1463 }
1464
1465@@ -89,6 +137,6 @@
1466 if (store == nullptr) {
1467 updateResults(std::vector<mediascanner::MediaFile>());
1468 } else {
1469- updateResults(store->store.listSongs(artist.toStdString(), album.toStdString(), album_artist.toStdString(), limit));
1470+ updateResults(store->store.listSongs(filter, limit));
1471 }
1472 }
1473
1474=== modified file 'src/qml/Ubuntu/MediaScanner/SongsModel.hh'
1475--- src/qml/Ubuntu/MediaScanner/SongsModel.hh 2014-02-27 05:37:36 +0000
1476+++ src/qml/Ubuntu/MediaScanner/SongsModel.hh 2014-05-29 09:17:39 +0000
1477@@ -22,6 +22,7 @@
1478
1479 #include <QString>
1480
1481+#include <mediascanner/Filter.hh>
1482 #include "MediaStoreWrapper.hh"
1483 #include "MediaFileModelBase.hh"
1484
1485@@ -31,9 +32,10 @@
1486 class SongsModel : public MediaFileModelBase {
1487 Q_OBJECT
1488 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)
1489- Q_PROPERTY(QString artist READ getArtist WRITE setArtist)
1490- Q_PROPERTY(QString album READ getAlbum WRITE setAlbum)
1491- Q_PROPERTY(QString albumArtist READ getAlbumArtist WRITE setAlbumArtist)
1492+ Q_PROPERTY(QVariant artist READ getArtist WRITE setArtist)
1493+ Q_PROPERTY(QVariant album READ getAlbum WRITE setAlbum)
1494+ Q_PROPERTY(QVariant albumArtist READ getAlbumArtist WRITE setAlbumArtist)
1495+ Q_PROPERTY(QVariant genre READ getGenre WRITE setGenre)
1496 Q_PROPERTY(int limit READ getLimit WRITE setLimit)
1497 public:
1498 explicit SongsModel(QObject *parent=0);
1499@@ -41,19 +43,21 @@
1500 MediaStoreWrapper *getStore();
1501 void setStore(MediaStoreWrapper *store);
1502
1503- QString getArtist();
1504- void setArtist(const QString artist);
1505- QString getAlbum();
1506- void setAlbum(const QString album);
1507- QString getAlbumArtist();
1508- void setAlbumArtist(const QString album_artist);
1509+ QVariant getArtist();
1510+ void setArtist(const QVariant artist);
1511+ QVariant getAlbum();
1512+ void setAlbum(const QVariant album);
1513+ QVariant getAlbumArtist();
1514+ void setAlbumArtist(const QVariant album_artist);
1515+ QVariant getGenre();
1516+ void setGenre(const QVariant genre);
1517 int getLimit();
1518 void setLimit(int limit);
1519 private:
1520 void update();
1521
1522 MediaStoreWrapper *store;
1523- QString artist, album, album_artist;
1524+ Filter filter;
1525 int limit;
1526 };
1527
1528
1529=== modified file 'src/qml/Ubuntu/MediaScanner/plugin.cc'
1530--- src/qml/Ubuntu/MediaScanner/plugin.cc 2014-02-28 07:01:44 +0000
1531+++ src/qml/Ubuntu/MediaScanner/plugin.cc 2014-05-29 09:17:39 +0000
1532@@ -22,6 +22,7 @@
1533 #include "MediaStoreWrapper.hh"
1534 #include "AlbumsModel.hh"
1535 #include "ArtistsModel.hh"
1536+#include "GenresModel.hh"
1537 #include "SongsModel.hh"
1538 #include "SongsSearchModel.hh"
1539
1540@@ -33,6 +34,7 @@
1541 "Use a MediaStore to retrieve MediaFiles");
1542 qmlRegisterType<AlbumsModel>(uri, 0, 1, "AlbumsModel");
1543 qmlRegisterType<ArtistsModel>(uri, 0, 1, "ArtistsModel");
1544+ qmlRegisterType<GenresModel>(uri, 0, 1, "GenresModel");
1545 qmlRegisterType<SongsModel>(uri, 0, 1, "SongsModel");
1546 qmlRegisterType<SongsSearchModel>(uri, 0, 1, "SongsSearchModel");
1547 }
1548
1549=== modified file 'src/qml/Ubuntu/MediaScanner/plugin.qmltypes'
1550--- src/qml/Ubuntu/MediaScanner/plugin.qmltypes 2014-05-08 07:17:11 +0000
1551+++ src/qml/Ubuntu/MediaScanner/plugin.qmltypes 2014-05-29 09:17:39 +0000
1552@@ -32,8 +32,9 @@
1553 exports: ["Ubuntu.MediaScanner/AlbumsModel 0.1"]
1554 exportMetaObjectRevisions: [0]
1555 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }
1556- Property { name: "artist"; type: "string" }
1557- Property { name: "albumArtist"; type: "string" }
1558+ Property { name: "artist"; type: "QVariant" }
1559+ Property { name: "albumArtist"; type: "QVariant" }
1560+ Property { name: "genre"; type: "QVariant" }
1561 Property { name: "limit"; type: "int" }
1562 }
1563 Component {
1564@@ -49,6 +50,28 @@
1565 }
1566 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }
1567 Property { name: "albumArtists"; type: "bool" }
1568+ Property { name: "genre"; type: "QVariant" }
1569+ Property { name: "limit"; type: "int" }
1570+ Property { name: "rowCount"; type: "int"; isReadonly: true }
1571+ Method {
1572+ name: "get"
1573+ type: "QVariant"
1574+ Parameter { name: "row"; type: "int" }
1575+ Parameter { name: "role"; type: "Roles" }
1576+ }
1577+ }
1578+ Component {
1579+ name: "mediascanner::qml::GenresModel"
1580+ prototype: "QAbstractListModel"
1581+ exports: ["Ubuntu.MediaScanner/GenresModel 0.1"]
1582+ exportMetaObjectRevisions: [0]
1583+ Enum {
1584+ name: "Roles"
1585+ values: {
1586+ "RoleGenre": 0
1587+ }
1588+ }
1589+ Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }
1590 Property { name: "limit"; type: "int" }
1591 Property { name: "rowCount"; type: "int"; isReadonly: true }
1592 Method {
1593@@ -140,9 +163,10 @@
1594 exports: ["Ubuntu.MediaScanner/SongsModel 0.1"]
1595 exportMetaObjectRevisions: [0]
1596 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }
1597- Property { name: "artist"; type: "string" }
1598- Property { name: "album"; type: "string" }
1599- Property { name: "albumArtist"; type: "string" }
1600+ Property { name: "artist"; type: "QVariant" }
1601+ Property { name: "album"; type: "QVariant" }
1602+ Property { name: "albumArtist"; type: "QVariant" }
1603+ Property { name: "genre"; type: "QVariant" }
1604 Property { name: "limit"; type: "int" }
1605 }
1606 Component {
1607
1608=== modified file 'src/qml/Ubuntu/MediaScanner/qmldir'
1609--- src/qml/Ubuntu/MediaScanner/qmldir 2014-01-02 07:48:47 +0000
1610+++ src/qml/Ubuntu/MediaScanner/qmldir 2014-05-29 09:17:39 +0000
1611@@ -1,2 +1,3 @@
1612 module Ubuntu.MediaScanner
1613 plugin mediascanner-qml
1614+typeinfo plugin.qmltypes
1615
1616=== added file 'test/qml/tst_albumsmodel.qml'
1617--- test/qml/tst_albumsmodel.qml 1970-01-01 00:00:00 +0000
1618+++ test/qml/tst_albumsmodel.qml 2014-05-29 09:17:39 +0000
1619@@ -0,0 +1,91 @@
1620+import QtQuick 2.0
1621+import QtTest 1.0
1622+import Ubuntu.MediaScanner 0.1
1623+
1624+Item {
1625+ id: root
1626+
1627+ MediaStore {
1628+ id: store
1629+ }
1630+
1631+ AlbumsModel {
1632+ id: model
1633+ store: store
1634+ }
1635+
1636+ TestCase {
1637+ name: "AlbumsModelTests"
1638+
1639+ function cleanup() {
1640+ model.artist = undefined;
1641+ model.albumArtist = undefined;
1642+ model.genre = undefined;
1643+ model.limit = -1;
1644+ }
1645+
1646+ function test_initial_state() {
1647+ compare(model.artist, undefined);
1648+ compare(model.albumArtist, undefined);
1649+ compare(model.genre, undefined);
1650+ compare(model.limit, -1);
1651+
1652+ compare(model.rowCount, 4);
1653+ compare(model.get(0, AlbumsModel.RoleTitle), "Ivy and the Big Apples");
1654+ compare(model.get(0, AlbumsModel.RoleArtist), "Spiderbait");
1655+
1656+ compare(model.get(1, AlbumsModel.RoleTitle), "Spiderbait");
1657+ compare(model.get(1, AlbumsModel.RoleArtist), "Spiderbait");
1658+
1659+ compare(model.get(2, AlbumsModel.RoleTitle), "April Uprising");
1660+ compare(model.get(2, AlbumsModel.RoleArtist), "The John Butler Trio");
1661+
1662+ compare(model.get(3, AlbumsModel.RoleTitle), "Sunrise Over Sea");
1663+ compare(model.get(3, AlbumsModel.RoleArtist), "The John Butler Trio");
1664+ }
1665+
1666+ function test_limit() {
1667+ model.limit = 2;
1668+ compare(model.rowCount, 2);
1669+
1670+ model.limit = 42;
1671+ compare(model.rowCount, 4);
1672+
1673+ model.limit = -1;
1674+ compare(model.rowCount, 4);
1675+ }
1676+
1677+ function test_artist() {
1678+ model.artist = "The John Butler Trio";
1679+ compare(model.rowCount, 2);
1680+
1681+ compare(model.get(0, AlbumsModel.RoleTitle), "April Uprising");
1682+ compare(model.get(0, AlbumsModel.RoleArtist), "The John Butler Trio");
1683+
1684+ model.artist = "unknown";
1685+ compare(model.rowCount, 0);
1686+ }
1687+
1688+ function test_album_artist() {
1689+ model.albumArtist = "The John Butler Trio";
1690+ compare(model.rowCount, 2);
1691+
1692+ compare(model.get(0, AlbumsModel.RoleTitle), "April Uprising");
1693+ compare(model.get(0, AlbumsModel.RoleArtist), "The John Butler Trio");
1694+
1695+ model.albumArtist = "unknown";
1696+ compare(model.rowCount, 0);
1697+ }
1698+
1699+ function test_genre() {
1700+ model.genre = "rock";
1701+ compare(model.rowCount, 2);
1702+ compare(model.get(0, AlbumsModel.RoleTitle), "Ivy and the Big Apples");
1703+ compare(model.get(1, AlbumsModel.RoleTitle), "Spiderbait");
1704+
1705+ model.genre = "unknown";
1706+ compare(model.rowCount, 0);
1707+ }
1708+
1709+ }
1710+}
1711
1712=== added file 'test/qml/tst_artistsmodel.qml'
1713--- test/qml/tst_artistsmodel.qml 1970-01-01 00:00:00 +0000
1714+++ test/qml/tst_artistsmodel.qml 2014-05-29 09:17:39 +0000
1715@@ -0,0 +1,68 @@
1716+import QtQuick 2.0
1717+import QtTest 1.0
1718+import Ubuntu.MediaScanner 0.1
1719+
1720+Item {
1721+ id: root
1722+
1723+ MediaStore {
1724+ id: store
1725+ }
1726+
1727+ ArtistsModel {
1728+ id: model
1729+ store: store
1730+ }
1731+
1732+ TestCase {
1733+ name: "ArtistsModelTests"
1734+
1735+ function cleanup() {
1736+ model.albumArtists = false;
1737+ model.genre = undefined;
1738+ model.limit = -1;
1739+ }
1740+
1741+ function test_initial_state() {
1742+ compare(model.albumArtists, false);
1743+ compare(model.limit, -1);
1744+
1745+ compare(model.rowCount, 2);
1746+ compare(model.get(0, ArtistsModel.RoleArtist), "Spiderbait");
1747+ compare(model.get(1, ArtistsModel.RoleArtist), "The John Butler Trio");
1748+ }
1749+
1750+ function test_limit() {
1751+ model.limit = 1;
1752+ compare(model.rowCount, 1);
1753+
1754+ model.limit = 42;
1755+ compare(model.rowCount, 2);
1756+
1757+ model.limit = -1;
1758+ compare(model.rowCount, 2);
1759+ }
1760+
1761+ function test_album_artists() {
1762+ model.albumArtists = true;
1763+ compare(model.rowCount, 2);
1764+
1765+ compare(model.get(0, ArtistsModel.RoleArtist), "Spiderbait");
1766+ compare(model.get(1, ArtistsModel.RoleArtist), "The John Butler Trio");
1767+ }
1768+
1769+ function test_genre() {
1770+ model.genre = "rock";
1771+ compare(model.rowCount, 1);
1772+ compare(model.get(0, ArtistsModel.RoleArtist), "Spiderbait");
1773+
1774+ model.genre = "roots";
1775+ compare(model.rowCount, 1);
1776+ compare(model.get(0, ArtistsModel.RoleArtist), "The John Butler Trio");
1777+
1778+ model.genre = "unknown";
1779+ compare(model.rowCount, 0);
1780+ }
1781+
1782+ }
1783+}
1784
1785=== added file 'test/qml/tst_genresmodel.qml'
1786--- test/qml/tst_genresmodel.qml 1970-01-01 00:00:00 +0000
1787+++ test/qml/tst_genresmodel.qml 2014-05-29 09:17:39 +0000
1788@@ -0,0 +1,44 @@
1789+import QtQuick 2.0
1790+import QtTest 1.0
1791+import Ubuntu.MediaScanner 0.1
1792+
1793+Item {
1794+ id: root
1795+
1796+ MediaStore {
1797+ id: store
1798+ }
1799+
1800+ GenresModel {
1801+ id: model
1802+ store: store
1803+ }
1804+
1805+ TestCase {
1806+ name: "GenresModelTests"
1807+
1808+ function cleanup() {
1809+ model.limit = -1;
1810+ }
1811+
1812+ function test_initial_state() {
1813+ compare(model.limit, -1);
1814+
1815+ compare(model.rowCount, 2);
1816+ compare(model.get(0, ArtistsModel.RoleGenre), "rock");
1817+ compare(model.get(1, ArtistsModel.RoleGenre), "roots");
1818+ }
1819+
1820+ function test_limit() {
1821+ model.limit = 1;
1822+ compare(model.rowCount, 1);
1823+
1824+ model.limit = 42;
1825+ compare(model.rowCount, 2);
1826+
1827+ model.limit = -1;
1828+ compare(model.rowCount, 2);
1829+ }
1830+
1831+ }
1832+}
1833
1834=== added file 'test/qml/tst_songsmodel.qml'
1835--- test/qml/tst_songsmodel.qml 1970-01-01 00:00:00 +0000
1836+++ test/qml/tst_songsmodel.qml 2014-05-29 09:17:39 +0000
1837@@ -0,0 +1,104 @@
1838+import QtQuick 2.0
1839+import QtTest 1.0
1840+import Ubuntu.MediaScanner 0.1
1841+
1842+Item {
1843+ id: root
1844+
1845+ MediaStore {
1846+ id: store
1847+ }
1848+
1849+ SongsModel {
1850+ id: model
1851+ store: store
1852+ }
1853+
1854+ TestCase {
1855+ name: "SongsModelTests"
1856+
1857+ function cleanup() {
1858+ model.artist = undefined;
1859+ model.albumArtist = undefined;
1860+ model.album = undefined;
1861+ model.genre = undefined;
1862+ model.limit = -1;
1863+ }
1864+
1865+ function test_initial_state() {
1866+ compare(model.artist, undefined);
1867+ compare(model.albumArtist, undefined);
1868+ compare(model.album, undefined);
1869+ compare(model.limit, -1);
1870+
1871+ compare(model.rowCount, 7);
1872+ compare(model.get(0, SongsModel.RoleTitle), "Buy Me a Pony")
1873+ compare(model.get(0, SongsModel.RoleAlbum), "Ivy and the Big Apples");
1874+ compare(model.get(0, SongsModel.RoleAuthor), "Spiderbait");
1875+
1876+ compare(model.get(1, SongsModel.RoleTitle), "Straight Through The Sun");
1877+ compare(model.get(2, SongsModel.RoleTitle), "It's Beautiful");
1878+ compare(model.get(3, SongsModel.RoleTitle), "Revolution");
1879+ compare(model.get(4, SongsModel.RoleTitle), "One Way Road");
1880+ compare(model.get(5, SongsModel.RoleTitle), "Peaches & Cream");
1881+ compare(model.get(6, SongsModel.RoleTitle), "Zebra");
1882+ }
1883+
1884+ function test_limit() {
1885+ model.limit = 2;
1886+ compare(model.rowCount, 2);
1887+
1888+ model.limit = 42;
1889+ compare(model.rowCount, 7);
1890+
1891+ model.limit = -1;
1892+ compare(model.rowCount, 7);
1893+ }
1894+
1895+ function test_artist() {
1896+ model.artist = "The John Butler Trio";
1897+ compare(model.rowCount, 4);
1898+
1899+ compare(model.get(0, SongsModel.RoleTitle), "Revolution");
1900+ compare(model.get(0, SongsModel.RoleAuthor), "The John Butler Trio");
1901+
1902+ model.artist = "unknown";
1903+ compare(model.rowCount, 0);
1904+ }
1905+
1906+ function test_album_artist() {
1907+ model.albumArtist = "The John Butler Trio";
1908+ compare(model.rowCount, 4);
1909+
1910+ compare(model.get(0, SongsModel.RoleTitle), "Revolution");
1911+ compare(model.get(0, SongsModel.RoleAuthor), "The John Butler Trio");
1912+
1913+ model.albumArtist = "unknown";
1914+ compare(model.rowCount, 0);
1915+ }
1916+
1917+ function test_album() {
1918+ model.album = "Sunrise Over Sea";
1919+ compare(model.rowCount, 2);
1920+
1921+ compare(model.get(0, SongsModel.RoleTitle), "Peaches & Cream");
1922+ compare(model.get(0, SongsModel.RoleAuthor), "The John Butler Trio");
1923+
1924+ model.albumArtist = "unknown";
1925+ compare(model.rowCount, 0);
1926+ }
1927+
1928+ function test_genre() {
1929+ model.genre = "rock";
1930+ compare(model.rowCount, 3);
1931+
1932+ compare(model.get(0, SongsModel.RoleTitle), "Buy Me a Pony");
1933+ compare(model.get(1, SongsModel.RoleTitle), "Straight Through The Sun");
1934+ compare(model.get(2, SongsModel.RoleTitle), "It's Beautiful");
1935+
1936+ model.albumArtist = "unknown";
1937+ compare(model.rowCount, 0);
1938+ }
1939+
1940+ }
1941+}
1942
1943=== modified file 'test/test_dbus.cc'
1944--- test/test_dbus.cc 2014-05-29 09:17:39 +0000
1945+++ test/test_dbus.cc 2014-05-29 09:17:39 +0000
1946@@ -6,18 +6,24 @@
1947 #include <mediascanner/Album.hh>
1948 #include <mediascanner/MediaFile.hh>
1949 #include <mediascanner/MediaFileBuilder.hh>
1950+#include <mediascanner/Filter.hh>
1951 #include <ms-dbus/dbus-codec.hh>
1952
1953 class MediaStoreDBusTests : public ::testing::Test {
1954+protected:
1955+ virtual void SetUp() override {
1956+ ::testing::Test::SetUp();
1957+ message = core::dbus::Message::make_method_call(
1958+ "org.example.Name",
1959+ core::dbus::types::ObjectPath("/org/example/Path"),
1960+ "org.example.Interface",
1961+ "Method");
1962+ }
1963+
1964+ core::dbus::Message::Ptr message;
1965 };
1966
1967 TEST_F(MediaStoreDBusTests, mediafile_codec) {
1968- auto message = core::dbus::Message::make_method_call(
1969- "org.example.Name",
1970- core::dbus::types::ObjectPath("/org/example/Path"),
1971- "org.example.Interface",
1972- "Method");
1973-
1974 mediascanner::MediaFile media = mediascanner::MediaFileBuilder("a")
1975 .setContentType("type")
1976 .setETag("etag")
1977@@ -42,12 +48,6 @@
1978 }
1979
1980 TEST_F(MediaStoreDBusTests, album_codec) {
1981- auto message = core::dbus::Message::make_method_call(
1982- "org.example.Name",
1983- core::dbus::types::ObjectPath("/org/example/Path"),
1984- "org.example.Interface",
1985- "Method");
1986-
1987 mediascanner::Album album("title", "artist");
1988 message->writer() << album;
1989
1990@@ -61,6 +61,33 @@
1991 EXPECT_EQ(album, album2);
1992 }
1993
1994+TEST_F(MediaStoreDBusTests, filter_codec) {
1995+ mediascanner::Filter filter;
1996+ filter.setArtist("Artist1");
1997+ filter.setAlbum("Album1");
1998+ filter.setAlbumArtist("AlbumArtist1");
1999+ filter.setGenre("Genre");
2000+ message->writer() << filter;
2001+
2002+ EXPECT_EQ("a{ss}", message->signature());
2003+ EXPECT_EQ(core::dbus::helper::TypeMapper<mediascanner::Filter>::signature(), message->signature());
2004+
2005+ mediascanner::Filter other;
2006+ message->reader() >> other;
2007+ EXPECT_EQ(filter, other);
2008+}
2009+
2010+TEST_F(MediaStoreDBusTests, filter_codec_empty) {
2011+ mediascanner::Filter empty;
2012+ message->writer() << empty;
2013+
2014+ EXPECT_EQ("a{ss}", message->signature());
2015+
2016+ mediascanner::Filter other;
2017+ message->reader() >> other;
2018+ EXPECT_EQ(empty, other);
2019+}
2020+
2021 int main(int argc, char **argv) {
2022 ::testing::InitGoogleTest(&argc, argv);
2023 return RUN_ALL_TESTS();
2024
2025=== modified file 'test/test_mediastore.cc'
2026--- test/test_mediastore.cc 2014-05-29 09:17:39 +0000
2027+++ test/test_mediastore.cc 2014-05-29 09:17:39 +0000
2028@@ -20,6 +20,7 @@
2029 #include <mediascanner/MediaFile.hh>
2030 #include <mediascanner/MediaFileBuilder.hh>
2031 #include <mediascanner/Album.hh>
2032+#include <mediascanner/Filter.hh>
2033 #include <mediascanner/MediaStore.hh>
2034 #include <mediascanner/internal/utils.hh>
2035
2036@@ -617,34 +618,56 @@
2037 store.insert(audio5);
2038 store.insert(audio6);
2039
2040- vector<MediaFile> tracks = store.listSongs();
2041+ Filter filter;
2042+ vector<MediaFile> tracks = store.listSongs(filter);
2043 ASSERT_EQ(6, tracks.size());
2044 EXPECT_EQ("TitleOne", tracks[0].getTitle());
2045
2046 // Apply a limit
2047- tracks = store.listSongs("", "", "", 4);
2048+ tracks = store.listSongs(filter, 4);
2049 EXPECT_EQ(4, tracks.size());
2050
2051 // List songs by artist
2052- tracks = store.listSongs("ArtistOne");
2053+ filter.setArtist("ArtistOne");
2054+ tracks = store.listSongs(filter);
2055 EXPECT_EQ(4, tracks.size());
2056
2057 // List songs by album
2058- tracks = store.listSongs("", "AlbumOne");
2059+ filter.clear();
2060+ filter.setAlbum("AlbumOne");
2061+ tracks = store.listSongs(filter);
2062 EXPECT_EQ(2, tracks.size());
2063
2064 // List songs by album artist
2065- tracks = store.listSongs("", "", "Various Artists");
2066+ filter.clear();
2067+ filter.setAlbumArtist("Various Artists");
2068+ tracks = store.listSongs(filter);
2069 EXPECT_EQ(2, tracks.size());
2070
2071 // Combinations
2072- tracks = store.listSongs("ArtistOne", "AlbumOne", "");
2073- EXPECT_EQ(2, tracks.size());
2074- tracks = store.listSongs("", "AlbumOne", "ArtistOne");
2075- EXPECT_EQ(2, tracks.size());
2076- tracks = store.listSongs("ArtistOne", "AlbumOne", "ArtistOne");
2077- EXPECT_EQ(2, tracks.size());
2078- tracks = store.listSongs("ArtistOne", "", "ArtistOne");
2079+ filter.clear();
2080+ filter.setArtist("ArtistOne");
2081+ filter.setAlbum("AlbumOne");
2082+ tracks = store.listSongs(filter);
2083+ EXPECT_EQ(2, tracks.size());
2084+
2085+ filter.clear();
2086+ filter.setAlbum("AlbumOne");
2087+ filter.setAlbumArtist("ArtistOne");
2088+ tracks = store.listSongs(filter);
2089+ EXPECT_EQ(2, tracks.size());
2090+
2091+ filter.clear();
2092+ filter.setArtist("ArtistOne");
2093+ filter.setAlbum("AlbumOne");
2094+ filter.setAlbumArtist("ArtistOne");
2095+ tracks = store.listSongs(filter);
2096+ EXPECT_EQ(2, tracks.size());
2097+
2098+ filter.clear();
2099+ filter.setArtist("ArtistOne");
2100+ filter.setAlbumArtist("ArtistOne");
2101+ tracks = store.listSongs(filter);
2102 EXPECT_EQ(3, tracks.size());
2103 }
2104
2105@@ -687,24 +710,31 @@
2106 store.insert(audio4);
2107 store.insert(audio5);
2108
2109- vector<Album> albums = store.listAlbums();
2110+ Filter filter;
2111+ vector<Album> albums = store.listAlbums(filter);
2112 ASSERT_EQ(4, albums.size());
2113 EXPECT_EQ("AlbumOne", albums[0].getTitle());
2114
2115 // test limit
2116- albums = store.listAlbums("", "", 2);
2117+ albums = store.listAlbums(filter, 2);
2118 EXPECT_EQ(2, albums.size());
2119
2120 // Songs by artist
2121- albums = store.listAlbums("ArtistOne");
2122+ filter.setArtist("ArtistOne");
2123+ albums = store.listAlbums(filter);
2124 EXPECT_EQ(3, albums.size());
2125
2126 // Songs by album artist
2127- albums = store.listAlbums("", "ArtistOne");
2128+ filter.clear();
2129+ filter.setAlbumArtist("ArtistOne");
2130+ albums = store.listAlbums(filter);
2131 EXPECT_EQ(2, albums.size());
2132
2133 // Combination
2134- albums = store.listAlbums("ArtistOne", "Various Artists");
2135+ filter.clear();
2136+ filter.setArtist("ArtistOne");
2137+ filter.setAlbumArtist("Various Artists");
2138+ albums = store.listAlbums(filter);
2139 EXPECT_EQ(1, albums.size());
2140 }
2141
2142@@ -747,17 +777,18 @@
2143 store.insert(audio4);
2144 store.insert(audio5);
2145
2146- vector<string> artists = store.listArtists(false);
2147+ Filter filter;
2148+ vector<string> artists = store.listArtists(filter);
2149 ASSERT_EQ(2, artists.size());
2150 EXPECT_EQ("ArtistOne", artists[0]);
2151 EXPECT_EQ("ArtistTwo", artists[1]);
2152
2153 // Test limit clause
2154- artists = store.listArtists(false, 1);
2155+ artists = store.listArtists(filter, 1);
2156 EXPECT_EQ(1, artists.size());
2157
2158 // List "album artists"
2159- artists = store.listArtists(true);
2160+ artists = store.listAlbumArtists(filter);
2161 ASSERT_EQ(3, artists.size());
2162 EXPECT_EQ("ArtistOne", artists[0]);
2163 EXPECT_EQ("ArtistTwo", artists[1]);

Subscribers

People subscribed via source and target branches