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
=== modified file 'src/mediascanner/CMakeLists.txt'
--- src/mediascanner/CMakeLists.txt 2014-05-29 09:17:39 +0000
+++ src/mediascanner/CMakeLists.txt 2014-05-29 09:17:39 +0000
@@ -2,6 +2,7 @@
2 MediaFile.cc2 MediaFile.cc
3 MediaFileBuilder.cc3 MediaFileBuilder.cc
4 MediaFilePrivate.cc4 MediaFilePrivate.cc
5 Filter.cc
5 Album.cc6 Album.cc
6 MediaStore.cc7 MediaStore.cc
7 utils.cc8 utils.cc
89
=== added file 'src/mediascanner/Filter.cc'
--- src/mediascanner/Filter.cc 1970-01-01 00:00:00 +0000
+++ src/mediascanner/Filter.cc 2014-05-29 09:17:39 +0000
@@ -0,0 +1,154 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * Authors:
5 * James Henstridge <james.henstridge@canonical.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License version 3 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "Filter.hh"
21
22using std::string;
23
24namespace mediascanner {
25
26struct Filter::Private {
27 string artist;
28 string album;
29 string album_artist;
30 string genre;
31
32 bool have_artist;
33 bool have_album;
34 bool have_album_artist;
35 bool have_genre;
36
37 Private() :
38 have_artist(false), have_album(false), have_album_artist(false),
39 have_genre(false) {
40 }
41};
42
43Filter::Filter() : p(new Private) {
44}
45
46Filter::Filter(const Filter &other) : Filter() {
47 *p = *other.p;
48}
49
50Filter::~Filter() {
51 delete p;
52}
53
54bool Filter::operator==(const Filter &other) const {
55 return
56 p->have_artist == other.p->have_artist &&
57 p->have_album == other.p->have_album &&
58 p->have_album_artist == other.p->have_album_artist &&
59 p->have_genre == other.p->have_genre &&
60 p->artist == other.p->artist &&
61 p->album == other.p->album &&
62 p->album_artist == other.p->album_artist &&
63 p->genre == other.p->genre;
64}
65
66bool Filter::operator!=(const Filter &other) const {
67 return !(*this == other);
68}
69
70Filter &Filter::operator=(const Filter &other) {
71 *p = *other.p;
72 return *this;
73}
74
75void Filter::clear() {
76 unsetArtist();
77 unsetAlbum();
78 unsetAlbumArtist();
79 unsetGenre();
80}
81
82void Filter::setArtist(const std::string &artist) {
83 p->artist = artist;
84 p->have_artist = true;
85}
86
87void Filter::unsetArtist() {
88 p->artist = "";
89 p->have_artist = false;
90}
91
92bool Filter::hasArtist() const {
93 return p->have_artist;
94}
95
96const std::string &Filter::getArtist() const {
97 return p->artist;
98}
99
100void Filter::setAlbum(const std::string &album) {
101 p->album = album;
102 p->have_album = true;
103}
104
105void Filter::unsetAlbum() {
106 p->album = "";
107 p->have_album = false;
108}
109
110bool Filter::hasAlbum() const {
111 return p->have_album;
112}
113
114const std::string &Filter::getAlbum() const {
115 return p->album;
116}
117
118void Filter::setAlbumArtist(const std::string &album_artist) {
119 p->album_artist = album_artist;
120 p->have_album_artist = true;
121}
122
123void Filter::unsetAlbumArtist() {
124 p->album_artist = "";
125 p->have_album_artist = false;
126}
127
128bool Filter::hasAlbumArtist() const {
129 return p->have_album_artist;
130}
131
132const std::string &Filter::getAlbumArtist() const {
133 return p->album_artist;
134}
135
136void Filter::setGenre(const std::string &genre) {
137 p->genre = genre;
138 p->have_genre = true;
139}
140
141void Filter::unsetGenre() {
142 p->genre = "";
143 p->have_genre = false;
144}
145
146bool Filter::hasGenre() const {
147 return p->have_genre;
148}
149
150const std::string &Filter::getGenre() const {
151 return p->genre;
152}
153
154}
0155
=== added file 'src/mediascanner/Filter.hh'
--- src/mediascanner/Filter.hh 1970-01-01 00:00:00 +0000
+++ src/mediascanner/Filter.hh 2014-05-29 09:17:39 +0000
@@ -0,0 +1,66 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * Authors:
5 * James Henstridge <james.henstridge@canonical.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License version 3 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef MEDIAFILTER_H_
21#define MEDIAFILTER_H_
22
23#include <string>
24
25namespace mediascanner {
26
27class Filter final {
28public:
29 Filter();
30 Filter(const Filter &other);
31 ~Filter();
32
33 Filter &operator=(const Filter &other);
34 bool operator==(const Filter &other) const;
35 bool operator!=(const Filter &other) const;
36
37 void clear();
38
39 void setArtist(const std::string &artist);
40 void unsetArtist();
41 bool hasArtist() const;
42 const std::string &getArtist() const;
43
44 void setAlbum(const std::string &album);
45 void unsetAlbum();
46 bool hasAlbum() const;
47 const std::string &getAlbum() const;
48
49 void setAlbumArtist(const std::string &album_artist);
50 void unsetAlbumArtist();
51 bool hasAlbumArtist() const;
52 const std::string &getAlbumArtist() const;
53
54 void setGenre(const std::string &genre);
55 void unsetGenre();
56 bool hasGenre() const;
57 const std::string &getGenre() const;
58
59private:
60 struct Private;
61 Private *p;
62};
63
64}
65
66#endif
067
=== modified file 'src/mediascanner/MediaStore.cc'
--- src/mediascanner/MediaStore.cc 2014-05-29 09:17:39 +0000
+++ src/mediascanner/MediaStore.cc 2014-05-29 09:17:39 +0000
@@ -33,6 +33,7 @@
33#include "MediaFile.hh"33#include "MediaFile.hh"
34#include "MediaFileBuilder.hh"34#include "MediaFileBuilder.hh"
35#include "Album.hh"35#include "Album.hh"
36#include "Filter.hh"
36#include "internal/sqliteutils.hh"37#include "internal/sqliteutils.hh"
37#include "internal/utils.hh"38#include "internal/utils.hh"
3839
@@ -448,21 +449,24 @@
448 }449 }
449}450}
450451
451std::vector<MediaFile> MediaStore::listSongs(const std::string& artist, const std::string& album, const std::string& album_artist, int limit) const {452std::vector<MediaFile> MediaStore::listSongs(const Filter &filter, int limit) const {
452 std::string qs(R"(453 std::string qs(R"(
453SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, type454SELECT filename, content_type, etag, title, date, artist, album, album_artist, genre, disc_number, track_number, duration, type
454 FROM media455 FROM media
455 WHERE type = ?456 WHERE type = ?
456)");457)");
457 if (!artist.empty()) {458 if (filter.hasArtist()) {
458 qs += " AND artist = ?";459 qs += " AND artist = ?";
459 }460 }
460 if (!album.empty()) {461 if (filter.hasAlbum()) {
461 qs += " AND album = ?";462 qs += " AND album = ?";
462 }463 }
463 if (!album_artist.empty()) {464 if (filter.hasAlbumArtist()) {
464 qs += " AND album_artist = ?";465 qs += " AND album_artist = ?";
465 }466 }
467 if (filter.hasGenre()) {
468 qs += " AND genre = ?";
469 }
466 qs += R"(470 qs += R"(
467ORDER BY album_artist, album, disc_number, track_number, title471ORDER BY album_artist, album, disc_number, track_number, title
468LIMIT ?472LIMIT ?
@@ -470,31 +474,37 @@
470 Statement query(p->db, qs.c_str());474 Statement query(p->db, qs.c_str());
471 int param = 1;475 int param = 1;
472 query.bind(param++, (int)AudioMedia);476 query.bind(param++, (int)AudioMedia);
473 if (!artist.empty()) {477 if (filter.hasArtist()) {
474 query.bind(param++, artist);478 query.bind(param++, filter.getArtist());
475 }479 }
476 if (!album.empty()) {480 if (filter.hasAlbum()) {
477 query.bind(param++, album);481 query.bind(param++, filter.getAlbum());
478 }482 }
479 if (!album_artist.empty()) {483 if (filter.hasAlbumArtist()) {
480 query.bind(param++, album_artist);484 query.bind(param++, filter.getAlbumArtist());
485 }
486 if (filter.hasGenre()) {
487 query.bind(param++, filter.getGenre());
481 }488 }
482 query.bind(param++, limit);489 query.bind(param++, limit);
483490
484 return collect_media(query);491 return collect_media(query);
485}492}
486493
487std::vector<Album> MediaStore::listAlbums(const std::string& artist, const std::string& album_artist, int limit) const {494std::vector<Album> MediaStore::listAlbums(const Filter &filter, int limit) const {
488 std::string qs(R"(495 std::string qs(R"(
489SELECT album, album_artist FROM media496SELECT album, album_artist FROM media
490 WHERE type = ?497 WHERE type = ?
491)");498)");
492 if (!artist.empty()) {499 if (filter.hasArtist()) {
493 qs += " AND artist = ?";500 qs += " AND artist = ?";
494 }501 }
495 if (!album_artist.empty()) {502 if (filter.hasAlbumArtist()) {
496 qs += " AND album_artist = ?";503 qs += " AND album_artist = ?";
497 }504 }
505 if (filter.hasGenre()) {
506 qs += "AND genre = ?";
507 }
498 qs += R"(508 qs += R"(
499GROUP BY album, album_artist509GROUP BY album, album_artist
500ORDER BY album_artist, album510ORDER BY album_artist, album
@@ -503,37 +513,68 @@
503 Statement query(p->db, qs.c_str());513 Statement query(p->db, qs.c_str());
504 int param = 1;514 int param = 1;
505 query.bind(param++, (int)AudioMedia);515 query.bind(param++, (int)AudioMedia);
506 if (!artist.empty()) {516 if (filter.hasArtist()) {
507 query.bind(param++, artist);517 query.bind(param++, filter.getArtist());
508 }518 }
509 if (!album_artist.empty()) {519 if (filter.hasAlbumArtist()) {
510 query.bind(param++, album_artist);520 query.bind(param++, filter.getAlbumArtist());
521 }
522 if (filter.hasGenre()) {
523 query.bind(param++, filter.getGenre());
511 }524 }
512 query.bind(param++, limit);525 query.bind(param++, limit);
513526
514 return collect_albums(query);527 return collect_albums(query);
515}528}
516529
517vector<std::string> MediaStore::listArtists(bool album_artists, int limit) const {530vector<std::string> MediaStore::listArtists(const Filter &filter, int limit) const {
518 const char *qs;531 string qs(R"(
519532SELECT artist FROM media
520 if (album_artists) {533 WHERE type = ?
521 qs = R"(534)");
535 if (filter.hasGenre()) {
536 qs += " AND genre = ?";
537 }
538 qs += R"(
539 GROUP BY artist
540 ORDER BY artist
541 LIMIT ?
542)";
543 Statement query(p->db, qs.c_str());
544 int param = 1;
545 query.bind(param++, (int)AudioMedia);
546 if (filter.hasGenre()) {
547 query.bind(param++, filter.getGenre());
548 }
549 query.bind(param++, limit);
550
551 vector<string> artists;
552 while (query.step()) {
553 artists.push_back(query.getText(0));
554 }
555 return artists;
556}
557
558vector<std::string> MediaStore::listAlbumArtists(const Filter &filter, int limit) const {
559 string qs(R"(
522SELECT album_artist FROM media560SELECT album_artist FROM media
561 WHERE type = ?
562)");
563 if (filter.hasGenre()) {
564 qs += " AND genre = ?";
565 }
566 qs += R"(
523 GROUP BY album_artist567 GROUP BY album_artist
524 ORDER BY album_artist568 ORDER BY album_artist
525 LIMIT ?569 LIMIT ?
526)";570)";
527 } else {571 Statement query(p->db, qs.c_str());
528 qs = R"(572 int param = 1;
529SELECT artist FROM media573 query.bind(param++, (int)AudioMedia);
530 GROUP BY artist574 if (filter.hasGenre()) {
531 ORDER BY artist575 query.bind(param++, filter.getGenre());
532 LIMIT ?
533)";
534 }576 }
535 Statement query(p->db, qs);577 query.bind(param++, limit);
536 query.bind(1, limit);
537578
538 vector<string> artists;579 vector<string> artists;
539 while (query.step()) {580 while (query.step()) {
@@ -542,6 +583,24 @@
542 return artists;583 return artists;
543}584}
544585
586vector<std::string> MediaStore::listGenres(int limit) const {
587 Statement query(p->db, R"(
588SELECT genre FROM media
589 WHERE type = ?
590 GROUP BY genre
591 ORDER BY genre
592 LIMIT ?
593)");
594 query.bind(1, (int)AudioMedia);
595 query.bind(2, limit);
596
597 vector<string> genres;
598 while (query.step()) {
599 genres.push_back(query.getText(0));
600 }
601 return genres;
602}
603
545void MediaStorePrivate::pruneDeleted() {604void MediaStorePrivate::pruneDeleted() {
546 vector<string> deleted;605 vector<string> deleted;
547 Statement query(db, "SELECT filename FROM media");606 Statement query(db, "SELECT filename FROM media");
548607
=== modified file 'src/mediascanner/MediaStore.hh'
--- src/mediascanner/MediaStore.hh 2014-05-29 09:17:39 +0000
+++ src/mediascanner/MediaStore.hh 2014-05-29 09:17:39 +0000
@@ -29,6 +29,7 @@
29struct MediaStorePrivate;29struct MediaStorePrivate;
30class MediaFile;30class MediaFile;
31class Album;31class Album;
32class Filter;
3233
33enum OpenType {34enum OpenType {
34 MS_READ_ONLY,35 MS_READ_ONLY,
@@ -53,9 +54,11 @@
53 std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const;54 std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const;
54 std::vector<MediaFile> getAlbumSongs(const Album& album) const;55 std::vector<MediaFile> getAlbumSongs(const Album& album) const;
55 std::string getETag(const std::string &filename) const;56 std::string getETag(const std::string &filename) const;
56 std::vector<MediaFile> listSongs(const std::string& artist="", const std::string& album="", const std::string& album_artist="", int limit=-1) const;57 std::vector<MediaFile> listSongs(const Filter &filter, int limit=-1) const;
57 std::vector<Album> listAlbums(const std::string& artist="", const std::string& album_artist="", int limit=-1) const;58 std::vector<Album> listAlbums(const Filter &filter, int limit=-1) const;
58 std::vector<std::string> listArtists(bool album_artists, int limit=-1) const;59 std::vector<std::string> listArtists(const Filter &filter, int limit=-1) const;
60 std::vector<std::string>listAlbumArtists(const Filter &filter, int limit=-1) const;
61 std::vector<std::string>listGenres(int limit=-1) const;
5962
60 size_t size() const;63 size_t size() const;
61 void pruneDeleted();64 void pruneDeleted();
6265
=== modified file 'src/ms-dbus/dbus-codec.cc'
--- src/ms-dbus/dbus-codec.cc 2014-05-29 09:17:39 +0000
+++ src/ms-dbus/dbus-codec.cc 2014-05-29 09:17:39 +0000
@@ -24,6 +24,7 @@
24#include <mediascanner/MediaFile.hh>24#include <mediascanner/MediaFile.hh>
25#include <mediascanner/MediaFileBuilder.hh>25#include <mediascanner/MediaFileBuilder.hh>
26#include <mediascanner/Album.hh>26#include <mediascanner/Album.hh>
27#include <mediascanner/Filter.hh>
27#include "dbus-codec.hh"28#include "dbus-codec.hh"
2829
29using core::dbus::Message;30using core::dbus::Message;
@@ -32,6 +33,7 @@
32using mediascanner::MediaFileBuilder;33using mediascanner::MediaFileBuilder;
33using mediascanner::MediaType;34using mediascanner::MediaType;
34using mediascanner::Album;35using mediascanner::Album;
36using mediascanner::Filter;
35using std::string;37using std::string;
3638
37void Codec<MediaFile>::encode_argument(Message::Writer &out, const MediaFile &file) {39void Codec<MediaFile>::encode_argument(Message::Writer &out, const MediaFile &file) {
@@ -88,3 +90,46 @@
88 r >> title >> artist;90 r >> title >> artist;
89 album = Album(title, artist);91 album = Album(title, artist);
90}92}
93
94void Codec<Filter>::encode_argument(Message::Writer &out, const Filter &filter) {
95 auto w = out.open_array(core::dbus::types::Signature("{ss}"));
96
97 if (filter.hasArtist()) {
98 w.close_dict_entry(
99 w.open_dict_entry() << string("artist") << filter.getArtist());
100 }
101 if (filter.hasAlbum()) {
102 w.close_dict_entry(
103 w.open_dict_entry() << string("album") << filter.getAlbum());
104 }
105 if (filter.hasAlbumArtist()) {
106 w.close_dict_entry(
107 w.open_dict_entry() << string("album_artist") << filter.getAlbumArtist());
108 }
109 if (filter.hasGenre()) {
110 w.close_dict_entry(
111 w.open_dict_entry() << string("genre") << filter.getGenre());
112 }
113
114 out.close_array(std::move(w));
115}
116
117void Codec<Filter>::decode_argument(Message::Reader &in, Filter &filter) {
118 auto r = in.pop_array();
119
120 filter.clear();
121 while (r.type() != ArgumentType::invalid) {
122 string key, value;
123 r.pop_dict_entry() >> key >> value;
124
125 if (key == "artist") {
126 filter.setArtist(value);
127 } else if (key == "album") {
128 filter.setAlbum(value);
129 } else if (key == "album_artist") {
130 filter.setAlbumArtist(value);
131 } else if (key == "genre") {
132 filter.setGenre(value);
133 }
134 }
135}
91136
=== modified file 'src/ms-dbus/dbus-codec.hh'
--- src/ms-dbus/dbus-codec.hh 2014-05-29 09:17:39 +0000
+++ src/ms-dbus/dbus-codec.hh 2014-05-29 09:17:39 +0000
@@ -27,6 +27,7 @@
27namespace mediascanner {27namespace mediascanner {
28class MediaFile;28class MediaFile;
29class Album;29class Album;
30class Filter;
30}31}
3132
32namespace core {33namespace core {
@@ -44,6 +45,12 @@
44 static void decode_argument(Message::Reader &in, mediascanner::Album &album);45 static void decode_argument(Message::Reader &in, mediascanner::Album &album);
45};46};
4647
48template <>
49struct Codec<mediascanner::Filter> {
50 static void encode_argument(Message::Writer &out, const mediascanner::Filter &filter);
51 static void decode_argument(Message::Reader &in, mediascanner::Filter &filter);
52};
53
47namespace helper {54namespace helper {
4855
49template<>56template<>
@@ -80,6 +87,23 @@
80 }87 }
81};88};
8289
90template<>
91struct TypeMapper<mediascanner::Filter> {
92 constexpr static ArgumentType type_value() {
93 return ArgumentType::array;
94 }
95 constexpr static bool is_basic_type() {
96 return false;
97 }
98 constexpr static bool requires_signature() {
99 return true;
100 }
101 static const std::string &signature() {
102 static const std::string s = "a{ss}";
103 return s;
104 }
105};
106
83}107}
84108
85}109}
86110
=== modified file 'src/ms-dbus/dbus-interface.hh'
--- src/ms-dbus/dbus-interface.hh 2014-05-29 09:17:39 +0000
+++ src/ms-dbus/dbus-interface.hh 2014-05-29 09:17:39 +0000
@@ -153,6 +153,32 @@
153 return std::chrono::seconds{1};153 return std::chrono::seconds{1};
154 }154 }
155 };155 };
156
157 struct ListAlbumArtists {
158 typedef MediaStoreInterface Interface;
159
160 inline static const std::string& name() {
161 static std::string s = "ListAlbumArtists";
162 return s;
163 }
164
165 inline static const std::chrono::milliseconds default_timeout() {
166 return std::chrono::seconds{1};
167 }
168 };
169
170 struct ListGenres {
171 typedef MediaStoreInterface Interface;
172
173 inline static const std::string& name() {
174 static std::string s = "ListGenres";
175 return s;
176 }
177
178 inline static const std::chrono::milliseconds default_timeout() {
179 return std::chrono::seconds{1};
180 }
181 };
156};182};
157183
158}184}
159185
=== modified file 'src/ms-dbus/service-skeleton.cc'
--- src/ms-dbus/service-skeleton.cc 2014-05-29 09:17:39 +0000
+++ src/ms-dbus/service-skeleton.cc 2014-05-29 09:17:39 +0000
@@ -6,6 +6,7 @@
6#include <sys/apparmor.h>6#include <sys/apparmor.h>
77
8#include <mediascanner/Album.hh>8#include <mediascanner/Album.hh>
9#include <mediascanner/Filter.hh>
9#include <mediascanner/MediaFile.hh>10#include <mediascanner/MediaFile.hh>
10#include <mediascanner/MediaStore.hh>11#include <mediascanner/MediaStore.hh>
1112
@@ -88,6 +89,16 @@
88 &Private::handle_list_artists,89 &Private::handle_list_artists,
89 this,90 this,
90 std::placeholders::_1));91 std::placeholders::_1));
92 object->install_method_handler<MediaStoreInterface::ListAlbumArtists>(
93 std::bind(
94 &Private::handle_list_album_artists,
95 this,
96 std::placeholders::_1));
97 object->install_method_handler<MediaStoreInterface::ListGenres>(
98 std::bind(
99 &Private::handle_list_genres,
100 this,
101 std::placeholders::_1));
91 }102 }
92103
93 std::string get_client_apparmor_context(const Message::Ptr &message) {104 std::string get_client_apparmor_context(const Message::Ptr &message) {
@@ -253,12 +264,12 @@
253 if (!check_access(message, AudioMedia))264 if (!check_access(message, AudioMedia))
254 return;265 return;
255266
256 std::string artist, album, album_artist;267 Filter filter;
257 int32_t limit;268 int32_t limit;
258 message->reader() >> artist >> album >> album_artist >> limit;269 message->reader() >> filter >> limit;
259 Message::Ptr reply;270 Message::Ptr reply;
260 try {271 try {
261 auto results = store->listSongs(artist, album, album_artist, limit);272 auto results = store->listSongs(filter, limit);
262 reply = Message::make_method_return(message);273 reply = Message::make_method_return(message);
263 reply->writer() << results;274 reply->writer() << results;
264 } catch (const std::exception &e) {275 } catch (const std::exception &e) {
@@ -273,12 +284,12 @@
273 if (!check_access(message, AudioMedia))284 if (!check_access(message, AudioMedia))
274 return;285 return;
275286
276 std::string artist, album_artist;287 Filter filter;
277 int32_t limit;288 int32_t limit;
278 message->reader() >> artist >> album_artist >> limit;289 message->reader() >> filter >> limit;
279 Message::Ptr reply;290 Message::Ptr reply;
280 try {291 try {
281 auto albums = store->listAlbums(artist, album_artist, limit);292 auto albums = store->listAlbums(filter, limit);
282 reply = Message::make_method_return(message);293 reply = Message::make_method_return(message);
283 reply->writer() << albums;294 reply->writer() << albums;
284 } catch (const std::exception &e) {295 } catch (const std::exception &e) {
@@ -293,14 +304,53 @@
293 if (!check_access(message, AudioMedia))304 if (!check_access(message, AudioMedia))
294 return;305 return;
295306
296 bool album_artists;307 Filter filter;
297 int32_t limit;308 int32_t limit;
298 message->reader() >> album_artists >> limit;309 message->reader() >> filter >> limit;
299 Message::Ptr reply;310 Message::Ptr reply;
300 try {311 try {
301 auto artists = store->listArtists(album_artists, limit);312 auto artists = store->listArtists(filter, limit);
302 reply = Message::make_method_return(message);313 reply = Message::make_method_return(message);
303 reply->writer() << artists;314 reply->writer() << artists;
315 } catch (const std::exception &e) {
316 reply = Message::make_error(
317 message, MediaStoreInterface::Errors::Error::name(),
318 e.what());
319 }
320 impl->access_bus()->send(reply);
321 }
322
323 void handle_list_album_artists(const Message::Ptr &message) {
324 if (!check_access(message, AudioMedia))
325 return;
326
327 Filter filter;
328 int32_t limit;
329 message->reader() >> filter >> limit;
330 Message::Ptr reply;
331 try {
332 auto artists = store->listAlbumArtists(filter, limit);
333 reply = Message::make_method_return(message);
334 reply->writer() << artists;
335 } catch (const std::exception &e) {
336 reply = Message::make_error(
337 message, MediaStoreInterface::Errors::Error::name(),
338 e.what());
339 }
340 impl->access_bus()->send(reply);
341 }
342
343 void handle_list_genres(const Message::Ptr &message) {
344 if (!check_access(message, AudioMedia))
345 return;
346
347 int32_t limit;
348 message->reader() >> limit;
349 Message::Ptr reply;
350 try {
351 auto genres = store->listGenres(limit);
352 reply = Message::make_method_return(message);
353 reply->writer() << genres;
304 } catch (const std::exception &e) {354 } catch (const std::exception &e) {
305 reply = Message::make_error(355 reply = Message::make_error(
306 message, MediaStoreInterface::Errors::Error::name(),356 message, MediaStoreInterface::Errors::Error::name(),
307357
=== modified file 'src/ms-dbus/service-stub.cc'
--- src/ms-dbus/service-stub.cc 2014-05-29 09:17:39 +0000
+++ src/ms-dbus/service-stub.cc 2014-05-29 09:17:39 +0000
@@ -20,6 +20,7 @@
20#include <stdexcept>20#include <stdexcept>
2121
22#include <mediascanner/Album.hh>22#include <mediascanner/Album.hh>
23#include <mediascanner/Filter.hh>
23#include <mediascanner/MediaFile.hh>24#include <mediascanner/MediaFile.hh>
24#include "service-stub.hh"25#include "service-stub.hh"
25#include "dbus-interface.hh"26#include "dbus-interface.hh"
@@ -79,21 +80,35 @@
79 return result.value();80 return result.value();
80}81}
8182
82std::vector<MediaFile> ServiceStub::listSongs(const string &artist, const string &album, const string &album_artist, int limit) const {83std::vector<MediaFile> ServiceStub::listSongs(const Filter &filter, int limit) const {
83 auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListSongs, std::vector<MediaFile>>(artist, album, album_artist, (int32_t)limit);84 auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListSongs, std::vector<MediaFile>>(filter, (int32_t)limit);
84 if (result.is_error())85 if (result.is_error())
85 throw std::runtime_error(result.error().print());86 throw std::runtime_error(result.error().print());
86 return result.value();87 return result.value();
87}88}
8889
89std::vector<Album> ServiceStub::listAlbums(const string &artist, const string &album_artist, int limit) const {90std::vector<Album> ServiceStub::listAlbums(const Filter &filter, int limit) const {
90 auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListAlbums, std::vector<Album>>(artist, album_artist, (int32_t)limit);91 auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListAlbums, std::vector<Album>>(filter, (int32_t)limit);
91 if (result.is_error())92 if (result.is_error())
92 throw std::runtime_error(result.error().print());93 throw std::runtime_error(result.error().print());
93 return result.value();94 return result.value();
94}95}
95std::vector<string> ServiceStub::listArtists(bool album_artists, int limit) const {96std::vector<string> ServiceStub::listArtists(const Filter &filter, int limit) const {
96 auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListArtists, std::vector<string>>(album_artists, (int32_t)limit);97 auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListArtists, std::vector<string>>(filter, (int32_t)limit);
98 if (result.is_error())
99 throw std::runtime_error(result.error().print());
100 return result.value();
101}
102
103std::vector<string> ServiceStub::listAlbumArtists(const Filter &filter, int limit) const {
104 auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListAlbumArtists, std::vector<string>>(filter, (int32_t)limit);
105 if (result.is_error())
106 throw std::runtime_error(result.error().print());
107 return result.value();
108}
109
110std::vector<string> ServiceStub::listGenres(int limit) const {
111 auto result = p->object->invoke_method_synchronously<MediaStoreInterface::ListGenres, std::vector<string>>((int32_t)limit);
97 if (result.is_error())112 if (result.is_error())
98 throw std::runtime_error(result.error().print());113 throw std::runtime_error(result.error().print());
99 return result.value();114 return result.value();
100115
=== modified file 'src/ms-dbus/service-stub.hh'
--- src/ms-dbus/service-stub.hh 2014-05-29 09:17:39 +0000
+++ src/ms-dbus/service-stub.hh 2014-05-29 09:17:39 +0000
@@ -32,6 +32,7 @@
32namespace mediascanner {32namespace mediascanner {
3333
34class Album;34class Album;
35class Filter;
35class MediaFile;36class MediaFile;
3637
37namespace dbus {38namespace dbus {
@@ -46,9 +47,11 @@
46 std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const;47 std::vector<Album> queryAlbums(const std::string &core_term, int limit=-1) const;
47 std::vector<MediaFile> getAlbumSongs(const Album& album) const;48 std::vector<MediaFile> getAlbumSongs(const Album& album) const;
48 std::string getETag(const std::string &filename) const;49 std::string getETag(const std::string &filename) const;
49 std::vector<MediaFile> listSongs(const std::string& artist="", const std::string& album="", const std::string& album_artist="", int limit=-1) const;50 std::vector<MediaFile> listSongs(const Filter &filter, int limit=-1) const;
50 std::vector<Album> listAlbums(const std::string& artist="", const std::string& album_artist="", int limit=-1) const;51 std::vector<Album> listAlbums(const Filter &filter, int limit=-1) const;
51 std::vector<std::string> listArtists(bool album_artists, int limit=-1) const;52 std::vector<std::string> listArtists(const Filter &filter, int limit=-1) const;
53 std::vector<std::string> listAlbumArtists(const Filter &filter, int limit=-1) const;
54 std::vector<std::string> listGenres(int limit=-1) const;
5255
53private:56private:
54 struct Private;57 struct Private;
5558
=== modified file 'src/qml/Ubuntu/MediaScanner/AlbumModelBase.cc'
--- src/qml/Ubuntu/MediaScanner/AlbumModelBase.cc 2014-05-06 09:09:49 +0000
+++ src/qml/Ubuntu/MediaScanner/AlbumModelBase.cc 2014-05-29 09:17:39 +0000
@@ -62,4 +62,5 @@
62 beginResetModel();62 beginResetModel();
63 this->results = results;63 this->results = results;
64 endResetModel();64 endResetModel();
65 Q_EMIT rowCountChanged();
65}66}
6667
=== modified file 'src/qml/Ubuntu/MediaScanner/AlbumModelBase.hh'
--- src/qml/Ubuntu/MediaScanner/AlbumModelBase.hh 2014-05-06 09:09:49 +0000
+++ src/qml/Ubuntu/MediaScanner/AlbumModelBase.hh 2014-05-29 09:17:39 +0000
@@ -31,7 +31,7 @@
31class AlbumModelBase : public QAbstractListModel {31class AlbumModelBase : public QAbstractListModel {
32 Q_OBJECT32 Q_OBJECT
33 Q_ENUMS(Roles)33 Q_ENUMS(Roles)
34 Q_PROPERTY(int rowCount READ rowCount) // NOTIFY modelReset34 Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
35public:35public:
36 enum Roles {36 enum Roles {
37 RoleTitle,37 RoleTitle,
@@ -44,6 +44,8 @@
44 QVariant data(const QModelIndex &index, int role) const override;44 QVariant data(const QModelIndex &index, int role) const override;
4545
46 Q_INVOKABLE QVariant get(int row, Roles role) const;46 Q_INVOKABLE QVariant get(int row, Roles role) const;
47Q_SIGNALS:
48 void rowCountChanged();
47protected:49protected:
48 QHash<int, QByteArray> roleNames() const override;50 QHash<int, QByteArray> roleNames() const override;
49 void updateResults(const std::vector<mediascanner::Album> &results);51 void updateResults(const std::vector<mediascanner::Album> &results);
5052
=== modified file 'src/qml/Ubuntu/MediaScanner/AlbumsModel.cc'
--- src/qml/Ubuntu/MediaScanner/AlbumsModel.cc 2014-02-27 07:02:21 +0000
+++ src/qml/Ubuntu/MediaScanner/AlbumsModel.cc 2014-05-29 09:17:39 +0000
@@ -24,8 +24,6 @@
24AlbumsModel::AlbumsModel(QObject *parent)24AlbumsModel::AlbumsModel(QObject *parent)
25 : AlbumModelBase(parent),25 : AlbumModelBase(parent),
26 store(nullptr),26 store(nullptr),
27 artist(""),
28 album_artist(""),
29 limit(-1) {27 limit(-1) {
30}28}
3129
@@ -40,25 +38,66 @@
40 }38 }
41}39}
4240
43QString AlbumsModel::getArtist() {41QVariant AlbumsModel::getArtist() {
44 return artist;42 if (!filter.hasArtist())
45}43 return QVariant();
4644 return QString::fromStdString(filter.getArtist());
47void AlbumsModel::setArtist(const QString artist) {45}
48 if (this->artist != artist) {46
49 this->artist = artist;47void AlbumsModel::setArtist(const QVariant artist) {
50 update();48 if (artist.isNull()) {
51 }49 if (filter.hasArtist()) {
52}50 filter.unsetArtist();
5351 update();
54QString AlbumsModel::getAlbumArtist() {52 }
55 return album_artist;53 } else {
56}54 const std::string std_artist = artist.value<QString>().toStdString();
5755 if (!filter.hasArtist() || filter.getArtist() != std_artist) {
58void AlbumsModel::setAlbumArtist(const QString album_artist) {56 filter.setArtist(std_artist);
59 if (this->album_artist != album_artist) {57 update();
60 this->album_artist = album_artist;58 }
61 update();59 }
60}
61
62QVariant AlbumsModel::getAlbumArtist() {
63 if (!filter.hasAlbumArtist())
64 return QVariant();
65 return QString::fromStdString(filter.getAlbumArtist());
66}
67
68void AlbumsModel::setAlbumArtist(const QVariant album_artist) {
69 if (album_artist.isNull()) {
70 if (filter.hasAlbumArtist()) {
71 filter.unsetAlbumArtist();
72 update();
73 }
74 } else {
75 const std::string std_album_artist = album_artist.value<QString>().toStdString();
76 if (!filter.hasAlbumArtist() || filter.getAlbumArtist() != std_album_artist) {
77 filter.setAlbumArtist(std_album_artist);
78 update();
79 }
80 }
81}
82
83QVariant AlbumsModel::getGenre() {
84 if (!filter.hasGenre())
85 return QVariant();
86 return QString::fromStdString(filter.getGenre());
87}
88
89void AlbumsModel::setGenre(const QVariant genre) {
90 if (genre.isNull()) {
91 if (filter.hasGenre()) {
92 filter.unsetGenre();
93 update();
94 }
95 } else {
96 const std::string std_genre = genre.value<QString>().toStdString();
97 if (!filter.hasGenre() || filter.getGenre() != std_genre) {
98 filter.setGenre(std_genre);
99 update();
100 }
62 }101 }
63}102}
64103
@@ -77,6 +116,6 @@
77 if (store == nullptr) {116 if (store == nullptr) {
78 updateResults(std::vector<mediascanner::Album>());117 updateResults(std::vector<mediascanner::Album>());
79 } else {118 } else {
80 updateResults(store->store.listAlbums(artist.toStdString(), album_artist.toStdString(), limit));119 updateResults(store->store.listAlbums(filter, limit));
81 }120 }
82}121}
83122
=== modified file 'src/qml/Ubuntu/MediaScanner/AlbumsModel.hh'
--- src/qml/Ubuntu/MediaScanner/AlbumsModel.hh 2014-02-27 07:02:21 +0000
+++ src/qml/Ubuntu/MediaScanner/AlbumsModel.hh 2014-05-29 09:17:39 +0000
@@ -22,6 +22,7 @@
2222
23#include <QString>23#include <QString>
2424
25#include <mediascanner/Filter.hh>
25#include "MediaStoreWrapper.hh"26#include "MediaStoreWrapper.hh"
26#include "AlbumModelBase.hh"27#include "AlbumModelBase.hh"
2728
@@ -31,8 +32,9 @@
31class AlbumsModel : public AlbumModelBase {32class AlbumsModel : public AlbumModelBase {
32 Q_OBJECT33 Q_OBJECT
33 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)34 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)
34 Q_PROPERTY(QString artist READ getArtist WRITE setArtist)35 Q_PROPERTY(QVariant artist READ getArtist WRITE setArtist)
35 Q_PROPERTY(QString albumArtist READ getAlbumArtist WRITE setAlbumArtist)36 Q_PROPERTY(QVariant albumArtist READ getAlbumArtist WRITE setAlbumArtist)
37 Q_PROPERTY(QVariant genre READ getGenre WRITE setGenre)
36 Q_PROPERTY(int limit READ getLimit WRITE setLimit)38 Q_PROPERTY(int limit READ getLimit WRITE setLimit)
37public:39public:
38 explicit AlbumsModel(QObject *parent=0);40 explicit AlbumsModel(QObject *parent=0);
@@ -40,17 +42,19 @@
40 MediaStoreWrapper *getStore();42 MediaStoreWrapper *getStore();
41 void setStore(MediaStoreWrapper *store);43 void setStore(MediaStoreWrapper *store);
4244
43 QString getArtist();45 QVariant getArtist();
44 void setArtist(const QString artist);46 void setArtist(const QVariant artist);
45 QString getAlbumArtist();47 QVariant getAlbumArtist();
46 void setAlbumArtist(const QString album_artist);48 void setAlbumArtist(const QVariant album_artist);
49 QVariant getGenre();
50 void setGenre(const QVariant genre);
47 int getLimit();51 int getLimit();
48 void setLimit(int limit);52 void setLimit(int limit);
49private:53private:
50 void update();54 void update();
5155
52 MediaStoreWrapper *store;56 MediaStoreWrapper *store;
53 QString artist, album_artist;57 Filter filter;
54 int limit;58 int limit;
55};59};
5660
5761
=== modified file 'src/qml/Ubuntu/MediaScanner/ArtistsModel.cc'
--- src/qml/Ubuntu/MediaScanner/ArtistsModel.cc 2014-05-06 09:09:49 +0000
+++ src/qml/Ubuntu/MediaScanner/ArtistsModel.cc 2014-05-29 09:17:39 +0000
@@ -75,6 +75,27 @@
75 }75 }
76}76}
7777
78QVariant ArtistsModel::getGenre() {
79 if (!filter.hasGenre())
80 return QVariant();
81 return QString::fromStdString(filter.getGenre());
82}
83
84void ArtistsModel::setGenre(const QVariant genre) {
85 if (genre.isNull()) {
86 if (filter.hasGenre()) {
87 filter.unsetGenre();
88 update();
89 }
90 } else {
91 const std::string std_genre = genre.value<QString>().toStdString();
92 if (!filter.hasGenre() || filter.getGenre() != std_genre) {
93 filter.setGenre(std_genre);
94 update();
95 }
96 }
97}
98
78int ArtistsModel::getLimit() {99int ArtistsModel::getLimit() {
79 return limit;100 return limit;
80}101}
@@ -91,8 +112,12 @@
91 if (store == nullptr) {112 if (store == nullptr) {
92 this->results.clear();113 this->results.clear();
93 } else {114 } else {
94 this->results = store->store.listArtists(album_artists, limit);115 if (album_artists) {
116 this->results = store->store.listAlbumArtists(filter, limit);
117 } else {
118 this->results = store->store.listArtists(filter, limit);
119 }
95 }120 }
96 this->results = results;
97 endResetModel();121 endResetModel();
122 Q_EMIT rowCountChanged();
98}123}
99124
=== modified file 'src/qml/Ubuntu/MediaScanner/ArtistsModel.hh'
--- src/qml/Ubuntu/MediaScanner/ArtistsModel.hh 2014-05-06 09:09:49 +0000
+++ src/qml/Ubuntu/MediaScanner/ArtistsModel.hh 2014-05-29 09:17:39 +0000
@@ -24,6 +24,7 @@
24#include <QAbstractListModel>24#include <QAbstractListModel>
25#include <QString>25#include <QString>
2626
27#include <mediascanner/Filter.hh>
27#include "MediaStoreWrapper.hh"28#include "MediaStoreWrapper.hh"
2829
29namespace mediascanner {30namespace mediascanner {
@@ -34,8 +35,9 @@
34 Q_ENUMS(Roles)35 Q_ENUMS(Roles)
35 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)36 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)
36 Q_PROPERTY(bool albumArtists READ getAlbumArtists WRITE setAlbumArtists)37 Q_PROPERTY(bool albumArtists READ getAlbumArtists WRITE setAlbumArtists)
38 Q_PROPERTY(QVariant genre READ getGenre WRITE setGenre)
37 Q_PROPERTY(int limit READ getLimit WRITE setLimit)39 Q_PROPERTY(int limit READ getLimit WRITE setLimit)
38 Q_PROPERTY(int rowCount READ rowCount) // NOTIFY modelReset40 Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
39public:41public:
40 enum Roles {42 enum Roles {
41 RoleArtist,43 RoleArtist,
@@ -46,6 +48,8 @@
46 QVariant data(const QModelIndex &index, int role) const override;48 QVariant data(const QModelIndex &index, int role) const override;
4749
48 Q_INVOKABLE QVariant get(int row, Roles role) const;50 Q_INVOKABLE QVariant get(int row, Roles role) const;
51Q_SIGNALS:
52 void rowCountChanged();
49protected:53protected:
50 QHash<int, QByteArray> roleNames() const override;54 QHash<int, QByteArray> roleNames() const override;
5155
@@ -53,6 +57,8 @@
53 void setStore(MediaStoreWrapper *store);57 void setStore(MediaStoreWrapper *store);
54 bool getAlbumArtists();58 bool getAlbumArtists();
55 void setAlbumArtists(bool album_artists);59 void setAlbumArtists(bool album_artists);
60 QVariant getGenre();
61 void setGenre(QVariant genre);
56 int getLimit();62 int getLimit();
57 void setLimit(int limit);63 void setLimit(int limit);
5864
@@ -62,6 +68,7 @@
62 QHash<int, QByteArray> roles;68 QHash<int, QByteArray> roles;
63 std::vector<std::string> results;69 std::vector<std::string> results;
64 MediaStoreWrapper *store;70 MediaStoreWrapper *store;
71 Filter filter;
65 bool album_artists;72 bool album_artists;
66 int limit;73 int limit;
67};74};
6875
=== modified file 'src/qml/Ubuntu/MediaScanner/CMakeLists.txt'
--- src/qml/Ubuntu/MediaScanner/CMakeLists.txt 2014-05-29 09:17:39 +0000
+++ src/qml/Ubuntu/MediaScanner/CMakeLists.txt 2014-05-29 09:17:39 +0000
@@ -12,6 +12,7 @@
12 AlbumModelBase.cc12 AlbumModelBase.cc
13 AlbumsModel.cc13 AlbumsModel.cc
14 ArtistsModel.cc14 ArtistsModel.cc
15 GenresModel.cc
15 SongsModel.cc16 SongsModel.cc
16 SongsSearchModel.cc17 SongsSearchModel.cc
17)18)
1819
=== added file 'src/qml/Ubuntu/MediaScanner/GenresModel.cc'
--- src/qml/Ubuntu/MediaScanner/GenresModel.cc 1970-01-01 00:00:00 +0000
+++ src/qml/Ubuntu/MediaScanner/GenresModel.cc 2014-05-29 09:17:39 +0000
@@ -0,0 +1,86 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * Authors:
5 * James Henstridge <james.henstridge@canonical.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License version 3 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "GenresModel.hh"
21
22using namespace mediascanner::qml;
23
24GenresModel::GenresModel(QObject *parent)
25 : QAbstractListModel(parent),
26 store(nullptr),
27 limit(-1) {
28 roles[Roles::RoleGenre] = "genre";
29}
30
31int GenresModel::rowCount(const QModelIndex &) const {
32 return results.size();
33}
34
35QVariant GenresModel::data(const QModelIndex &index, int role) const {
36 if (index.row() < 0 || index.row() >= (ptrdiff_t)results.size()) {
37 return QVariant();
38 }
39 switch (role) {
40 case RoleGenre:
41 return QString::fromStdString(results[index.row()]);
42 default:
43 return QVariant();
44 }
45}
46
47QVariant GenresModel::get(int row, GenresModel::Roles role) const {
48 return data(index(row, 0), role);
49}
50
51QHash<int, QByteArray> GenresModel::roleNames() const {
52 return roles;
53}
54
55MediaStoreWrapper *GenresModel::getStore() {
56 return store;
57}
58
59void GenresModel::setStore(MediaStoreWrapper *store) {
60 if (this->store != store) {
61 this->store = store;
62 update();
63 }
64}
65
66int GenresModel::getLimit() {
67 return limit;
68}
69
70void GenresModel::setLimit(int limit) {
71 if (this->limit != limit) {
72 this->limit = limit;
73 update();
74 }
75}
76
77void GenresModel::update() {
78 beginResetModel();
79 if (store == nullptr) {
80 this->results.clear();
81 } else {
82 this->results = store->store.listGenres(limit);
83 }
84 endResetModel();
85 Q_EMIT rowCountChanged();
86}
087
=== added file 'src/qml/Ubuntu/MediaScanner/GenresModel.hh'
--- src/qml/Ubuntu/MediaScanner/GenresModel.hh 1970-01-01 00:00:00 +0000
+++ src/qml/Ubuntu/MediaScanner/GenresModel.hh 2014-05-29 09:17:39 +0000
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * Authors:
5 * James Henstridge <james.henstridge@canonical.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License version 3 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef MEDIASCANNER_QML_GENRESMODEL_H
21#define MEDIASCANNER_QML_GENRESMODEL_H
22
23#include <string>
24#include <QAbstractListModel>
25#include <QString>
26
27#include <mediascanner/Filter.hh>
28#include "MediaStoreWrapper.hh"
29
30namespace mediascanner {
31namespace qml {
32
33class GenresModel : public QAbstractListModel {
34 Q_OBJECT
35 Q_ENUMS(Roles)
36 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)
37 Q_PROPERTY(int limit READ getLimit WRITE setLimit)
38 Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
39public:
40 enum Roles {
41 RoleGenre,
42 };
43
44 explicit GenresModel(QObject *parent = 0);
45 int rowCount(const QModelIndex &parent=QModelIndex()) const override;
46 QVariant data(const QModelIndex &index, int role) const override;
47
48 Q_INVOKABLE QVariant get(int row, Roles role) const;
49Q_SIGNALS:
50 void rowCountChanged();
51protected:
52 QHash<int, QByteArray> roleNames() const override;
53
54 MediaStoreWrapper *getStore();
55 void setStore(MediaStoreWrapper *store);
56 int getLimit();
57 void setLimit(int limit);
58
59private:
60 void update();
61
62 QHash<int, QByteArray> roles;
63 std::vector<std::string> results;
64 MediaStoreWrapper *store;
65 int limit;
66};
67
68}
69}
70
71#endif
072
=== modified file 'src/qml/Ubuntu/MediaScanner/MediaFileModelBase.cc'
--- src/qml/Ubuntu/MediaScanner/MediaFileModelBase.cc 2014-05-06 09:09:49 +0000
+++ src/qml/Ubuntu/MediaScanner/MediaFileModelBase.cc 2014-05-29 09:17:39 +0000
@@ -99,4 +99,5 @@
99 beginResetModel();99 beginResetModel();
100 this->results = results;100 this->results = results;
101 endResetModel();101 endResetModel();
102 Q_EMIT rowCountChanged();
102}103}
103104
=== modified file 'src/qml/Ubuntu/MediaScanner/MediaFileModelBase.hh'
--- src/qml/Ubuntu/MediaScanner/MediaFileModelBase.hh 2014-05-06 09:09:49 +0000
+++ src/qml/Ubuntu/MediaScanner/MediaFileModelBase.hh 2014-05-29 09:17:39 +0000
@@ -31,7 +31,7 @@
31class MediaFileModelBase : public QAbstractListModel {31class MediaFileModelBase : public QAbstractListModel {
32 Q_OBJECT32 Q_OBJECT
33 Q_ENUMS(Roles)33 Q_ENUMS(Roles)
34 Q_PROPERTY(int rowCount READ rowCount) // NOTIFY modelReset34 Q_PROPERTY(int rowCount READ rowCount NOTIFY rowCountChanged)
35public:35public:
36 enum Roles {36 enum Roles {
37 RoleModelData,37 RoleModelData,
@@ -56,6 +56,8 @@
56 QVariant data(const QModelIndex &index, int role) const override;56 QVariant data(const QModelIndex &index, int role) const override;
5757
58 Q_INVOKABLE QVariant get(int row, Roles role) const;58 Q_INVOKABLE QVariant get(int row, Roles role) const;
59Q_SIGNALS:
60 void rowCountChanged();
59protected:61protected:
60 QHash<int, QByteArray> roleNames() const override;62 QHash<int, QByteArray> roleNames() const override;
61 void updateResults(const std::vector<mediascanner::MediaFile> &results);63 void updateResults(const std::vector<mediascanner::MediaFile> &results);
6264
=== modified file 'src/qml/Ubuntu/MediaScanner/SongsModel.cc'
--- src/qml/Ubuntu/MediaScanner/SongsModel.cc 2014-02-27 05:37:36 +0000
+++ src/qml/Ubuntu/MediaScanner/SongsModel.cc 2014-05-29 09:17:39 +0000
@@ -24,9 +24,6 @@
24SongsModel::SongsModel(QObject *parent)24SongsModel::SongsModel(QObject *parent)
25 : MediaFileModelBase(parent),25 : MediaFileModelBase(parent),
26 store(nullptr),26 store(nullptr),
27 artist(""),
28 album(""),
29 album_artist(""),
30 limit(-1) {27 limit(-1) {
31}28}
3229
@@ -41,36 +38,87 @@
41 }38 }
42}39}
4340
44QString SongsModel::getArtist() {41QVariant SongsModel::getArtist() {
45 return artist;42 if (!filter.hasArtist())
46}43 return QVariant();
4744 return QString::fromStdString(filter.getArtist());
48void SongsModel::setArtist(const QString artist) {45}
49 if (this->artist != artist) {46
50 this->artist = artist;47void SongsModel::setArtist(const QVariant artist) {
51 update();48 if (artist.isNull()) {
52 }49 if (filter.hasArtist()) {
53}50 filter.unsetArtist();
5451 update();
55QString SongsModel::getAlbum() {52 }
56 return album;53 } else {
57}54 const std::string std_artist = artist.value<QString>().toStdString();
5855 if (!filter.hasArtist() || filter.getArtist() != std_artist) {
59void SongsModel::setAlbum(const QString album) {56 filter.setArtist(std_artist);
60 if (this->album != album) {57 update();
61 this->album = album;58 }
62 update();59 }
63 }60}
64}61
6562QVariant SongsModel::getAlbum() {
66QString SongsModel::getAlbumArtist() {63 if (!filter.hasAlbum())
67 return album_artist;64 return QVariant();
68}65 return QString::fromStdString(filter.getAlbum());
6966}
70void SongsModel::setAlbumArtist(const QString album_artist) {67
71 if (this->album_artist != album_artist) {68void SongsModel::setAlbum(const QVariant album) {
72 this->album_artist = album_artist;69 if (album.isNull()) {
73 update();70 if (filter.hasAlbum()) {
71 filter.unsetAlbum();
72 update();
73 }
74 } else {
75 const std::string std_album = album.value<QString>().toStdString();
76 if (!filter.hasAlbum() || filter.getAlbum() != std_album) {
77 filter.setAlbum(std_album);
78 update();
79 }
80 }
81}
82
83QVariant SongsModel::getAlbumArtist() {
84 if (!filter.hasAlbumArtist())
85 return QVariant();
86 return QString::fromStdString(filter.getAlbumArtist());
87}
88
89void SongsModel::setAlbumArtist(const QVariant album_artist) {
90 if (album_artist.isNull()) {
91 if (filter.hasAlbumArtist()) {
92 filter.unsetAlbumArtist();
93 update();
94 }
95 } else {
96 const std::string std_album_artist = album_artist.value<QString>().toStdString();
97 if (!filter.hasAlbumArtist() || filter.getAlbumArtist() != std_album_artist) {
98 filter.setAlbumArtist(std_album_artist);
99 update();
100 }
101 }
102}
103
104QVariant SongsModel::getGenre() {
105 if (!filter.hasGenre())
106 return QVariant();
107 return QString::fromStdString(filter.getGenre());
108}
109
110void SongsModel::setGenre(const QVariant genre) {
111 if (genre.isNull()) {
112 if (filter.hasGenre()) {
113 filter.unsetGenre();
114 update();
115 }
116 } else {
117 const std::string std_genre = genre.value<QString>().toStdString();
118 if (!filter.hasGenre() || filter.getGenre() != std_genre) {
119 filter.setGenre(std_genre);
120 update();
121 }
74 }122 }
75}123}
76124
@@ -89,6 +137,6 @@
89 if (store == nullptr) {137 if (store == nullptr) {
90 updateResults(std::vector<mediascanner::MediaFile>());138 updateResults(std::vector<mediascanner::MediaFile>());
91 } else {139 } else {
92 updateResults(store->store.listSongs(artist.toStdString(), album.toStdString(), album_artist.toStdString(), limit));140 updateResults(store->store.listSongs(filter, limit));
93 }141 }
94}142}
95143
=== modified file 'src/qml/Ubuntu/MediaScanner/SongsModel.hh'
--- src/qml/Ubuntu/MediaScanner/SongsModel.hh 2014-02-27 05:37:36 +0000
+++ src/qml/Ubuntu/MediaScanner/SongsModel.hh 2014-05-29 09:17:39 +0000
@@ -22,6 +22,7 @@
2222
23#include <QString>23#include <QString>
2424
25#include <mediascanner/Filter.hh>
25#include "MediaStoreWrapper.hh"26#include "MediaStoreWrapper.hh"
26#include "MediaFileModelBase.hh"27#include "MediaFileModelBase.hh"
2728
@@ -31,9 +32,10 @@
31class SongsModel : public MediaFileModelBase {32class SongsModel : public MediaFileModelBase {
32 Q_OBJECT33 Q_OBJECT
33 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)34 Q_PROPERTY(mediascanner::qml::MediaStoreWrapper* store READ getStore WRITE setStore)
34 Q_PROPERTY(QString artist READ getArtist WRITE setArtist)35 Q_PROPERTY(QVariant artist READ getArtist WRITE setArtist)
35 Q_PROPERTY(QString album READ getAlbum WRITE setAlbum)36 Q_PROPERTY(QVariant album READ getAlbum WRITE setAlbum)
36 Q_PROPERTY(QString albumArtist READ getAlbumArtist WRITE setAlbumArtist)37 Q_PROPERTY(QVariant albumArtist READ getAlbumArtist WRITE setAlbumArtist)
38 Q_PROPERTY(QVariant genre READ getGenre WRITE setGenre)
37 Q_PROPERTY(int limit READ getLimit WRITE setLimit)39 Q_PROPERTY(int limit READ getLimit WRITE setLimit)
38public:40public:
39 explicit SongsModel(QObject *parent=0);41 explicit SongsModel(QObject *parent=0);
@@ -41,19 +43,21 @@
41 MediaStoreWrapper *getStore();43 MediaStoreWrapper *getStore();
42 void setStore(MediaStoreWrapper *store);44 void setStore(MediaStoreWrapper *store);
4345
44 QString getArtist();46 QVariant getArtist();
45 void setArtist(const QString artist);47 void setArtist(const QVariant artist);
46 QString getAlbum();48 QVariant getAlbum();
47 void setAlbum(const QString album);49 void setAlbum(const QVariant album);
48 QString getAlbumArtist();50 QVariant getAlbumArtist();
49 void setAlbumArtist(const QString album_artist);51 void setAlbumArtist(const QVariant album_artist);
52 QVariant getGenre();
53 void setGenre(const QVariant genre);
50 int getLimit();54 int getLimit();
51 void setLimit(int limit);55 void setLimit(int limit);
52private:56private:
53 void update();57 void update();
5458
55 MediaStoreWrapper *store;59 MediaStoreWrapper *store;
56 QString artist, album, album_artist;60 Filter filter;
57 int limit;61 int limit;
58};62};
5963
6064
=== modified file 'src/qml/Ubuntu/MediaScanner/plugin.cc'
--- src/qml/Ubuntu/MediaScanner/plugin.cc 2014-02-28 07:01:44 +0000
+++ src/qml/Ubuntu/MediaScanner/plugin.cc 2014-05-29 09:17:39 +0000
@@ -22,6 +22,7 @@
22#include "MediaStoreWrapper.hh"22#include "MediaStoreWrapper.hh"
23#include "AlbumsModel.hh"23#include "AlbumsModel.hh"
24#include "ArtistsModel.hh"24#include "ArtistsModel.hh"
25#include "GenresModel.hh"
25#include "SongsModel.hh"26#include "SongsModel.hh"
26#include "SongsSearchModel.hh"27#include "SongsSearchModel.hh"
2728
@@ -33,6 +34,7 @@
33 "Use a MediaStore to retrieve MediaFiles");34 "Use a MediaStore to retrieve MediaFiles");
34 qmlRegisterType<AlbumsModel>(uri, 0, 1, "AlbumsModel");35 qmlRegisterType<AlbumsModel>(uri, 0, 1, "AlbumsModel");
35 qmlRegisterType<ArtistsModel>(uri, 0, 1, "ArtistsModel");36 qmlRegisterType<ArtistsModel>(uri, 0, 1, "ArtistsModel");
37 qmlRegisterType<GenresModel>(uri, 0, 1, "GenresModel");
36 qmlRegisterType<SongsModel>(uri, 0, 1, "SongsModel");38 qmlRegisterType<SongsModel>(uri, 0, 1, "SongsModel");
37 qmlRegisterType<SongsSearchModel>(uri, 0, 1, "SongsSearchModel");39 qmlRegisterType<SongsSearchModel>(uri, 0, 1, "SongsSearchModel");
38}40}
3941
=== modified file 'src/qml/Ubuntu/MediaScanner/plugin.qmltypes'
--- src/qml/Ubuntu/MediaScanner/plugin.qmltypes 2014-05-08 07:17:11 +0000
+++ src/qml/Ubuntu/MediaScanner/plugin.qmltypes 2014-05-29 09:17:39 +0000
@@ -32,8 +32,9 @@
32 exports: ["Ubuntu.MediaScanner/AlbumsModel 0.1"]32 exports: ["Ubuntu.MediaScanner/AlbumsModel 0.1"]
33 exportMetaObjectRevisions: [0]33 exportMetaObjectRevisions: [0]
34 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }34 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }
35 Property { name: "artist"; type: "string" }35 Property { name: "artist"; type: "QVariant" }
36 Property { name: "albumArtist"; type: "string" }36 Property { name: "albumArtist"; type: "QVariant" }
37 Property { name: "genre"; type: "QVariant" }
37 Property { name: "limit"; type: "int" }38 Property { name: "limit"; type: "int" }
38 }39 }
39 Component {40 Component {
@@ -49,6 +50,28 @@
49 }50 }
50 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }51 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }
51 Property { name: "albumArtists"; type: "bool" }52 Property { name: "albumArtists"; type: "bool" }
53 Property { name: "genre"; type: "QVariant" }
54 Property { name: "limit"; type: "int" }
55 Property { name: "rowCount"; type: "int"; isReadonly: true }
56 Method {
57 name: "get"
58 type: "QVariant"
59 Parameter { name: "row"; type: "int" }
60 Parameter { name: "role"; type: "Roles" }
61 }
62 }
63 Component {
64 name: "mediascanner::qml::GenresModel"
65 prototype: "QAbstractListModel"
66 exports: ["Ubuntu.MediaScanner/GenresModel 0.1"]
67 exportMetaObjectRevisions: [0]
68 Enum {
69 name: "Roles"
70 values: {
71 "RoleGenre": 0
72 }
73 }
74 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }
52 Property { name: "limit"; type: "int" }75 Property { name: "limit"; type: "int" }
53 Property { name: "rowCount"; type: "int"; isReadonly: true }76 Property { name: "rowCount"; type: "int"; isReadonly: true }
54 Method {77 Method {
@@ -140,9 +163,10 @@
140 exports: ["Ubuntu.MediaScanner/SongsModel 0.1"]163 exports: ["Ubuntu.MediaScanner/SongsModel 0.1"]
141 exportMetaObjectRevisions: [0]164 exportMetaObjectRevisions: [0]
142 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }165 Property { name: "store"; type: "mediascanner::qml::MediaStoreWrapper"; isPointer: true }
143 Property { name: "artist"; type: "string" }166 Property { name: "artist"; type: "QVariant" }
144 Property { name: "album"; type: "string" }167 Property { name: "album"; type: "QVariant" }
145 Property { name: "albumArtist"; type: "string" }168 Property { name: "albumArtist"; type: "QVariant" }
169 Property { name: "genre"; type: "QVariant" }
146 Property { name: "limit"; type: "int" }170 Property { name: "limit"; type: "int" }
147 }171 }
148 Component {172 Component {
149173
=== modified file 'src/qml/Ubuntu/MediaScanner/qmldir'
--- src/qml/Ubuntu/MediaScanner/qmldir 2014-01-02 07:48:47 +0000
+++ src/qml/Ubuntu/MediaScanner/qmldir 2014-05-29 09:17:39 +0000
@@ -1,2 +1,3 @@
1module Ubuntu.MediaScanner1module Ubuntu.MediaScanner
2plugin mediascanner-qml2plugin mediascanner-qml
3typeinfo plugin.qmltypes
34
=== added file 'test/qml/tst_albumsmodel.qml'
--- test/qml/tst_albumsmodel.qml 1970-01-01 00:00:00 +0000
+++ test/qml/tst_albumsmodel.qml 2014-05-29 09:17:39 +0000
@@ -0,0 +1,91 @@
1import QtQuick 2.0
2import QtTest 1.0
3import Ubuntu.MediaScanner 0.1
4
5Item {
6 id: root
7
8 MediaStore {
9 id: store
10 }
11
12 AlbumsModel {
13 id: model
14 store: store
15 }
16
17 TestCase {
18 name: "AlbumsModelTests"
19
20 function cleanup() {
21 model.artist = undefined;
22 model.albumArtist = undefined;
23 model.genre = undefined;
24 model.limit = -1;
25 }
26
27 function test_initial_state() {
28 compare(model.artist, undefined);
29 compare(model.albumArtist, undefined);
30 compare(model.genre, undefined);
31 compare(model.limit, -1);
32
33 compare(model.rowCount, 4);
34 compare(model.get(0, AlbumsModel.RoleTitle), "Ivy and the Big Apples");
35 compare(model.get(0, AlbumsModel.RoleArtist), "Spiderbait");
36
37 compare(model.get(1, AlbumsModel.RoleTitle), "Spiderbait");
38 compare(model.get(1, AlbumsModel.RoleArtist), "Spiderbait");
39
40 compare(model.get(2, AlbumsModel.RoleTitle), "April Uprising");
41 compare(model.get(2, AlbumsModel.RoleArtist), "The John Butler Trio");
42
43 compare(model.get(3, AlbumsModel.RoleTitle), "Sunrise Over Sea");
44 compare(model.get(3, AlbumsModel.RoleArtist), "The John Butler Trio");
45 }
46
47 function test_limit() {
48 model.limit = 2;
49 compare(model.rowCount, 2);
50
51 model.limit = 42;
52 compare(model.rowCount, 4);
53
54 model.limit = -1;
55 compare(model.rowCount, 4);
56 }
57
58 function test_artist() {
59 model.artist = "The John Butler Trio";
60 compare(model.rowCount, 2);
61
62 compare(model.get(0, AlbumsModel.RoleTitle), "April Uprising");
63 compare(model.get(0, AlbumsModel.RoleArtist), "The John Butler Trio");
64
65 model.artist = "unknown";
66 compare(model.rowCount, 0);
67 }
68
69 function test_album_artist() {
70 model.albumArtist = "The John Butler Trio";
71 compare(model.rowCount, 2);
72
73 compare(model.get(0, AlbumsModel.RoleTitle), "April Uprising");
74 compare(model.get(0, AlbumsModel.RoleArtist), "The John Butler Trio");
75
76 model.albumArtist = "unknown";
77 compare(model.rowCount, 0);
78 }
79
80 function test_genre() {
81 model.genre = "rock";
82 compare(model.rowCount, 2);
83 compare(model.get(0, AlbumsModel.RoleTitle), "Ivy and the Big Apples");
84 compare(model.get(1, AlbumsModel.RoleTitle), "Spiderbait");
85
86 model.genre = "unknown";
87 compare(model.rowCount, 0);
88 }
89
90 }
91}
092
=== added file 'test/qml/tst_artistsmodel.qml'
--- test/qml/tst_artistsmodel.qml 1970-01-01 00:00:00 +0000
+++ test/qml/tst_artistsmodel.qml 2014-05-29 09:17:39 +0000
@@ -0,0 +1,68 @@
1import QtQuick 2.0
2import QtTest 1.0
3import Ubuntu.MediaScanner 0.1
4
5Item {
6 id: root
7
8 MediaStore {
9 id: store
10 }
11
12 ArtistsModel {
13 id: model
14 store: store
15 }
16
17 TestCase {
18 name: "ArtistsModelTests"
19
20 function cleanup() {
21 model.albumArtists = false;
22 model.genre = undefined;
23 model.limit = -1;
24 }
25
26 function test_initial_state() {
27 compare(model.albumArtists, false);
28 compare(model.limit, -1);
29
30 compare(model.rowCount, 2);
31 compare(model.get(0, ArtistsModel.RoleArtist), "Spiderbait");
32 compare(model.get(1, ArtistsModel.RoleArtist), "The John Butler Trio");
33 }
34
35 function test_limit() {
36 model.limit = 1;
37 compare(model.rowCount, 1);
38
39 model.limit = 42;
40 compare(model.rowCount, 2);
41
42 model.limit = -1;
43 compare(model.rowCount, 2);
44 }
45
46 function test_album_artists() {
47 model.albumArtists = true;
48 compare(model.rowCount, 2);
49
50 compare(model.get(0, ArtistsModel.RoleArtist), "Spiderbait");
51 compare(model.get(1, ArtistsModel.RoleArtist), "The John Butler Trio");
52 }
53
54 function test_genre() {
55 model.genre = "rock";
56 compare(model.rowCount, 1);
57 compare(model.get(0, ArtistsModel.RoleArtist), "Spiderbait");
58
59 model.genre = "roots";
60 compare(model.rowCount, 1);
61 compare(model.get(0, ArtistsModel.RoleArtist), "The John Butler Trio");
62
63 model.genre = "unknown";
64 compare(model.rowCount, 0);
65 }
66
67 }
68}
069
=== added file 'test/qml/tst_genresmodel.qml'
--- test/qml/tst_genresmodel.qml 1970-01-01 00:00:00 +0000
+++ test/qml/tst_genresmodel.qml 2014-05-29 09:17:39 +0000
@@ -0,0 +1,44 @@
1import QtQuick 2.0
2import QtTest 1.0
3import Ubuntu.MediaScanner 0.1
4
5Item {
6 id: root
7
8 MediaStore {
9 id: store
10 }
11
12 GenresModel {
13 id: model
14 store: store
15 }
16
17 TestCase {
18 name: "GenresModelTests"
19
20 function cleanup() {
21 model.limit = -1;
22 }
23
24 function test_initial_state() {
25 compare(model.limit, -1);
26
27 compare(model.rowCount, 2);
28 compare(model.get(0, ArtistsModel.RoleGenre), "rock");
29 compare(model.get(1, ArtistsModel.RoleGenre), "roots");
30 }
31
32 function test_limit() {
33 model.limit = 1;
34 compare(model.rowCount, 1);
35
36 model.limit = 42;
37 compare(model.rowCount, 2);
38
39 model.limit = -1;
40 compare(model.rowCount, 2);
41 }
42
43 }
44}
045
=== added file 'test/qml/tst_songsmodel.qml'
--- test/qml/tst_songsmodel.qml 1970-01-01 00:00:00 +0000
+++ test/qml/tst_songsmodel.qml 2014-05-29 09:17:39 +0000
@@ -0,0 +1,104 @@
1import QtQuick 2.0
2import QtTest 1.0
3import Ubuntu.MediaScanner 0.1
4
5Item {
6 id: root
7
8 MediaStore {
9 id: store
10 }
11
12 SongsModel {
13 id: model
14 store: store
15 }
16
17 TestCase {
18 name: "SongsModelTests"
19
20 function cleanup() {
21 model.artist = undefined;
22 model.albumArtist = undefined;
23 model.album = undefined;
24 model.genre = undefined;
25 model.limit = -1;
26 }
27
28 function test_initial_state() {
29 compare(model.artist, undefined);
30 compare(model.albumArtist, undefined);
31 compare(model.album, undefined);
32 compare(model.limit, -1);
33
34 compare(model.rowCount, 7);
35 compare(model.get(0, SongsModel.RoleTitle), "Buy Me a Pony")
36 compare(model.get(0, SongsModel.RoleAlbum), "Ivy and the Big Apples");
37 compare(model.get(0, SongsModel.RoleAuthor), "Spiderbait");
38
39 compare(model.get(1, SongsModel.RoleTitle), "Straight Through The Sun");
40 compare(model.get(2, SongsModel.RoleTitle), "It's Beautiful");
41 compare(model.get(3, SongsModel.RoleTitle), "Revolution");
42 compare(model.get(4, SongsModel.RoleTitle), "One Way Road");
43 compare(model.get(5, SongsModel.RoleTitle), "Peaches & Cream");
44 compare(model.get(6, SongsModel.RoleTitle), "Zebra");
45 }
46
47 function test_limit() {
48 model.limit = 2;
49 compare(model.rowCount, 2);
50
51 model.limit = 42;
52 compare(model.rowCount, 7);
53
54 model.limit = -1;
55 compare(model.rowCount, 7);
56 }
57
58 function test_artist() {
59 model.artist = "The John Butler Trio";
60 compare(model.rowCount, 4);
61
62 compare(model.get(0, SongsModel.RoleTitle), "Revolution");
63 compare(model.get(0, SongsModel.RoleAuthor), "The John Butler Trio");
64
65 model.artist = "unknown";
66 compare(model.rowCount, 0);
67 }
68
69 function test_album_artist() {
70 model.albumArtist = "The John Butler Trio";
71 compare(model.rowCount, 4);
72
73 compare(model.get(0, SongsModel.RoleTitle), "Revolution");
74 compare(model.get(0, SongsModel.RoleAuthor), "The John Butler Trio");
75
76 model.albumArtist = "unknown";
77 compare(model.rowCount, 0);
78 }
79
80 function test_album() {
81 model.album = "Sunrise Over Sea";
82 compare(model.rowCount, 2);
83
84 compare(model.get(0, SongsModel.RoleTitle), "Peaches & Cream");
85 compare(model.get(0, SongsModel.RoleAuthor), "The John Butler Trio");
86
87 model.albumArtist = "unknown";
88 compare(model.rowCount, 0);
89 }
90
91 function test_genre() {
92 model.genre = "rock";
93 compare(model.rowCount, 3);
94
95 compare(model.get(0, SongsModel.RoleTitle), "Buy Me a Pony");
96 compare(model.get(1, SongsModel.RoleTitle), "Straight Through The Sun");
97 compare(model.get(2, SongsModel.RoleTitle), "It's Beautiful");
98
99 model.albumArtist = "unknown";
100 compare(model.rowCount, 0);
101 }
102
103 }
104}
0105
=== modified file 'test/test_dbus.cc'
--- test/test_dbus.cc 2014-05-29 09:17:39 +0000
+++ test/test_dbus.cc 2014-05-29 09:17:39 +0000
@@ -6,18 +6,24 @@
6#include <mediascanner/Album.hh>6#include <mediascanner/Album.hh>
7#include <mediascanner/MediaFile.hh>7#include <mediascanner/MediaFile.hh>
8#include <mediascanner/MediaFileBuilder.hh>8#include <mediascanner/MediaFileBuilder.hh>
9#include <mediascanner/Filter.hh>
9#include <ms-dbus/dbus-codec.hh>10#include <ms-dbus/dbus-codec.hh>
1011
11class MediaStoreDBusTests : public ::testing::Test {12class MediaStoreDBusTests : public ::testing::Test {
13protected:
14 virtual void SetUp() override {
15 ::testing::Test::SetUp();
16 message = core::dbus::Message::make_method_call(
17 "org.example.Name",
18 core::dbus::types::ObjectPath("/org/example/Path"),
19 "org.example.Interface",
20 "Method");
21 }
22
23 core::dbus::Message::Ptr message;
12};24};
1325
14TEST_F(MediaStoreDBusTests, mediafile_codec) {26TEST_F(MediaStoreDBusTests, mediafile_codec) {
15 auto message = core::dbus::Message::make_method_call(
16 "org.example.Name",
17 core::dbus::types::ObjectPath("/org/example/Path"),
18 "org.example.Interface",
19 "Method");
20
21 mediascanner::MediaFile media = mediascanner::MediaFileBuilder("a")27 mediascanner::MediaFile media = mediascanner::MediaFileBuilder("a")
22 .setContentType("type")28 .setContentType("type")
23 .setETag("etag")29 .setETag("etag")
@@ -42,12 +48,6 @@
42}48}
4349
44TEST_F(MediaStoreDBusTests, album_codec) {50TEST_F(MediaStoreDBusTests, album_codec) {
45 auto message = core::dbus::Message::make_method_call(
46 "org.example.Name",
47 core::dbus::types::ObjectPath("/org/example/Path"),
48 "org.example.Interface",
49 "Method");
50
51 mediascanner::Album album("title", "artist");51 mediascanner::Album album("title", "artist");
52 message->writer() << album;52 message->writer() << album;
5353
@@ -61,6 +61,33 @@
61 EXPECT_EQ(album, album2);61 EXPECT_EQ(album, album2);
62}62}
6363
64TEST_F(MediaStoreDBusTests, filter_codec) {
65 mediascanner::Filter filter;
66 filter.setArtist("Artist1");
67 filter.setAlbum("Album1");
68 filter.setAlbumArtist("AlbumArtist1");
69 filter.setGenre("Genre");
70 message->writer() << filter;
71
72 EXPECT_EQ("a{ss}", message->signature());
73 EXPECT_EQ(core::dbus::helper::TypeMapper<mediascanner::Filter>::signature(), message->signature());
74
75 mediascanner::Filter other;
76 message->reader() >> other;
77 EXPECT_EQ(filter, other);
78}
79
80TEST_F(MediaStoreDBusTests, filter_codec_empty) {
81 mediascanner::Filter empty;
82 message->writer() << empty;
83
84 EXPECT_EQ("a{ss}", message->signature());
85
86 mediascanner::Filter other;
87 message->reader() >> other;
88 EXPECT_EQ(empty, other);
89}
90
64int main(int argc, char **argv) {91int main(int argc, char **argv) {
65 ::testing::InitGoogleTest(&argc, argv);92 ::testing::InitGoogleTest(&argc, argv);
66 return RUN_ALL_TESTS();93 return RUN_ALL_TESTS();
6794
=== modified file 'test/test_mediastore.cc'
--- test/test_mediastore.cc 2014-05-29 09:17:39 +0000
+++ test/test_mediastore.cc 2014-05-29 09:17:39 +0000
@@ -20,6 +20,7 @@
20#include <mediascanner/MediaFile.hh>20#include <mediascanner/MediaFile.hh>
21#include <mediascanner/MediaFileBuilder.hh>21#include <mediascanner/MediaFileBuilder.hh>
22#include <mediascanner/Album.hh>22#include <mediascanner/Album.hh>
23#include <mediascanner/Filter.hh>
23#include <mediascanner/MediaStore.hh>24#include <mediascanner/MediaStore.hh>
24#include <mediascanner/internal/utils.hh>25#include <mediascanner/internal/utils.hh>
2526
@@ -617,34 +618,56 @@
617 store.insert(audio5);618 store.insert(audio5);
618 store.insert(audio6);619 store.insert(audio6);
619620
620 vector<MediaFile> tracks = store.listSongs();621 Filter filter;
622 vector<MediaFile> tracks = store.listSongs(filter);
621 ASSERT_EQ(6, tracks.size());623 ASSERT_EQ(6, tracks.size());
622 EXPECT_EQ("TitleOne", tracks[0].getTitle());624 EXPECT_EQ("TitleOne", tracks[0].getTitle());
623625
624 // Apply a limit626 // Apply a limit
625 tracks = store.listSongs("", "", "", 4);627 tracks = store.listSongs(filter, 4);
626 EXPECT_EQ(4, tracks.size());628 EXPECT_EQ(4, tracks.size());
627629
628 // List songs by artist630 // List songs by artist
629 tracks = store.listSongs("ArtistOne");631 filter.setArtist("ArtistOne");
632 tracks = store.listSongs(filter);
630 EXPECT_EQ(4, tracks.size());633 EXPECT_EQ(4, tracks.size());
631634
632 // List songs by album635 // List songs by album
633 tracks = store.listSongs("", "AlbumOne");636 filter.clear();
637 filter.setAlbum("AlbumOne");
638 tracks = store.listSongs(filter);
634 EXPECT_EQ(2, tracks.size());639 EXPECT_EQ(2, tracks.size());
635640
636 // List songs by album artist641 // List songs by album artist
637 tracks = store.listSongs("", "", "Various Artists");642 filter.clear();
643 filter.setAlbumArtist("Various Artists");
644 tracks = store.listSongs(filter);
638 EXPECT_EQ(2, tracks.size());645 EXPECT_EQ(2, tracks.size());
639646
640 // Combinations647 // Combinations
641 tracks = store.listSongs("ArtistOne", "AlbumOne", "");648 filter.clear();
642 EXPECT_EQ(2, tracks.size());649 filter.setArtist("ArtistOne");
643 tracks = store.listSongs("", "AlbumOne", "ArtistOne");650 filter.setAlbum("AlbumOne");
644 EXPECT_EQ(2, tracks.size());651 tracks = store.listSongs(filter);
645 tracks = store.listSongs("ArtistOne", "AlbumOne", "ArtistOne");652 EXPECT_EQ(2, tracks.size());
646 EXPECT_EQ(2, tracks.size());653
647 tracks = store.listSongs("ArtistOne", "", "ArtistOne");654 filter.clear();
655 filter.setAlbum("AlbumOne");
656 filter.setAlbumArtist("ArtistOne");
657 tracks = store.listSongs(filter);
658 EXPECT_EQ(2, tracks.size());
659
660 filter.clear();
661 filter.setArtist("ArtistOne");
662 filter.setAlbum("AlbumOne");
663 filter.setAlbumArtist("ArtistOne");
664 tracks = store.listSongs(filter);
665 EXPECT_EQ(2, tracks.size());
666
667 filter.clear();
668 filter.setArtist("ArtistOne");
669 filter.setAlbumArtist("ArtistOne");
670 tracks = store.listSongs(filter);
648 EXPECT_EQ(3, tracks.size());671 EXPECT_EQ(3, tracks.size());
649}672}
650673
@@ -687,24 +710,31 @@
687 store.insert(audio4);710 store.insert(audio4);
688 store.insert(audio5);711 store.insert(audio5);
689712
690 vector<Album> albums = store.listAlbums();713 Filter filter;
714 vector<Album> albums = store.listAlbums(filter);
691 ASSERT_EQ(4, albums.size());715 ASSERT_EQ(4, albums.size());
692 EXPECT_EQ("AlbumOne", albums[0].getTitle());716 EXPECT_EQ("AlbumOne", albums[0].getTitle());
693717
694 // test limit718 // test limit
695 albums = store.listAlbums("", "", 2);719 albums = store.listAlbums(filter, 2);
696 EXPECT_EQ(2, albums.size());720 EXPECT_EQ(2, albums.size());
697721
698 // Songs by artist722 // Songs by artist
699 albums = store.listAlbums("ArtistOne");723 filter.setArtist("ArtistOne");
724 albums = store.listAlbums(filter);
700 EXPECT_EQ(3, albums.size());725 EXPECT_EQ(3, albums.size());
701726
702 // Songs by album artist727 // Songs by album artist
703 albums = store.listAlbums("", "ArtistOne");728 filter.clear();
729 filter.setAlbumArtist("ArtistOne");
730 albums = store.listAlbums(filter);
704 EXPECT_EQ(2, albums.size());731 EXPECT_EQ(2, albums.size());
705732
706 // Combination733 // Combination
707 albums = store.listAlbums("ArtistOne", "Various Artists");734 filter.clear();
735 filter.setArtist("ArtistOne");
736 filter.setAlbumArtist("Various Artists");
737 albums = store.listAlbums(filter);
708 EXPECT_EQ(1, albums.size());738 EXPECT_EQ(1, albums.size());
709}739}
710740
@@ -747,17 +777,18 @@
747 store.insert(audio4);777 store.insert(audio4);
748 store.insert(audio5);778 store.insert(audio5);
749779
750 vector<string> artists = store.listArtists(false);780 Filter filter;
781 vector<string> artists = store.listArtists(filter);
751 ASSERT_EQ(2, artists.size());782 ASSERT_EQ(2, artists.size());
752 EXPECT_EQ("ArtistOne", artists[0]);783 EXPECT_EQ("ArtistOne", artists[0]);
753 EXPECT_EQ("ArtistTwo", artists[1]);784 EXPECT_EQ("ArtistTwo", artists[1]);
754785
755 // Test limit clause786 // Test limit clause
756 artists = store.listArtists(false, 1);787 artists = store.listArtists(filter, 1);
757 EXPECT_EQ(1, artists.size());788 EXPECT_EQ(1, artists.size());
758789
759 // List "album artists"790 // List "album artists"
760 artists = store.listArtists(true);791 artists = store.listAlbumArtists(filter);
761 ASSERT_EQ(3, artists.size());792 ASSERT_EQ(3, artists.size());
762 EXPECT_EQ("ArtistOne", artists[0]);793 EXPECT_EQ("ArtistOne", artists[0]);
763 EXPECT_EQ("ArtistTwo", artists[1]);794 EXPECT_EQ("ArtistTwo", artists[1]);

Subscribers

People subscribed via source and target branches