Add "group by" support to the library, and improve the whole library model to make it more robust.
Still todo: the "Group by advanced..." dialog, unit tests. Updates issue #94.
This commit is contained in:
parent
df38ebf9d9
commit
4c42813d9f
683
src/library.cpp
683
src/library.cpp
@ -125,41 +125,67 @@ void Library::SongsDiscovered(const SongList& songs) {
|
||||
if (!query_options_.Matches(song))
|
||||
continue;
|
||||
|
||||
LibraryItem* artist = NULL;
|
||||
LibraryItem* album = NULL;
|
||||
// Find parent containers in the tree
|
||||
LibraryItem* container = root_;
|
||||
for (int i=0 ; i<3 ; ++i) {
|
||||
QueryOptions::GroupBy type = query_options_.group_by[i];
|
||||
if (type == QueryOptions::GroupBy_None) break;
|
||||
|
||||
if (song.is_compilation()) {
|
||||
if (compilation_artist_node_ == NULL)
|
||||
CreateCompilationArtistNode(true);
|
||||
artist = compilation_artist_node_;
|
||||
} else {
|
||||
if (artist_nodes_.contains(song.artist()))
|
||||
artist = artist_nodes_[song.artist()];
|
||||
else {
|
||||
artist = CreateArtistNode(true, song.artist());
|
||||
// Special case: if we're at the top level and the song is a compilation
|
||||
// and the top level is Artists, then we want the Various Artists node :(
|
||||
if (i == 0 && type == QueryOptions::GroupBy_Artist && song.is_compilation()) {
|
||||
if (compilation_artist_node_ == NULL)
|
||||
CreateCompilationArtistNode(true, root_);
|
||||
container = compilation_artist_node_;
|
||||
} else {
|
||||
// Otherwise find the proper container based on the item's key
|
||||
QString key;
|
||||
switch (type) {
|
||||
case QueryOptions::GroupBy_Album: key = song.album(); break;
|
||||
case QueryOptions::GroupBy_Artist: key = song.artist(); break;
|
||||
case QueryOptions::GroupBy_Composer: key = song.composer(); break;
|
||||
case QueryOptions::GroupBy_Genre: key = song.genre(); break;
|
||||
case QueryOptions::GroupBy_Year:
|
||||
key = QString::number(qMax(0, song.year())); break;
|
||||
case QueryOptions::GroupBy_YearAlbum:
|
||||
key = PrettyYearAlbum(qMax(0, song.year()), song.album()); break;
|
||||
case QueryOptions::GroupBy_None: Q_ASSERT(0); break;
|
||||
}
|
||||
|
||||
if (!container_nodes_[i].contains(key)) {
|
||||
// Create the container
|
||||
container_nodes_[i][key] =
|
||||
ItemFromSong(type, true, i == 0, container, song);
|
||||
container_nodes_[i][key]->container_level = i;
|
||||
}
|
||||
container = container_nodes_[i][key];
|
||||
}
|
||||
|
||||
// If we just created the damn thing then we don't need to continue into
|
||||
// it any further.
|
||||
if (!container->lazy_loaded)
|
||||
break;
|
||||
}
|
||||
|
||||
if (artist->lazy_loaded) {
|
||||
album = artist->ChildByKey(song.album());
|
||||
if (album == NULL)
|
||||
album = CreateAlbumNode(true, song.album(), artist, song.is_compilation(),
|
||||
song.art_automatic(), song.art_manual(), artist->key);
|
||||
if (!container->lazy_loaded)
|
||||
continue;
|
||||
|
||||
if (album->lazy_loaded)
|
||||
CreateSongNode(true, song, album);
|
||||
}
|
||||
// We've gone all the way down to the lowest level, so now we have to
|
||||
// create the song in the container.
|
||||
song_nodes_[song.id()] =
|
||||
ItemFromSong(QueryOptions::GroupBy_None, true, false, container, song);
|
||||
}
|
||||
}
|
||||
|
||||
LibraryItem* Library::CreateCompilationArtistNode(bool signal) {
|
||||
LibraryItem* parent = root_;
|
||||
LibraryItem* Library::CreateCompilationArtistNode(bool signal, LibraryItem* parent) {
|
||||
if (signal)
|
||||
beginInsertRows(ItemToIndex(parent), parent->children.count(), parent->children.count());
|
||||
|
||||
compilation_artist_node_ =
|
||||
new LibraryItem(LibraryItem::Type_CompilationArtist, tr("Various Artists"), parent);
|
||||
new LibraryItem(LibraryItem::Type_Container, parent);
|
||||
compilation_artist_node_->key = tr("Various Artists");
|
||||
compilation_artist_node_->sort_text = " various";
|
||||
compilation_artist_node_->container_level = parent->container_level + 1;
|
||||
|
||||
if (signal)
|
||||
endInsertRows();
|
||||
@ -167,191 +193,133 @@ LibraryItem* Library::CreateCompilationArtistNode(bool signal) {
|
||||
return compilation_artist_node_;
|
||||
}
|
||||
|
||||
LibraryItem* Library::CreateArtistNode(bool signal, const QString& name) {
|
||||
LibraryItem* parent = root_;
|
||||
if (signal)
|
||||
beginInsertRows(ItemToIndex(parent), parent->children.count(), parent->children.count());
|
||||
QString Library::DividerKey(QueryOptions::GroupBy type,
|
||||
LibraryItem* item) const {
|
||||
if (item->sort_text.isEmpty())
|
||||
return QString();
|
||||
|
||||
LibraryItem* ret = new LibraryItem(LibraryItem::Type_Artist, name, parent);
|
||||
ret->display_text = PrettyArtist(name);
|
||||
ret->sort_text = SortTextForArtist(name);
|
||||
switch (type) {
|
||||
case QueryOptions::GroupBy_Album:
|
||||
case QueryOptions::GroupBy_Artist:
|
||||
case QueryOptions::GroupBy_Composer:
|
||||
case QueryOptions::GroupBy_Genre:
|
||||
if (item->sort_text[0].isDigit())
|
||||
return "0";
|
||||
if (item->sort_text[0] == ' ')
|
||||
return QString();
|
||||
return QString(item->sort_text[0]);
|
||||
|
||||
artist_nodes_[name] = ret;
|
||||
case QueryOptions::GroupBy_Year:
|
||||
return QString::number(item->sort_text.toInt() / 10 * 10);
|
||||
|
||||
if (signal)
|
||||
endInsertRows();
|
||||
case QueryOptions::GroupBy_YearAlbum:
|
||||
return QString::number(item->metadata.year());
|
||||
|
||||
if (!name.isEmpty()) {
|
||||
QChar divider_char = DividerChar(ret->sort_text);
|
||||
|
||||
if (!divider_char.isNull() && !divider_nodes_.contains(divider_char)) {
|
||||
if (signal)
|
||||
beginInsertRows(ItemToIndex(parent), parent->children.count(), parent->children.count());
|
||||
|
||||
LibraryItem* divider =
|
||||
new LibraryItem(LibraryItem::Type_Divider, QString(divider_char), root_);
|
||||
divider->lazy_loaded = true;
|
||||
|
||||
if (divider_char == '0')
|
||||
divider->display_text = "0-9";
|
||||
|
||||
divider_nodes_[divider_char] = divider;
|
||||
|
||||
if (signal)
|
||||
endInsertRows();
|
||||
}
|
||||
case QueryOptions::GroupBy_None:
|
||||
default:
|
||||
Q_ASSERT(0);
|
||||
return QString();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QChar Library::DividerChar(const QString& sort_text) const {
|
||||
if (sort_text.isEmpty())
|
||||
return QChar();
|
||||
QString Library::DividerDisplayText(QueryOptions::GroupBy type,
|
||||
const QString& key) const {
|
||||
switch (type) {
|
||||
case QueryOptions::GroupBy_Album:
|
||||
case QueryOptions::GroupBy_Artist:
|
||||
case QueryOptions::GroupBy_Composer:
|
||||
case QueryOptions::GroupBy_Genre:
|
||||
if (key == "0")
|
||||
return "0-9";
|
||||
// fallthrough
|
||||
|
||||
QChar ret = sort_text[0];
|
||||
if (ret.isDigit())
|
||||
return '0';
|
||||
case QueryOptions::GroupBy_Year:
|
||||
case QueryOptions::GroupBy_YearAlbum:
|
||||
return key;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LibraryItem* Library::CreateAlbumNode(bool signal, const QString& name,
|
||||
LibraryItem* parent, bool compilation,
|
||||
const QString& art_automatic,
|
||||
const QString& art_manual,
|
||||
const QString& artist) {
|
||||
if (signal)
|
||||
beginInsertRows(ItemToIndex(parent), parent->children.count(), parent->children.count());
|
||||
|
||||
LibraryItem* ret = new LibraryItem(
|
||||
compilation ? LibraryItem::Type_CompilationAlbum
|
||||
: LibraryItem::Type_Album,
|
||||
name, parent);
|
||||
|
||||
ret->display_text = PrettyAlbum(name);
|
||||
ret->sort_text = SortTextForAlbum(name);
|
||||
|
||||
// TODO: These should be async
|
||||
/*if (!art_manual.isNull())
|
||||
ret->cover_art.load(art_manual);
|
||||
if (!art_automatic.isNull() && ret->cover_art.isNull())
|
||||
ret->cover_art.load(art_automatic);*/
|
||||
|
||||
ret->artist = compilation ? QString() : artist;
|
||||
|
||||
if (signal)
|
||||
endInsertRows();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
LibraryItem* Library::CreateSongNode(bool signal, const Song& song, LibraryItem* parent) {
|
||||
if (signal)
|
||||
beginInsertRows(ItemToIndex(parent), parent->children.count(), parent->children.count());
|
||||
|
||||
LibraryItem* ret = new LibraryItem(LibraryItem::Type_Song, song.title(), parent);
|
||||
ret->lazy_loaded = true;
|
||||
ret->display_text = song.PrettyTitleWithArtist();
|
||||
ret->song = song;
|
||||
|
||||
song_nodes_[song.id()] = ret;
|
||||
|
||||
if (signal)
|
||||
endInsertRows();
|
||||
|
||||
return ret;
|
||||
case QueryOptions::GroupBy_None:
|
||||
default:
|
||||
Q_ASSERT(0);
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
void Library::SongsDeleted(const SongList& songs) {
|
||||
// Delete song nodes
|
||||
QSet<LibraryItem*> parents;
|
||||
foreach (const Song& song, songs) {
|
||||
if (song_nodes_.contains(song.id())) {
|
||||
LibraryItem* node = song_nodes_[song.id()];
|
||||
|
||||
if (node->parent != root_)
|
||||
parents << node->parent;
|
||||
|
||||
beginRemoveRows(ItemToIndex(node->parent), node->row, node->row);
|
||||
node->parent->Delete(node->row);
|
||||
song_nodes_.remove(song.id());
|
||||
endRemoveRows();
|
||||
} else {
|
||||
// If we get here it means some of the songs we want to delete haven't
|
||||
// been lazy-loaded yet. This is bad, because it would mean that to
|
||||
// clean up empty parents we would need to lazy-load them all
|
||||
// individually. This can take a very long time, so better to just
|
||||
// reset the model.
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete now-empty album nodes
|
||||
foreach (const Song& song, songs) {
|
||||
LibraryItem* artist = NULL;
|
||||
// Now delete empty parents
|
||||
QSet<QString> divider_keys;
|
||||
while (!parents.isEmpty()) {
|
||||
foreach (LibraryItem* node, parents) {
|
||||
parents.remove(node);
|
||||
if (node->children.count() != 0)
|
||||
continue;
|
||||
|
||||
if (song.is_compilation() && compilation_artist_node_ &&
|
||||
compilation_artist_node_->lazy_loaded)
|
||||
artist = compilation_artist_node_;
|
||||
else if (!song.is_compilation() &&
|
||||
artist_nodes_.contains(song.artist()) &&
|
||||
artist_nodes_[song.artist()]->lazy_loaded)
|
||||
artist = artist_nodes_[song.artist()];
|
||||
// Consider its parent for the next round
|
||||
if (node->parent != root_)
|
||||
parents << node->parent;
|
||||
|
||||
if (artist == NULL)
|
||||
continue;
|
||||
// Maybe consider its divider node
|
||||
if (node->container_level == 0)
|
||||
divider_keys << DividerKey(query_options_.group_by[0], node);
|
||||
|
||||
LibraryItem* node = artist->ChildByKey(song.album());
|
||||
if (!node)
|
||||
continue;
|
||||
// Special case the Various Artists node
|
||||
if (node == compilation_artist_node_)
|
||||
compilation_artist_node_ = NULL;
|
||||
else
|
||||
container_nodes_[node->container_level].remove(node->key);
|
||||
|
||||
LazyPopulate(node);
|
||||
|
||||
if (node->children.count() == 0) {
|
||||
// It was empty - delete it
|
||||
beginRemoveRows(ItemToIndex(node->parent), node->row, node->row);
|
||||
node->parent->Delete(node->row);
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
// Delete now-empty artist nodes
|
||||
foreach (const Song& song, songs) {
|
||||
// Was it a compilation?
|
||||
LibraryItem* node = NULL;
|
||||
if (song.is_compilation())
|
||||
node = compilation_artist_node_;
|
||||
else
|
||||
node = artist_nodes_.contains(song.artist()) ? artist_nodes_[song.artist()] : NULL;
|
||||
// Delete empty dividers
|
||||
foreach (const QString& divider_key, divider_keys) {
|
||||
if (!divider_nodes_.contains(divider_key))
|
||||
continue;
|
||||
|
||||
if (node) {
|
||||
LazyPopulate(node);
|
||||
|
||||
if (node->children.count() == 0) {
|
||||
beginRemoveRows(ItemToIndex(node->parent), node->row, node->row);
|
||||
node->parent->Delete(node->row);
|
||||
|
||||
if (song.is_compilation())
|
||||
compilation_artist_node_ = NULL;
|
||||
else
|
||||
artist_nodes_.remove(song.artist());
|
||||
|
||||
endRemoveRows();
|
||||
bool found = false;
|
||||
foreach (LibraryItem* node, container_nodes_[0].values()) {
|
||||
if (DividerKey(query_options_.group_by[0], node) == divider_key) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete now-empty dividers
|
||||
foreach (const Song& song, songs) {
|
||||
QString sort_text(SortTextForArtist(song.artist()));
|
||||
QChar divider_char(DividerChar(sort_text));
|
||||
if (!divider_char.isNull() && !sort_text.isEmpty() &&
|
||||
divider_nodes_.contains(divider_char)) {
|
||||
bool found = false;
|
||||
foreach (LibraryItem* artist_node, artist_nodes_.values()) {
|
||||
if (artist_node->sort_text.startsWith(divider_char)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
continue;
|
||||
|
||||
if (!found) {
|
||||
int row = divider_nodes_[divider_char]->row;
|
||||
beginRemoveRows(ItemToIndex(root_), row, row);
|
||||
root_->Delete(row);
|
||||
endRemoveRows();
|
||||
divider_nodes_.remove(divider_char);
|
||||
}
|
||||
}
|
||||
// Remove the divider
|
||||
int row = divider_nodes_[divider_key]->row;
|
||||
beginRemoveRows(ItemToIndex(root_), row, row);
|
||||
root_->Delete(row);
|
||||
endRemoveRows();
|
||||
divider_nodes_.remove(divider_key);
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,113 +330,337 @@ QVariant Library::data(const QModelIndex& index, int role) const {
|
||||
}
|
||||
|
||||
QVariant Library::data(const LibraryItem* item, int role) const {
|
||||
QueryOptions::GroupBy container_type =
|
||||
item->type == LibraryItem::Type_Container ?
|
||||
query_options_.group_by[item->container_level] : QueryOptions::GroupBy_None;
|
||||
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return item->DisplayText();
|
||||
|
||||
case Qt::DecorationRole:
|
||||
switch (item->type) {
|
||||
case LibraryItem::Type_Album:
|
||||
case LibraryItem::Type_CompilationAlbum: {
|
||||
// TODO
|
||||
/*if (item->cover_art.isNull())
|
||||
return no_cover_icon_;
|
||||
else
|
||||
return QIcon(item->cover_art);*/
|
||||
|
||||
return album_icon_;
|
||||
}
|
||||
case LibraryItem::Type_Artist:
|
||||
case LibraryItem::Type_CompilationArtist:
|
||||
return artist_icon_;
|
||||
switch (item->type)
|
||||
case LibraryItem::Type_Container:
|
||||
switch (container_type) {
|
||||
case QueryOptions::GroupBy_Album:
|
||||
return album_icon_;
|
||||
case QueryOptions::GroupBy_Artist:
|
||||
return artist_icon_;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Role_Type:
|
||||
return item->type;
|
||||
|
||||
case Role_ContainerType:
|
||||
return container_type;
|
||||
|
||||
case Role_Key:
|
||||
return item->key;
|
||||
|
||||
case Role_Artist:
|
||||
return item->artist;
|
||||
return item->metadata.artist();
|
||||
|
||||
case Role_SortText:
|
||||
if (item->type == LibraryItem::Type_Song)
|
||||
return item->song.disc() * 1000 + item->song.track();
|
||||
return item->metadata.disc() * 1000 + item->metadata.track();
|
||||
return item->SortText();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void Library::LazyPopulate(LibraryItem* item) {
|
||||
if (item->lazy_loaded)
|
||||
void Library::LazyPopulate(LibraryItem* parent, bool signal) {
|
||||
if (parent->lazy_loaded)
|
||||
return;
|
||||
parent->lazy_loaded = true;
|
||||
|
||||
switch (item->type) {
|
||||
case LibraryItem::Type_CompilationArtist:
|
||||
foreach (const LibraryBackendInterface::Album& album,
|
||||
backend_->Worker()->GetCompilationAlbums(query_options_))
|
||||
CreateAlbumNode(false, album.album_name, item, true, album.art_automatic, album.art_manual, album.artist);
|
||||
break;
|
||||
// Information about what we want the children to be
|
||||
int child_level = parent->container_level + 1;
|
||||
QueryOptions::GroupBy child_type = query_options_.group_by[child_level];
|
||||
|
||||
case LibraryItem::Type_CompilationAlbum:
|
||||
foreach (const Song& song, backend_->Worker()->GetCompilationSongs(item->key, query_options_))
|
||||
CreateSongNode(false, song, item);
|
||||
break;
|
||||
// Initialise the query
|
||||
LibraryQuery q(query_options_);
|
||||
InitQuery(child_type, &q);
|
||||
|
||||
case LibraryItem::Type_Artist:
|
||||
foreach (const LibraryBackendInterface::Album& album,
|
||||
backend_->Worker()->GetAlbumsByArtist(item->key, query_options_))
|
||||
CreateAlbumNode(false, album.album_name, item, false, album.art_automatic, album.art_manual, album.artist);
|
||||
break;
|
||||
|
||||
case LibraryItem::Type_Album:
|
||||
foreach (const Song& song, backend_->Worker()->GetSongs(item->parent->key, item->key, query_options_))
|
||||
CreateSongNode(false, song, item);
|
||||
break;
|
||||
|
||||
default:
|
||||
qWarning("Tried to LazyPopulate a bad item type");
|
||||
break;
|
||||
// Top-level artists is special - we don't want compilation albums appearing
|
||||
if (child_level == 0 && child_type == QueryOptions::GroupBy_Artist) {
|
||||
q.AddCompilationRequirement(false);
|
||||
}
|
||||
|
||||
item->lazy_loaded = true;
|
||||
// Walk up through the item's parents adding filters as necessary
|
||||
LibraryItem* p = parent;
|
||||
while (p != root_) {
|
||||
FilterQuery(query_options_.group_by[p->container_level], p, &q);
|
||||
p = p->parent;
|
||||
}
|
||||
|
||||
// Execute the query
|
||||
if (!backend_->Worker()->ExecQuery(&q))
|
||||
return;
|
||||
|
||||
// Step through the results
|
||||
while (q.Next()) {
|
||||
// Create the item - it will get inserted into the model here
|
||||
LibraryItem* item =
|
||||
ItemFromQuery(child_type, signal, child_level == 0, parent, q);
|
||||
item->container_level = child_level;
|
||||
|
||||
// Save a pointer to it for later
|
||||
if (child_type == QueryOptions::GroupBy_None)
|
||||
song_nodes_[item->metadata.id()] = item;
|
||||
else
|
||||
container_nodes_[child_level][item->key] = item;
|
||||
}
|
||||
}
|
||||
|
||||
void Library::Reset() {
|
||||
delete root_;
|
||||
artist_nodes_.clear();
|
||||
song_nodes_.clear();
|
||||
container_nodes_[0].clear();
|
||||
container_nodes_[1].clear();
|
||||
container_nodes_[2].clear();
|
||||
divider_nodes_.clear();
|
||||
compilation_artist_node_ = NULL;
|
||||
|
||||
root_ = new LibraryItem(this);
|
||||
root_->lazy_loaded = true;
|
||||
root_->lazy_loaded = false;
|
||||
|
||||
// Various artists?
|
||||
if (backend_->Worker()->HasCompilations(query_options_))
|
||||
CreateCompilationArtistNode(false);
|
||||
if (query_options_.group_by[0] == QueryOptions::GroupBy_Artist &&
|
||||
backend_->Worker()->HasCompilations(query_options_))
|
||||
CreateCompilationArtistNode(false, root_);
|
||||
|
||||
// Populate artists
|
||||
foreach (const QString& artist, backend_->Worker()->GetAllArtists(query_options_))
|
||||
CreateArtistNode(false, artist);
|
||||
// Populate top level
|
||||
LazyPopulate(root_, false);
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
QString Library::PrettyArtist(QString artist) const {
|
||||
if (artist.isEmpty()) {
|
||||
artist = tr("Unknown");
|
||||
void Library::InitQuery(QueryOptions::GroupBy type, LibraryQuery* q) {
|
||||
switch (type) {
|
||||
case QueryOptions::GroupBy_Artist:
|
||||
q->SetColumnSpec("DISTINCT artist");
|
||||
break;
|
||||
case QueryOptions::GroupBy_Album:
|
||||
q->SetColumnSpec("DISTINCT album");
|
||||
break;
|
||||
case QueryOptions::GroupBy_Composer:
|
||||
q->SetColumnSpec("DISTINCT composer");
|
||||
break;
|
||||
case QueryOptions::GroupBy_YearAlbum:
|
||||
q->SetColumnSpec("DISTINCT year, album");
|
||||
break;
|
||||
case QueryOptions::GroupBy_Year:
|
||||
q->SetColumnSpec("DISTINCT year");
|
||||
break;
|
||||
case QueryOptions::GroupBy_Genre:
|
||||
q->SetColumnSpec("DISTINCT genre");
|
||||
break;
|
||||
case QueryOptions::GroupBy_None:
|
||||
q->SetColumnSpec("ROWID, " + QString(Song::kColumnSpec));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Library::FilterQuery(QueryOptions::GroupBy type, LibraryItem* item,
|
||||
LibraryQuery* q) {
|
||||
switch (type) {
|
||||
case QueryOptions::GroupBy_Artist:
|
||||
if (item == compilation_artist_node_)
|
||||
q->AddCompilationRequirement(true);
|
||||
else {
|
||||
if (item->container_level == 0) // Stupid hack
|
||||
q->AddCompilationRequirement(false);
|
||||
q->AddWhere("artist", item->key);
|
||||
}
|
||||
break;
|
||||
case QueryOptions::GroupBy_Album:
|
||||
q->AddWhere("album", item->key);
|
||||
break;
|
||||
case QueryOptions::GroupBy_YearAlbum:
|
||||
q->AddWhere("year", item->metadata.year());
|
||||
q->AddWhere("album", item->metadata.album());
|
||||
break;
|
||||
case QueryOptions::GroupBy_Year:
|
||||
q->AddWhere("year", item->key);
|
||||
break;
|
||||
case QueryOptions::GroupBy_Composer:
|
||||
q->AddWhere("composer", item->key);
|
||||
break;
|
||||
case QueryOptions::GroupBy_Genre:
|
||||
q->AddWhere("genre", item->key);
|
||||
break;
|
||||
case QueryOptions::GroupBy_None:
|
||||
Q_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LibraryItem* Library::InitItem(QueryOptions::GroupBy type,
|
||||
bool signal, LibraryItem *parent) {
|
||||
LibraryItem::Type item_type =
|
||||
type == QueryOptions::GroupBy_None ? LibraryItem::Type_Song :
|
||||
LibraryItem::Type_Container;
|
||||
|
||||
if (signal)
|
||||
beginInsertRows(ItemToIndex(parent),
|
||||
parent->children.count(),parent->children.count());
|
||||
|
||||
// Initialise the item depending on what type it's meant to be
|
||||
return new LibraryItem(item_type, parent);
|
||||
}
|
||||
|
||||
LibraryItem* Library::ItemFromQuery(QueryOptions::GroupBy type,
|
||||
bool signal, bool create_divider,
|
||||
LibraryItem* parent, const LibraryQuery& q) {
|
||||
LibraryItem* item = InitItem(type, signal, parent);
|
||||
int year = 0;
|
||||
|
||||
switch (type) {
|
||||
case QueryOptions::GroupBy_Artist:
|
||||
item->key = q.Value(0).toString();
|
||||
item->display_text = TextOrUnknown(item->key);
|
||||
item->sort_text = SortTextForArtist(item->key);
|
||||
break;
|
||||
|
||||
case QueryOptions::GroupBy_YearAlbum:
|
||||
year = qMax(0, q.Value(0).toInt());
|
||||
item->metadata.set_year(year);
|
||||
item->metadata.set_album(q.Value(1).toString());
|
||||
item->key = PrettyYearAlbum(year, item->metadata.album());
|
||||
item->sort_text = SortTextForYear(year) + item->metadata.album();
|
||||
break;
|
||||
|
||||
case QueryOptions::GroupBy_Year:
|
||||
year = qMax(0, q.Value(0).toInt());
|
||||
item->key = QString::number(year);
|
||||
item->sort_text = SortTextForYear(year);
|
||||
break;
|
||||
|
||||
case QueryOptions::GroupBy_Composer:
|
||||
case QueryOptions::GroupBy_Genre:
|
||||
case QueryOptions::GroupBy_Album:
|
||||
item->key = q.Value(0).toString();
|
||||
item->display_text = TextOrUnknown(item->key);
|
||||
item->sort_text = SortText(item->key);
|
||||
break;
|
||||
|
||||
case QueryOptions::GroupBy_None:
|
||||
item->metadata.InitFromQuery(q);
|
||||
item->key = item->metadata.title();
|
||||
item->display_text = item->metadata.PrettyTitleWithArtist();
|
||||
break;
|
||||
}
|
||||
|
||||
return artist;
|
||||
FinishItem(type, signal, create_divider, parent, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
LibraryItem* Library::ItemFromSong(QueryOptions::GroupBy type,
|
||||
bool signal, bool create_divider,
|
||||
LibraryItem* parent, const Song& s) {
|
||||
LibraryItem* item = InitItem(type, signal, parent);
|
||||
int year = 0;
|
||||
|
||||
switch (type) {
|
||||
case QueryOptions::GroupBy_Artist:
|
||||
item->key = s.artist();
|
||||
item->display_text = TextOrUnknown(item->key);
|
||||
item->sort_text = SortTextForArtist(item->key);
|
||||
break;
|
||||
|
||||
case QueryOptions::GroupBy_YearAlbum:
|
||||
year = qMax(0, s.year());
|
||||
item->metadata.set_year(year);
|
||||
item->metadata.set_album(s.album());
|
||||
item->key = PrettyYearAlbum(year, s.album());
|
||||
item->sort_text = SortTextForYear(year) + s.album();
|
||||
break;
|
||||
|
||||
case QueryOptions::GroupBy_Year:
|
||||
year = qMax(0, s.year());
|
||||
item->key = QString::number(year);
|
||||
item->sort_text = SortTextForYear(year);
|
||||
break;
|
||||
|
||||
case QueryOptions::GroupBy_Composer: item->key = s.composer();
|
||||
case QueryOptions::GroupBy_Genre: if (item->key.isNull()) item->key = s.genre();
|
||||
case QueryOptions::GroupBy_Album: if (item->key.isNull()) item->key = s.album();
|
||||
item->display_text = TextOrUnknown(item->key);
|
||||
item->sort_text = SortText(item->key);
|
||||
break;
|
||||
|
||||
case QueryOptions::GroupBy_None:
|
||||
item->metadata = s;
|
||||
item->key = s.title();
|
||||
item->display_text = s.PrettyTitleWithArtist();
|
||||
break;
|
||||
}
|
||||
|
||||
FinishItem(type, signal, create_divider, parent, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
void Library::FinishItem(QueryOptions::GroupBy type,
|
||||
bool signal, bool create_divider,
|
||||
LibraryItem *parent, LibraryItem *item) {
|
||||
if (type == QueryOptions::GroupBy_None)
|
||||
item->lazy_loaded = true;
|
||||
|
||||
if (signal)
|
||||
endInsertRows();
|
||||
|
||||
// Create the divider entry if we're supposed to
|
||||
if (create_divider) {
|
||||
QString divider_key = DividerKey(type, item);
|
||||
|
||||
if (!divider_key.isEmpty() && !divider_nodes_.contains(divider_key)) {
|
||||
if (signal)
|
||||
beginInsertRows(ItemToIndex(parent), parent->children.count(),
|
||||
parent->children.count());
|
||||
|
||||
LibraryItem* divider =
|
||||
new LibraryItem(LibraryItem::Type_Divider, root_);
|
||||
divider->key = divider_key;
|
||||
divider->display_text = DividerDisplayText(type, divider_key);
|
||||
divider->lazy_loaded = true;
|
||||
|
||||
divider_nodes_[divider_key] = divider;
|
||||
|
||||
if (signal)
|
||||
endInsertRows();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString Library::TextOrUnknown(const QString& text) const {
|
||||
if (text.isEmpty()) {
|
||||
return tr("Unknown");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
QString Library::PrettyYearAlbum(int year, const QString& album) const {
|
||||
return QString::number(year) + " - " + TextOrUnknown(album);
|
||||
}
|
||||
|
||||
QString Library::SortText(QString text) const {
|
||||
if (text.isEmpty()) {
|
||||
text = " unknown";
|
||||
} else {
|
||||
text = text.toLower();
|
||||
}
|
||||
text = text.remove(QRegExp("[^\\w ]"));
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
QString Library::SortTextForArtist(QString artist) const {
|
||||
artist = SortTextForAlbum(artist);
|
||||
artist = SortText(artist);
|
||||
|
||||
if (artist.startsWith("the ")) {
|
||||
artist = artist.right(artist.length() - 4) + ", the";
|
||||
@ -477,32 +669,15 @@ QString Library::SortTextForArtist(QString artist) const {
|
||||
return artist;
|
||||
}
|
||||
|
||||
QString Library::PrettyAlbum(QString album) const {
|
||||
if (album.isEmpty()) {
|
||||
album = tr("Unknown");
|
||||
}
|
||||
|
||||
return album;
|
||||
}
|
||||
|
||||
QString Library::SortTextForAlbum(QString album) const {
|
||||
if (album.isEmpty()) {
|
||||
album = " unknown";
|
||||
} else {
|
||||
album = album.toLower();
|
||||
}
|
||||
album = album.remove(QRegExp("[^\\w ]"));
|
||||
|
||||
return album;
|
||||
QString Library::SortTextForYear(int year) const {
|
||||
QString str = QString::number(year);
|
||||
return QString("0").repeated(qMax(0, 4 - str.length())) + str;
|
||||
}
|
||||
|
||||
Qt::ItemFlags Library::flags(const QModelIndex& index) const {
|
||||
switch (IndexToItem(index)->type) {
|
||||
case LibraryItem::Type_Album:
|
||||
case LibraryItem::Type_Artist:
|
||||
case LibraryItem::Type_Song:
|
||||
case LibraryItem::Type_CompilationAlbum:
|
||||
case LibraryItem::Type_CompilationArtist:
|
||||
case LibraryItem::Type_Container:
|
||||
return Qt::ItemIsSelectable |
|
||||
Qt::ItemIsEnabled |
|
||||
Qt::ItemIsDragEnabled;
|
||||
@ -541,10 +716,7 @@ bool Library::CompareItems(const LibraryItem* a, const LibraryItem* b) const {
|
||||
|
||||
void Library::GetChildSongs(LibraryItem* item, QList<QUrl>* urls, SongList* songs) const {
|
||||
switch (item->type) {
|
||||
case LibraryItem::Type_Album:
|
||||
case LibraryItem::Type_Artist:
|
||||
case LibraryItem::Type_CompilationAlbum:
|
||||
case LibraryItem::Type_CompilationArtist: {
|
||||
case LibraryItem::Type_Container: {
|
||||
const_cast<Library*>(this)->LazyPopulate(item);
|
||||
|
||||
QList<LibraryItem*> children = item->children;
|
||||
@ -557,8 +729,8 @@ void Library::GetChildSongs(LibraryItem* item, QList<QUrl>* urls, SongList* song
|
||||
}
|
||||
|
||||
case LibraryItem::Type_Song:
|
||||
urls->append(QUrl::fromLocalFile(item->song.filename()));
|
||||
songs->append(item->song);
|
||||
urls->append(QUrl::fromLocalFile(item->metadata.filename()));
|
||||
songs->append(item->metadata);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -594,3 +766,12 @@ bool Library::canFetchMore(const QModelIndex &parent) const {
|
||||
LibraryItem* item = IndexToItem(parent);
|
||||
return !item->lazy_loaded;
|
||||
}
|
||||
|
||||
void Library::SetGroupBy(QueryOptions::GroupBy g[3]) {
|
||||
query_options_.group_by[0] = g[0];
|
||||
query_options_.group_by[1] = g[1];
|
||||
query_options_.group_by[2] = g[2];
|
||||
|
||||
if (!waiting_for_threads_)
|
||||
Reset();
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ class Library : public SimpleTreeModel<LibraryItem> {
|
||||
|
||||
enum {
|
||||
Role_Type = Qt::UserRole + 1,
|
||||
Role_ContainerType,
|
||||
Role_SortText,
|
||||
Role_Key,
|
||||
Role_Artist,
|
||||
@ -80,9 +81,11 @@ class Library : public SimpleTreeModel<LibraryItem> {
|
||||
public slots:
|
||||
void SetFilterAge(int age);
|
||||
void SetFilterText(const QString& text);
|
||||
void SetGroupBy(QueryOptions::GroupBy g[3]);
|
||||
|
||||
protected:
|
||||
void LazyPopulate(LibraryItem* item);
|
||||
void LazyPopulate(LibraryItem* item) { LazyPopulate(item, false); }
|
||||
void LazyPopulate(LibraryItem* item, bool signal);
|
||||
|
||||
private slots:
|
||||
// From LibraryBackend
|
||||
@ -97,25 +100,37 @@ class Library : public SimpleTreeModel<LibraryItem> {
|
||||
private:
|
||||
void Initialise();
|
||||
|
||||
LibraryItem* CreateCompilationArtistNode(bool signal);
|
||||
LibraryItem* CreateArtistNode(bool signal, const QString& name);
|
||||
LibraryItem* CreateAlbumNode(bool signal, const QString& name,
|
||||
LibraryItem* parent, bool compilation,
|
||||
const QString& art_automatic,
|
||||
const QString& art_manual,
|
||||
const QString& artist);
|
||||
LibraryItem* CreateSongNode(bool signal, const Song& song, LibraryItem* parent);
|
||||
// Functions for working with queries and creating items
|
||||
void InitQuery(QueryOptions::GroupBy type, LibraryQuery* q);
|
||||
void FilterQuery(QueryOptions::GroupBy type,
|
||||
LibraryItem* item,LibraryQuery* q);
|
||||
LibraryItem* ItemFromQuery(QueryOptions::GroupBy type,
|
||||
bool signal, bool create_divider,
|
||||
LibraryItem* parent, const LibraryQuery& q);
|
||||
LibraryItem* ItemFromSong(QueryOptions::GroupBy type,
|
||||
bool signal, bool create_divider,
|
||||
LibraryItem* parent, const Song& s);
|
||||
LibraryItem* CreateCompilationArtistNode(bool signal, LibraryItem* parent);
|
||||
|
||||
QString PrettyArtist(QString artist) const;
|
||||
QString PrettyAlbum(QString album) const;
|
||||
// Helpers for ItemFromQuery and ItemFromSong
|
||||
LibraryItem* InitItem(QueryOptions::GroupBy type, bool signal, LibraryItem* parent);
|
||||
void FinishItem(QueryOptions::GroupBy type, bool signal, bool create_divider,
|
||||
LibraryItem* parent, LibraryItem* item);
|
||||
|
||||
// Functions for manipulating text
|
||||
QString TextOrUnknown(const QString& text) const;
|
||||
QString PrettyYearAlbum(int year, const QString& album) const;
|
||||
|
||||
QString SortText(QString text) const;
|
||||
QString SortTextForArtist(QString artist) const;
|
||||
QString SortTextForAlbum(QString album) const;
|
||||
QString SortTextForYear(int year) const;
|
||||
|
||||
QString DividerKey(QueryOptions::GroupBy type, LibraryItem* item) const;
|
||||
QString DividerDisplayText(QueryOptions::GroupBy type, const QString& key) const;
|
||||
|
||||
// Helpers
|
||||
QVariant data(const LibraryItem* item, int role) const;
|
||||
|
||||
bool CompareItems(const LibraryItem* a, const LibraryItem* b) const;
|
||||
QChar DividerChar(const QString& sort_text) const;
|
||||
|
||||
private:
|
||||
EngineBase* engine_;
|
||||
@ -129,9 +144,16 @@ class Library : public SimpleTreeModel<LibraryItem> {
|
||||
|
||||
QueryOptions query_options_;
|
||||
|
||||
// Keyed on database ID
|
||||
QMap<int, LibraryItem*> song_nodes_;
|
||||
QMap<QString, LibraryItem*> artist_nodes_;
|
||||
QMap<QChar, LibraryItem*> divider_nodes_;
|
||||
|
||||
// Keyed on whatever the key is for that level - artist, album, year, etc.
|
||||
QMap<QString, LibraryItem*> container_nodes_[3];
|
||||
|
||||
// Keyed on a letter, a year, a century, etc.
|
||||
QMap<QString, LibraryItem*> divider_nodes_;
|
||||
|
||||
// Only applies if the first level is "artist"
|
||||
LibraryItem* compilation_artist_node_;
|
||||
|
||||
QIcon artist_icon_;
|
||||
|
@ -467,13 +467,11 @@ QStringList LibraryBackend::GetAllArtists(const QueryOptions& opt) {
|
||||
query.SetColumnSpec("DISTINCT artist");
|
||||
query.AddCompilationRequirement(false);
|
||||
|
||||
QSqlQuery q(query.Query(Connect()));
|
||||
q.exec();
|
||||
if (CheckErrors(q.lastError())) return QStringList();
|
||||
if (!ExecQuery(&query)) return QStringList();
|
||||
|
||||
QStringList ret;
|
||||
while (q.next()) {
|
||||
ret << q.value(0).toString();
|
||||
while (query.Next()) {
|
||||
ret << query.Value(0).toString();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -494,14 +492,12 @@ SongList LibraryBackend::GetSongs(const QString& artist, const QString& album, c
|
||||
query.AddWhere("artist", artist);
|
||||
query.AddWhere("album", album);
|
||||
|
||||
QSqlQuery q(query.Query(Connect()));
|
||||
q.exec();
|
||||
if (CheckErrors(q.lastError())) return SongList();
|
||||
if (!ExecQuery(&query)) return SongList();
|
||||
|
||||
SongList ret;
|
||||
while (q.next()) {
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
song.InitFromQuery(q);
|
||||
song.InitFromQuery(query);
|
||||
ret << song;
|
||||
}
|
||||
return ret;
|
||||
@ -528,11 +524,9 @@ bool LibraryBackend::HasCompilations(const QueryOptions& opt) {
|
||||
query.SetColumnSpec("ROWID");
|
||||
query.AddCompilationRequirement(true);
|
||||
|
||||
QSqlQuery q(query.Query(Connect()));
|
||||
q.exec();
|
||||
if (CheckErrors(q.lastError())) return false;
|
||||
if (!ExecQuery(&query)) return false;
|
||||
|
||||
return q.next();
|
||||
return query.Next();
|
||||
}
|
||||
|
||||
LibraryBackend::AlbumList LibraryBackend::GetCompilationAlbums(const QueryOptions& opt) {
|
||||
@ -545,14 +539,12 @@ SongList LibraryBackend::GetCompilationSongs(const QString& album, const QueryOp
|
||||
query.AddCompilationRequirement(true);
|
||||
query.AddWhere("album", album);
|
||||
|
||||
QSqlQuery q(query.Query(Connect()));
|
||||
q.exec();
|
||||
if (CheckErrors(q.lastError())) return SongList();
|
||||
if (!ExecQuery(&query)) return SongList();
|
||||
|
||||
SongList ret;
|
||||
while (q.next()) {
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
song.InitFromQuery(q);
|
||||
song.InitFromQuery(query);
|
||||
ret << song;
|
||||
}
|
||||
return ret;
|
||||
@ -673,20 +665,18 @@ LibraryBackend::AlbumList LibraryBackend::GetAlbums(const QString& artist,
|
||||
query.AddWhere("artist", artist);
|
||||
}
|
||||
|
||||
QSqlQuery q(query.Query(Connect()));
|
||||
q.exec();
|
||||
if (CheckErrors(q.lastError())) return ret;
|
||||
if (!ExecQuery(&query)) return ret;
|
||||
|
||||
QString last_album;
|
||||
QString last_artist;
|
||||
while (q.next()) {
|
||||
bool compilation = q.value(2).toBool() | q.value(3).toBool();
|
||||
while (query.Next()) {
|
||||
bool compilation = query.Value(2).toBool() | query.Value(3).toBool();
|
||||
|
||||
Album info;
|
||||
info.artist = compilation ? QString() : q.value(1).toString();
|
||||
info.album_name = q.value(0).toString();
|
||||
info.art_automatic = q.value(4).toString();
|
||||
info.art_manual = q.value(5).toString();
|
||||
info.artist = compilation ? QString() : query.Value(1).toString();
|
||||
info.album_name = query.Value(0).toString();
|
||||
info.art_automatic = query.Value(4).toString();
|
||||
info.art_manual = query.Value(5).toString();
|
||||
|
||||
if (info.artist == last_artist && info.album_name == last_album)
|
||||
continue;
|
||||
@ -710,13 +700,11 @@ LibraryBackend::Album LibraryBackend::GetAlbumArt(const QString& artist, const Q
|
||||
query.AddWhere("artist", artist);
|
||||
query.AddWhere("album", album);
|
||||
|
||||
QSqlQuery q(query.Query(Connect()));
|
||||
q.exec();
|
||||
if (CheckErrors(q.lastError())) return ret;
|
||||
if (!ExecQuery(&query)) return ret;
|
||||
|
||||
if (q.next()) {
|
||||
ret.art_automatic = q.value(0).toString();
|
||||
ret.art_manual = q.value(1).toString();
|
||||
if (query.Next()) {
|
||||
ret.art_automatic = query.Value(0).toString();
|
||||
ret.art_manual = query.Value(1).toString();
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -761,14 +749,12 @@ void LibraryBackend::ForceCompilation(const QString& artist, const QString& albu
|
||||
if (!artist.isNull())
|
||||
query.AddWhere("artist", artist);
|
||||
|
||||
QSqlQuery q(query.Query(db));
|
||||
q.exec();
|
||||
CheckErrors(q.lastError());
|
||||
if (!ExecQuery(&query)) return;
|
||||
|
||||
SongList deleted_songs;
|
||||
while (q.next()) {
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
song.InitFromQuery(q);
|
||||
song.InitFromQuery(query);
|
||||
deleted_songs << song;
|
||||
}
|
||||
|
||||
@ -780,7 +766,7 @@ void LibraryBackend::ForceCompilation(const QString& artist, const QString& albu
|
||||
if (!artist.isEmpty())
|
||||
sql += " AND artist = :artist";
|
||||
|
||||
q = QSqlQuery(sql, db);
|
||||
QSqlQuery q(sql, db);
|
||||
q.bindValue(":forced_compilation_on", on ? 1 : 0);
|
||||
q.bindValue(":forced_compilation_off", on ? 0 : 1);
|
||||
q.bindValue(":album", album);
|
||||
@ -791,14 +777,12 @@ void LibraryBackend::ForceCompilation(const QString& artist, const QString& albu
|
||||
CheckErrors(q.lastError());
|
||||
|
||||
// Now get the updated songs
|
||||
q = QSqlQuery(query.Query(db));
|
||||
q.exec();
|
||||
CheckErrors(q.lastError());
|
||||
if (!ExecQuery(&query)) return;
|
||||
|
||||
SongList added_songs;
|
||||
while (q.next()) {
|
||||
while (query.Next()) {
|
||||
Song song;
|
||||
song.InitFromQuery(q);
|
||||
song.InitFromQuery(query);
|
||||
added_songs << song;
|
||||
}
|
||||
|
||||
@ -807,3 +791,7 @@ void LibraryBackend::ForceCompilation(const QString& artist, const QString& albu
|
||||
emit SongsDiscovered(added_songs);
|
||||
}
|
||||
}
|
||||
|
||||
bool LibraryBackend::ExecQuery(LibraryQuery *q) {
|
||||
return !CheckErrors(q->Exec(Connect()));
|
||||
}
|
||||
|
@ -82,6 +82,8 @@ class LibraryBackendInterface : public QObject {
|
||||
|
||||
virtual void UpdateCompilationsAsync() = 0;
|
||||
|
||||
virtual bool ExecQuery(LibraryQuery* q) = 0;
|
||||
|
||||
public slots:
|
||||
virtual void LoadDirectories() = 0;
|
||||
virtual void UpdateTotalSongCount() = 0;
|
||||
@ -144,6 +146,8 @@ class LibraryBackend : public LibraryBackendInterface {
|
||||
|
||||
void UpdateCompilationsAsync();
|
||||
|
||||
bool ExecQuery(LibraryQuery* q);
|
||||
|
||||
public slots:
|
||||
void LoadDirectories();
|
||||
void UpdateTotalSongCount();
|
||||
|
@ -28,25 +28,17 @@ class LibraryItem : public SimpleTreeItem<LibraryItem> {
|
||||
enum Type {
|
||||
Type_Root,
|
||||
Type_Divider,
|
||||
Type_CompilationArtist,
|
||||
Type_CompilationAlbum,
|
||||
Type_Artist,
|
||||
Type_Album,
|
||||
Type_Container,
|
||||
Type_Song,
|
||||
};
|
||||
|
||||
LibraryItem(SimpleTreeModel<LibraryItem>* model)
|
||||
: SimpleTreeItem<LibraryItem>(Type_Root, model) {}
|
||||
LibraryItem(Type type, const QString& key = QString::null, LibraryItem* parent = NULL)
|
||||
: SimpleTreeItem<LibraryItem>(type, key, parent) {}
|
||||
: SimpleTreeItem<LibraryItem>(Type_Root, model), container_level(-1) {}
|
||||
LibraryItem(Type type, LibraryItem* parent = NULL)
|
||||
: SimpleTreeItem<LibraryItem>(type, parent), container_level(-1) {}
|
||||
|
||||
Song song;
|
||||
|
||||
// Maybe stores album cover art
|
||||
QPixmap cover_art;
|
||||
|
||||
// Stores the artist of an album
|
||||
QString artist;
|
||||
int container_level;
|
||||
Song metadata;
|
||||
};
|
||||
|
||||
#endif // LIBRARYITEM_H
|
||||
|
@ -19,6 +19,16 @@
|
||||
|
||||
#include <QtDebug>
|
||||
#include <QDateTime>
|
||||
#include <QSqlError>
|
||||
|
||||
QueryOptions::QueryOptions()
|
||||
: max_age(-1)
|
||||
{
|
||||
group_by[0] = GroupBy_Artist;
|
||||
group_by[1] = GroupBy_Album;
|
||||
group_by[2] = GroupBy_None;
|
||||
}
|
||||
|
||||
|
||||
LibraryQuery::LibraryQuery()
|
||||
{
|
||||
@ -65,7 +75,7 @@ void LibraryQuery::AddCompilationRequirement(bool compilation) {
|
||||
where_clauses_ << QString("effective_compilation = %1").arg(compilation ? 1 : 0);
|
||||
}
|
||||
|
||||
QSqlQuery LibraryQuery::Query(QSqlDatabase db) const {
|
||||
QSqlError LibraryQuery::Exec(QSqlDatabase db) {
|
||||
QString sql = QString("SELECT %1 FROM songs").arg(column_spec_);
|
||||
|
||||
if (!where_clauses_.isEmpty())
|
||||
@ -74,14 +84,23 @@ QSqlQuery LibraryQuery::Query(QSqlDatabase db) const {
|
||||
if (!order_by_.isEmpty())
|
||||
sql += " ORDER BY " + order_by_;
|
||||
|
||||
QSqlQuery q(sql, db);
|
||||
query_ = QSqlQuery(sql, db);
|
||||
|
||||
// Bind values
|
||||
foreach (const QVariant& value, bound_values_) {
|
||||
q.addBindValue(value);
|
||||
query_.addBindValue(value);
|
||||
}
|
||||
|
||||
return q;
|
||||
query_.exec();
|
||||
return query_.lastError();
|
||||
}
|
||||
|
||||
bool LibraryQuery::Next() {
|
||||
return query_.next();
|
||||
}
|
||||
|
||||
QVariant LibraryQuery::Value(int column) const {
|
||||
return query_.value(column);
|
||||
}
|
||||
|
||||
bool QueryOptions::Matches(const Song& song) const {
|
||||
|
@ -26,10 +26,22 @@
|
||||
class Song;
|
||||
|
||||
struct QueryOptions {
|
||||
QueryOptions() : max_age(-1) {}
|
||||
QueryOptions();
|
||||
|
||||
// These values get saved in QSettings - don't change them
|
||||
enum GroupBy {
|
||||
GroupBy_None = 0,
|
||||
GroupBy_Artist = 1,
|
||||
GroupBy_Album = 2,
|
||||
GroupBy_YearAlbum = 3,
|
||||
GroupBy_Year = 4,
|
||||
GroupBy_Composer = 5,
|
||||
GroupBy_Genre = 6,
|
||||
};
|
||||
|
||||
bool Matches(const Song& song) const;
|
||||
|
||||
GroupBy group_by[3];
|
||||
QString filter;
|
||||
int max_age;
|
||||
};
|
||||
@ -45,13 +57,19 @@ class LibraryQuery {
|
||||
void AddWhereLike(const QString& column, const QVariant& value);
|
||||
void AddCompilationRequirement(bool compilation);
|
||||
|
||||
QSqlQuery Query(QSqlDatabase db) const;
|
||||
QSqlError Exec(QSqlDatabase db);
|
||||
bool Next();
|
||||
QVariant Value(int column) const;
|
||||
|
||||
operator const QSqlQuery& () const { return query_; }
|
||||
|
||||
private:
|
||||
QString column_spec_;
|
||||
QString order_by_;
|
||||
QStringList where_clauses_;
|
||||
QVariantList bound_values_;
|
||||
|
||||
QSqlQuery query_;
|
||||
};
|
||||
|
||||
#endif // LIBRARYQUERY_H
|
||||
|
@ -178,9 +178,8 @@ void LibraryView::contextMenuEvent(QContextMenuEvent *e) {
|
||||
context_menu_index_ = qobject_cast<QSortFilterProxyModel*>(model())
|
||||
->mapToSource(context_menu_index_);
|
||||
|
||||
int type = library_->data(context_menu_index_, Library::Role_Type).toInt();
|
||||
bool enable_various = type == LibraryItem::Type_Album ||
|
||||
type == LibraryItem::Type_CompilationAlbum;
|
||||
int type = library_->data(context_menu_index_, Library::Role_ContainerType).toInt();
|
||||
bool enable_various = type == QueryOptions::GroupBy_Album;
|
||||
|
||||
show_in_various_->setEnabled(enable_various);
|
||||
no_show_in_various_->setEnabled(enable_various);
|
||||
|
@ -233,10 +233,23 @@ MainWindow::MainWindow(QNetworkAccessManager* network, QWidget *parent)
|
||||
connect(filter_age_mapper, SIGNAL(mapped(int)), library_, SLOT(SetFilterAge(int)));
|
||||
connect(ui_.library_filter_clear, SIGNAL(clicked()), SLOT(ClearLibraryFilter()));
|
||||
|
||||
// "Group by ..."
|
||||
QActionGroup* group_by_group = new QActionGroup(this);
|
||||
group_by_group->addAction(ui_.group_by_artist);
|
||||
group_by_group->addAction(ui_.group_by_artist_album);
|
||||
group_by_group->addAction(ui_.group_by_artist_yearalbum);
|
||||
group_by_group->addAction(ui_.group_by_album);
|
||||
group_by_group->addAction(ui_.group_by_genre_album);
|
||||
group_by_group->addAction(ui_.group_by_genre_artist_album);
|
||||
group_by_group->addAction(ui_.group_by_advanced);
|
||||
connect(group_by_group, SIGNAL(triggered(QAction*)), SLOT(GroupByClicked(QAction*)));
|
||||
|
||||
// Library config menu
|
||||
QMenu* library_menu = new QMenu(this);
|
||||
library_menu->addActions(filter_age_group->actions());
|
||||
library_menu->addSeparator();
|
||||
library_menu->addActions(group_by_group->actions());
|
||||
library_menu->addSeparator();
|
||||
library_menu->addAction(tr("Configure library..."), library_config_dialog_, SLOT(show()));
|
||||
ui_.library_options->setMenu(library_menu);
|
||||
|
||||
@ -322,6 +335,13 @@ MainWindow::MainWindow(QNetworkAccessManager* network, QWidget *parent)
|
||||
|
||||
ui_.file_view->SetPath(settings_.value("file_path", QDir::homePath()).toString());
|
||||
|
||||
QueryOptions::GroupBy g[3];
|
||||
g[0] = QueryOptions::GroupBy(settings_.value("group_by1", int(QueryOptions::GroupBy_Artist)).toInt());
|
||||
g[1] = QueryOptions::GroupBy(settings_.value("group_by2", int(QueryOptions::GroupBy_Album)).toInt());
|
||||
g[2] = QueryOptions::GroupBy(settings_.value("group_by3", int(QueryOptions::GroupBy_None)).toInt());
|
||||
library_->SetGroupBy(g);
|
||||
UpdateGroupBySelection(g);
|
||||
|
||||
if (!settings_.value("hidden", false).toBool()) {
|
||||
show();
|
||||
}
|
||||
@ -780,3 +800,67 @@ void MainWindow::AddStreamAccepted() {
|
||||
void MainWindow::PlaylistRemoveCurrent() {
|
||||
ui_.playlist->RemoveSelected();
|
||||
}
|
||||
|
||||
void MainWindow::GroupByClicked(QAction* action) {
|
||||
QueryOptions::GroupBy g[3];
|
||||
g[0] = QueryOptions::GroupBy_None;
|
||||
g[1] = QueryOptions::GroupBy_None;
|
||||
g[2] = QueryOptions::GroupBy_None;
|
||||
|
||||
if (action == ui_.group_by_album) {
|
||||
g[0] = QueryOptions::GroupBy_Album;
|
||||
} else if (action == ui_.group_by_artist) {
|
||||
g[0] = QueryOptions::GroupBy_Artist;
|
||||
} else if (action == ui_.group_by_artist_album) {
|
||||
g[0] = QueryOptions::GroupBy_Artist;
|
||||
g[1] = QueryOptions::GroupBy_Album;
|
||||
} else if (action == ui_.group_by_artist_yearalbum) {
|
||||
g[0] = QueryOptions::GroupBy_Artist;
|
||||
g[1] = QueryOptions::GroupBy_YearAlbum;
|
||||
} else if (action == ui_.group_by_genre_album) {
|
||||
g[0] = QueryOptions::GroupBy_Genre;
|
||||
g[1] = QueryOptions::GroupBy_Album;
|
||||
} else if (action == ui_.group_by_genre_artist_album) {
|
||||
g[0] = QueryOptions::GroupBy_Genre;
|
||||
g[1] = QueryOptions::GroupBy_Artist;
|
||||
g[2] = QueryOptions::GroupBy_Album;
|
||||
} else {
|
||||
qWarning() << "Unknown action in" << __PRETTY_FUNCTION__;
|
||||
return;
|
||||
}
|
||||
|
||||
library_->SetGroupBy(g);
|
||||
|
||||
settings_.setValue("group_by1", int(g[0]));
|
||||
settings_.setValue("group_by2", int(g[1]));
|
||||
settings_.setValue("group_by3", int(g[2]));
|
||||
}
|
||||
|
||||
void MainWindow::UpdateGroupBySelection(QueryOptions::GroupBy g[3]) {
|
||||
if (g[0] == QueryOptions::GroupBy_Album &&
|
||||
g[1] == QueryOptions::GroupBy_None &&
|
||||
g[2] == QueryOptions::GroupBy_None)
|
||||
ui_.group_by_album->setChecked(true);
|
||||
else if (g[0] == QueryOptions::GroupBy_Artist &&
|
||||
g[1] == QueryOptions::GroupBy_None &&
|
||||
g[2] == QueryOptions::GroupBy_None)
|
||||
ui_.group_by_artist->setChecked(true);
|
||||
else if (g[0] == QueryOptions::GroupBy_Artist &&
|
||||
g[1] == QueryOptions::GroupBy_Album &&
|
||||
g[2] == QueryOptions::GroupBy_None)
|
||||
ui_.group_by_artist_album->setChecked(true);
|
||||
else if (g[0] == QueryOptions::GroupBy_Artist &&
|
||||
g[1] == QueryOptions::GroupBy_YearAlbum &&
|
||||
g[2] == QueryOptions::GroupBy_None)
|
||||
ui_.group_by_artist_yearalbum->setChecked(true);
|
||||
else if (g[0] == QueryOptions::GroupBy_Genre &&
|
||||
g[1] == QueryOptions::GroupBy_Album &&
|
||||
g[2] == QueryOptions::GroupBy_None)
|
||||
ui_.group_by_genre_album->setChecked(true);
|
||||
else if (g[0] == QueryOptions::GroupBy_Genre &&
|
||||
g[1] == QueryOptions::GroupBy_Artist &&
|
||||
g[2] == QueryOptions::GroupBy_Album)
|
||||
ui_.group_by_genre_artist_album->setChecked(true);
|
||||
else
|
||||
ui_.group_by_advanced->setChecked(true);
|
||||
}
|
||||
|
@ -82,6 +82,7 @@ class MainWindow : public QMainWindow {
|
||||
|
||||
void LibraryDoubleClick(const QModelIndex& index);
|
||||
void ClearLibraryFilter();
|
||||
void GroupByClicked(QAction*);
|
||||
|
||||
void VolumeWheelEvent(int delta);
|
||||
void TrayClicked(QSystemTrayIcon::ActivationReason reason);
|
||||
@ -106,6 +107,7 @@ class MainWindow : public QMainWindow {
|
||||
|
||||
private:
|
||||
void SaveGeometry();
|
||||
void UpdateGroupBySelection(QueryOptions::GroupBy g[3]);
|
||||
|
||||
private:
|
||||
static const int kStateVersion;
|
||||
|
@ -41,7 +41,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::SelectedClicked|QAbstractItemView::EditKeyPressed</set>
|
||||
<set>QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked</set>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
@ -756,6 +756,62 @@
|
||||
<string>Remove from playlist</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="group_by_artist">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Group by Artist</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="group_by_artist_album">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Group by Artist/Album</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="group_by_artist_yearalbum">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Group by Artist/Year - Album</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="group_by_album">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Group by Album</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="group_by_genre_album">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Group by Genre/Album</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="group_by_genre_artist_album">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Group by Genre/Artist/Album</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="group_by_advanced">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Advanced grouping...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
@ -26,7 +26,8 @@ template <typename T>
|
||||
class SimpleTreeItem {
|
||||
public:
|
||||
SimpleTreeItem(int _type, SimpleTreeModel<T>* _model); // For the root item
|
||||
SimpleTreeItem(int _type, const QString& _key = QString::null, T* _parent = NULL);
|
||||
SimpleTreeItem(int _type, const QString& _key, T* _parent = NULL);
|
||||
SimpleTreeItem(int _type, T* _parent = NULL);
|
||||
virtual ~SimpleTreeItem();
|
||||
|
||||
void InsertNotify(T* _parent);
|
||||
@ -77,6 +78,19 @@ SimpleTreeItem<T>::SimpleTreeItem(int _type, const QString& _key, T* _parent)
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
SimpleTreeItem<T>::SimpleTreeItem(int _type, T* _parent)
|
||||
: type(_type),
|
||||
lazy_loaded(false),
|
||||
parent(_parent),
|
||||
model(_parent ? _parent->model : NULL)
|
||||
{
|
||||
if (parent) {
|
||||
row = parent->children.count();
|
||||
parent->children << static_cast<T*>(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void SimpleTreeItem<T>::InsertNotify(T* _parent) {
|
||||
|
@ -618,13 +618,12 @@ p, li { white-space: pre-wrap; }
|
||||
<context>
|
||||
<name>Library</name>
|
||||
<message>
|
||||
<location filename="../library.cpp" line="161"/>
|
||||
<location filename="../library.cpp" line="186"/>
|
||||
<source>Various Artists</source>
|
||||
<translation>Různí umělci</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../library.cpp" line="464"/>
|
||||
<location filename="../library.cpp" line="482"/>
|
||||
<location filename="../library.cpp" line="642"/>
|
||||
<source>Unknown</source>
|
||||
<translation>Neznámý</translation>
|
||||
</message>
|
||||
@ -742,10 +741,10 @@ p, li { white-space: pre-wrap; }
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="517"/>
|
||||
<location filename="../mainwindow.cpp" line="244"/>
|
||||
<location filename="../mainwindow.cpp" line="379"/>
|
||||
<location filename="../mainwindow.cpp" line="395"/>
|
||||
<location filename="../mainwindow.cpp" line="576"/>
|
||||
<location filename="../mainwindow.cpp" line="257"/>
|
||||
<location filename="../mainwindow.cpp" line="399"/>
|
||||
<location filename="../mainwindow.cpp" line="415"/>
|
||||
<location filename="../mainwindow.cpp" line="596"/>
|
||||
<source>Play</source>
|
||||
<translation>Přehrát</translation>
|
||||
</message>
|
||||
@ -771,7 +770,7 @@ p, li { white-space: pre-wrap; }
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="559"/>
|
||||
<location filename="../mainwindow.cpp" line="246"/>
|
||||
<location filename="../mainwindow.cpp" line="259"/>
|
||||
<source>Stop after this track</source>
|
||||
<translation>Zastavit po této skladbě</translation>
|
||||
</message>
|
||||
@ -874,7 +873,7 @@ p, li { white-space: pre-wrap; }
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="728"/>
|
||||
<location filename="../mainwindow.cpp" line="358"/>
|
||||
<location filename="../mainwindow.cpp" line="378"/>
|
||||
<source>&Hide tray icon</source>
|
||||
<translation>S&krýt ikonu v systémovém panelu</translation>
|
||||
</message>
|
||||
@ -899,29 +898,64 @@ p, li { white-space: pre-wrap; }
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="240"/>
|
||||
<location filename="../mainwindow.ui" line="764"/>
|
||||
<source>Group by Artist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="772"/>
|
||||
<source>Group by Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="780"/>
|
||||
<source>Group by Artist/Year - Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="788"/>
|
||||
<source>Group by Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="796"/>
|
||||
<source>Group by Genre/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="804"/>
|
||||
<source>Group by Genre/Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="812"/>
|
||||
<source>Advanced grouping...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="253"/>
|
||||
<source>Configure library...</source>
|
||||
<translation>Nastavit knihovnu...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="333"/>
|
||||
<location filename="../mainwindow.cpp" line="354"/>
|
||||
<location filename="../mainwindow.cpp" line="353"/>
|
||||
<location filename="../mainwindow.cpp" line="374"/>
|
||||
<source>&Show tray icon</source>
|
||||
<translation>Zobrazit ikonu v &systémovém panelu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="406"/>
|
||||
<location filename="../mainwindow.cpp" line="573"/>
|
||||
<location filename="../mainwindow.cpp" line="426"/>
|
||||
<location filename="../mainwindow.cpp" line="593"/>
|
||||
<source>Pause</source>
|
||||
<translation>Pozastavit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="623"/>
|
||||
<location filename="../mainwindow.cpp" line="643"/>
|
||||
<source>Set %1 to "%2"...</source>
|
||||
<translation>Nastavit %1 na "%2"...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="625"/>
|
||||
<location filename="../mainwindow.cpp" line="645"/>
|
||||
<source>Edit tag "%1"...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -771,6 +771,34 @@ p, li { white-space: pre-wrap; }
|
||||
<source>Remove from playlist</source>
|
||||
<translation>Αφαίρεση από την λίστα</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Artist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Artist/Year - Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Genre/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Genre/Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Advanced grouping...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiLoadingIndicator</name>
|
||||
|
@ -604,13 +604,12 @@ p, li { white-space: pre-wrap; }
|
||||
<context>
|
||||
<name>Library</name>
|
||||
<message>
|
||||
<location filename="../library.cpp" line="161"/>
|
||||
<location filename="../library.cpp" line="186"/>
|
||||
<source>Various Artists</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../library.cpp" line="464"/>
|
||||
<location filename="../library.cpp" line="482"/>
|
||||
<location filename="../library.cpp" line="642"/>
|
||||
<source>Unknown</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -728,10 +727,10 @@ p, li { white-space: pre-wrap; }
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="517"/>
|
||||
<location filename="../mainwindow.cpp" line="244"/>
|
||||
<location filename="../mainwindow.cpp" line="379"/>
|
||||
<location filename="../mainwindow.cpp" line="395"/>
|
||||
<location filename="../mainwindow.cpp" line="576"/>
|
||||
<location filename="../mainwindow.cpp" line="257"/>
|
||||
<location filename="../mainwindow.cpp" line="399"/>
|
||||
<location filename="../mainwindow.cpp" line="415"/>
|
||||
<location filename="../mainwindow.cpp" line="596"/>
|
||||
<source>Play</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -757,7 +756,7 @@ p, li { white-space: pre-wrap; }
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="559"/>
|
||||
<location filename="../mainwindow.cpp" line="246"/>
|
||||
<location filename="../mainwindow.cpp" line="259"/>
|
||||
<source>Stop after this track</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -863,9 +862,44 @@ p, li { white-space: pre-wrap; }
|
||||
<source>Remove from playlist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="764"/>
|
||||
<source>Group by Artist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="772"/>
|
||||
<source>Group by Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="780"/>
|
||||
<source>Group by Artist/Year - Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="788"/>
|
||||
<source>Group by Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="796"/>
|
||||
<source>Group by Genre/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="804"/>
|
||||
<source>Group by Genre/Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="812"/>
|
||||
<source>Advanced grouping...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="728"/>
|
||||
<location filename="../mainwindow.cpp" line="358"/>
|
||||
<location filename="../mainwindow.cpp" line="378"/>
|
||||
<source>&Hide tray icon</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
@ -885,29 +919,29 @@ p, li { white-space: pre-wrap; }
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="240"/>
|
||||
<location filename="../mainwindow.cpp" line="253"/>
|
||||
<source>Configure library...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="333"/>
|
||||
<location filename="../mainwindow.cpp" line="354"/>
|
||||
<location filename="../mainwindow.cpp" line="353"/>
|
||||
<location filename="../mainwindow.cpp" line="374"/>
|
||||
<source>&Show tray icon</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="406"/>
|
||||
<location filename="../mainwindow.cpp" line="573"/>
|
||||
<location filename="../mainwindow.cpp" line="426"/>
|
||||
<location filename="../mainwindow.cpp" line="593"/>
|
||||
<source>Pause</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="623"/>
|
||||
<location filename="../mainwindow.cpp" line="643"/>
|
||||
<source>Set %1 to "%2"...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="625"/>
|
||||
<location filename="../mainwindow.cpp" line="645"/>
|
||||
<source>Edit tag "%1"...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -754,6 +754,34 @@ p, li { white-space: pre-wrap; }
|
||||
<source>Remove from playlist</source>
|
||||
<translation>Eliminar de la lista de reproducción</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Artist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Artist/Year - Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Genre/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Genre/Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Advanced grouping...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiLoadingIndicator</name>
|
||||
|
@ -617,13 +617,12 @@ p, li { white-space: pre-wrap; }
|
||||
<context>
|
||||
<name>Library</name>
|
||||
<message>
|
||||
<location filename="../library.cpp" line="161"/>
|
||||
<location filename="../library.cpp" line="186"/>
|
||||
<source>Various Artists</source>
|
||||
<translation>Compilations d'artistes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../library.cpp" line="464"/>
|
||||
<location filename="../library.cpp" line="482"/>
|
||||
<location filename="../library.cpp" line="642"/>
|
||||
<source>Unknown</source>
|
||||
<translation>Inconnu</translation>
|
||||
</message>
|
||||
@ -741,10 +740,10 @@ p, li { white-space: pre-wrap; }
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="517"/>
|
||||
<location filename="../mainwindow.cpp" line="244"/>
|
||||
<location filename="../mainwindow.cpp" line="379"/>
|
||||
<location filename="../mainwindow.cpp" line="395"/>
|
||||
<location filename="../mainwindow.cpp" line="576"/>
|
||||
<location filename="../mainwindow.cpp" line="257"/>
|
||||
<location filename="../mainwindow.cpp" line="399"/>
|
||||
<location filename="../mainwindow.cpp" line="415"/>
|
||||
<location filename="../mainwindow.cpp" line="596"/>
|
||||
<source>Play</source>
|
||||
<translation>Lecture</translation>
|
||||
</message>
|
||||
@ -770,7 +769,7 @@ p, li { white-space: pre-wrap; }
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="559"/>
|
||||
<location filename="../mainwindow.cpp" line="246"/>
|
||||
<location filename="../mainwindow.cpp" line="259"/>
|
||||
<source>Stop after this track</source>
|
||||
<translation>Arrêter la lecture après cette piste</translation>
|
||||
</message>
|
||||
@ -873,7 +872,7 @@ p, li { white-space: pre-wrap; }
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="728"/>
|
||||
<location filename="../mainwindow.cpp" line="358"/>
|
||||
<location filename="../mainwindow.cpp" line="378"/>
|
||||
<source>&Hide tray icon</source>
|
||||
<translation>&Masquer l'icône</translation>
|
||||
</message>
|
||||
@ -898,29 +897,64 @@ p, li { white-space: pre-wrap; }
|
||||
<translation>Supprimer de la liste de lecture</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="240"/>
|
||||
<location filename="../mainwindow.ui" line="764"/>
|
||||
<source>Group by Artist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="772"/>
|
||||
<source>Group by Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="780"/>
|
||||
<source>Group by Artist/Year - Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="788"/>
|
||||
<source>Group by Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="796"/>
|
||||
<source>Group by Genre/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="804"/>
|
||||
<source>Group by Genre/Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="812"/>
|
||||
<source>Advanced grouping...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="253"/>
|
||||
<source>Configure library...</source>
|
||||
<translation>Configurer votre bibliothèque...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="333"/>
|
||||
<location filename="../mainwindow.cpp" line="354"/>
|
||||
<location filename="../mainwindow.cpp" line="353"/>
|
||||
<location filename="../mainwindow.cpp" line="374"/>
|
||||
<source>&Show tray icon</source>
|
||||
<translation>&Afficher l'icône</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="406"/>
|
||||
<location filename="../mainwindow.cpp" line="573"/>
|
||||
<location filename="../mainwindow.cpp" line="426"/>
|
||||
<location filename="../mainwindow.cpp" line="593"/>
|
||||
<source>Pause</source>
|
||||
<translation>Pause</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="623"/>
|
||||
<location filename="../mainwindow.cpp" line="643"/>
|
||||
<source>Set %1 to "%2"...</source>
|
||||
<translation>Définir %1 à la valeur "%2"...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="625"/>
|
||||
<location filename="../mainwindow.cpp" line="645"/>
|
||||
<source>Edit tag "%1"...</source>
|
||||
<translation>Modifer le tag "%1"...</translation>
|
||||
</message>
|
||||
|
@ -741,6 +741,34 @@ p, li { white-space: pre-wrap; }
|
||||
<source>Remove from playlist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Artist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Artist/Year - Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Genre/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group by Genre/Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Advanced grouping...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MultiLoadingIndicator</name>
|
||||
|
@ -618,13 +618,12 @@ p, li { white-space: pre-wrap; }
|
||||
<context>
|
||||
<name>Library</name>
|
||||
<message>
|
||||
<location filename="../library.cpp" line="161"/>
|
||||
<location filename="../library.cpp" line="186"/>
|
||||
<source>Various Artists</source>
|
||||
<translation>Rôzni interpréti</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../library.cpp" line="464"/>
|
||||
<location filename="../library.cpp" line="482"/>
|
||||
<location filename="../library.cpp" line="642"/>
|
||||
<source>Unknown</source>
|
||||
<translation>Neznámi</translation>
|
||||
</message>
|
||||
@ -686,44 +685,44 @@ p, li { white-space: pre-wrap; }
|
||||
<context>
|
||||
<name>MainWindow</name>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="240"/>
|
||||
<location filename="../mainwindow.cpp" line="253"/>
|
||||
<source>Configure library...</source>
|
||||
<translation>Nastaviť zbierku...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="517"/>
|
||||
<location filename="../mainwindow.cpp" line="244"/>
|
||||
<location filename="../mainwindow.cpp" line="379"/>
|
||||
<location filename="../mainwindow.cpp" line="395"/>
|
||||
<location filename="../mainwindow.cpp" line="576"/>
|
||||
<location filename="../mainwindow.cpp" line="257"/>
|
||||
<location filename="../mainwindow.cpp" line="399"/>
|
||||
<location filename="../mainwindow.cpp" line="415"/>
|
||||
<location filename="../mainwindow.cpp" line="596"/>
|
||||
<source>Play</source>
|
||||
<translation>Hrať</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="559"/>
|
||||
<location filename="../mainwindow.cpp" line="246"/>
|
||||
<location filename="../mainwindow.cpp" line="259"/>
|
||||
<source>Stop after this track</source>
|
||||
<translation>Zastaviť po tejto skladbe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="333"/>
|
||||
<location filename="../mainwindow.cpp" line="354"/>
|
||||
<location filename="../mainwindow.cpp" line="353"/>
|
||||
<location filename="../mainwindow.cpp" line="374"/>
|
||||
<source>&Show tray icon</source>
|
||||
<translation>&Zobraziť tray ikonu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="406"/>
|
||||
<location filename="../mainwindow.cpp" line="573"/>
|
||||
<location filename="../mainwindow.cpp" line="426"/>
|
||||
<location filename="../mainwindow.cpp" line="593"/>
|
||||
<source>Pause</source>
|
||||
<translation>Pauza</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="623"/>
|
||||
<location filename="../mainwindow.cpp" line="643"/>
|
||||
<source>Set %1 to "%2"...</source>
|
||||
<translation>Nastaviť %1 do "%2"...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.cpp" line="625"/>
|
||||
<location filename="../mainwindow.cpp" line="645"/>
|
||||
<source>Edit tag "%1"...</source>
|
||||
<translation>Upraviť tag "%1"...</translation>
|
||||
</message>
|
||||
@ -904,9 +903,44 @@ p, li { white-space: pre-wrap; }
|
||||
<source>Remove from playlist</source>
|
||||
<translation>Odstrániť z playlistu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="764"/>
|
||||
<source>Group by Artist</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="772"/>
|
||||
<source>Group by Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="780"/>
|
||||
<source>Group by Artist/Year - Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="788"/>
|
||||
<source>Group by Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="796"/>
|
||||
<source>Group by Genre/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="804"/>
|
||||
<source>Group by Genre/Artist/Album</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="812"/>
|
||||
<source>Advanced grouping...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../mainwindow.ui" line="728"/>
|
||||
<location filename="../mainwindow.cpp" line="358"/>
|
||||
<location filename="../mainwindow.cpp" line="378"/>
|
||||
<source>&Hide tray icon</source>
|
||||
<translation>&Skryť tray ikonu</translation>
|
||||
</message>
|
||||
|
@ -639,12 +639,12 @@ msgid "Tag"
|
||||
msgstr "Značka"
|
||||
|
||||
#. ts-context Library
|
||||
#: ../library.cpp:161
|
||||
#: ../library.cpp:186
|
||||
msgid "Various Artists"
|
||||
msgstr "Různí umělci"
|
||||
|
||||
#. ts-context Library
|
||||
#: ../library.cpp:464 ../library.cpp:482
|
||||
#: ../library.cpp:642
|
||||
msgid "Unknown"
|
||||
msgstr "Neznámý"
|
||||
|
||||
@ -749,8 +749,8 @@ msgid "Previous track"
|
||||
msgstr "Předchozí skladba"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:517 ../mainwindow.cpp:244 ../mainwindow.cpp:379
|
||||
#: ../mainwindow.cpp:395 ../mainwindow.cpp:576
|
||||
#: ../mainwindow.ui:517 ../mainwindow.cpp:257 ../mainwindow.cpp:399
|
||||
#: ../mainwindow.cpp:415 ../mainwindow.cpp:596
|
||||
msgid "Play"
|
||||
msgstr "Přehrát"
|
||||
|
||||
@ -775,7 +775,7 @@ msgid "Ctrl+Q"
|
||||
msgstr "Ctrl+Q"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:559 ../mainwindow.cpp:246
|
||||
#: ../mainwindow.ui:559 ../mainwindow.cpp:259
|
||||
msgid "Stop after this track"
|
||||
msgstr "Zastavit po této skladbě"
|
||||
|
||||
@ -876,7 +876,7 @@ msgid "Open media..."
|
||||
msgstr "Otevřít média..."
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:728 ../mainwindow.cpp:358
|
||||
#: ../mainwindow.ui:728 ../mainwindow.cpp:378
|
||||
msgid "&Hide tray icon"
|
||||
msgstr "S&krýt ikonu v systémovém panelu"
|
||||
|
||||
@ -902,27 +902,69 @@ msgid "Remove from playlist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:240
|
||||
#: ../mainwindow.ui:764
|
||||
#, fuzzy
|
||||
msgid "Group by Artist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:772
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:780
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Year - Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:788
|
||||
#, fuzzy
|
||||
msgid "Group by Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:796
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:804
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:812
|
||||
#, fuzzy
|
||||
msgid "Advanced grouping..."
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:253
|
||||
msgid "Configure library..."
|
||||
msgstr "Nastavit knihovnu..."
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:333 ../mainwindow.cpp:354
|
||||
#: ../mainwindow.cpp:353 ../mainwindow.cpp:374
|
||||
msgid "&Show tray icon"
|
||||
msgstr "Zobrazit ikonu v &systémovém panelu"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:406 ../mainwindow.cpp:573
|
||||
#: ../mainwindow.cpp:426 ../mainwindow.cpp:593
|
||||
msgid "Pause"
|
||||
msgstr "Pozastavit"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:623
|
||||
#: ../mainwindow.cpp:643
|
||||
msgid "Set %1 to \"%2\"..."
|
||||
msgstr "Nastavit %1 na \"%2\"..."
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:625
|
||||
#: ../mainwindow.cpp:645
|
||||
#, fuzzy
|
||||
msgid "Edit tag \"%1\"..."
|
||||
msgstr ""
|
||||
|
@ -761,6 +761,41 @@ msgstr "Τροποποίησησ ετικέτας..."
|
||||
msgid "Remove from playlist"
|
||||
msgstr "Αφαίρεση από την λίστα"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Artist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Year - Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Advanced grouping..."
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MultiLoadingIndicator
|
||||
msgid "Form"
|
||||
msgstr "Μορφή"
|
||||
|
@ -770,6 +770,41 @@ msgstr "Editar etiqueta..."
|
||||
msgid "Remove from playlist"
|
||||
msgstr "Eliminar de la lista de reproducción"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Artist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Year - Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Advanced grouping..."
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MultiLoadingIndicator
|
||||
msgid "Form"
|
||||
msgstr ""
|
||||
|
@ -639,12 +639,12 @@ msgid "Tag"
|
||||
msgstr "Tag"
|
||||
|
||||
#. ts-context Library
|
||||
#: ../library.cpp:161
|
||||
#: ../library.cpp:186
|
||||
msgid "Various Artists"
|
||||
msgstr "Compilations d'artistes"
|
||||
|
||||
#. ts-context Library
|
||||
#: ../library.cpp:464 ../library.cpp:482
|
||||
#: ../library.cpp:642
|
||||
msgid "Unknown"
|
||||
msgstr "Inconnu"
|
||||
|
||||
@ -751,8 +751,8 @@ msgid "Previous track"
|
||||
msgstr "Piste précédente"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:517 ../mainwindow.cpp:244 ../mainwindow.cpp:379
|
||||
#: ../mainwindow.cpp:395 ../mainwindow.cpp:576
|
||||
#: ../mainwindow.ui:517 ../mainwindow.cpp:257 ../mainwindow.cpp:399
|
||||
#: ../mainwindow.cpp:415 ../mainwindow.cpp:596
|
||||
msgid "Play"
|
||||
msgstr "Lecture"
|
||||
|
||||
@ -777,7 +777,7 @@ msgid "Ctrl+Q"
|
||||
msgstr "Ctrl+Q"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:559 ../mainwindow.cpp:246
|
||||
#: ../mainwindow.ui:559 ../mainwindow.cpp:259
|
||||
msgid "Stop after this track"
|
||||
msgstr "Arrêter la lecture après cette piste"
|
||||
|
||||
@ -877,7 +877,7 @@ msgid "Open media..."
|
||||
msgstr "Ouvrir un media..."
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:728 ../mainwindow.cpp:358
|
||||
#: ../mainwindow.ui:728 ../mainwindow.cpp:378
|
||||
msgid "&Hide tray icon"
|
||||
msgstr "&Masquer l'icône"
|
||||
|
||||
@ -902,27 +902,69 @@ msgid "Remove from playlist"
|
||||
msgstr "Supprimer de la liste de lecture"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:240
|
||||
#: ../mainwindow.ui:764
|
||||
#, fuzzy
|
||||
msgid "Group by Artist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:772
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:780
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Year - Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:788
|
||||
#, fuzzy
|
||||
msgid "Group by Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:796
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:804
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:812
|
||||
#, fuzzy
|
||||
msgid "Advanced grouping..."
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:253
|
||||
msgid "Configure library..."
|
||||
msgstr "Configurer votre bibliothèque..."
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:333 ../mainwindow.cpp:354
|
||||
#: ../mainwindow.cpp:353 ../mainwindow.cpp:374
|
||||
msgid "&Show tray icon"
|
||||
msgstr "&Afficher l'icône"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:406 ../mainwindow.cpp:573
|
||||
#: ../mainwindow.cpp:426 ../mainwindow.cpp:593
|
||||
msgid "Pause"
|
||||
msgstr "Pause"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:623
|
||||
#: ../mainwindow.cpp:643
|
||||
msgid "Set %1 to \"%2\"..."
|
||||
msgstr "Définir %1 à la valeur \"%2\"..."
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:625
|
||||
#: ../mainwindow.cpp:645
|
||||
msgid "Edit tag \"%1\"..."
|
||||
msgstr "Modifer le tag \"%1\"..."
|
||||
|
||||
|
@ -839,6 +839,41 @@ msgstr ""
|
||||
msgid "Remove from playlist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Artist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Year - Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#, fuzzy
|
||||
msgid "Advanced grouping..."
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MultiLoadingIndicator
|
||||
msgid "Form"
|
||||
msgstr "Форма"
|
||||
|
@ -641,12 +641,12 @@ msgid "Tag"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context Library
|
||||
#: ../library.cpp:161
|
||||
#: ../library.cpp:186
|
||||
msgid "Various Artists"
|
||||
msgstr "Rôzni interpréti"
|
||||
|
||||
#. ts-context Library
|
||||
#: ../library.cpp:464 ../library.cpp:482
|
||||
#: ../library.cpp:642
|
||||
msgid "Unknown"
|
||||
msgstr "Neznámi"
|
||||
|
||||
@ -696,38 +696,38 @@ msgid "Click here to add some music"
|
||||
msgstr "Kliknite sem aby ste pridali nejakú hudbu"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:240
|
||||
#: ../mainwindow.cpp:253
|
||||
msgid "Configure library..."
|
||||
msgstr "Nastaviť zbierku..."
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:517 ../mainwindow.cpp:244 ../mainwindow.cpp:379
|
||||
#: ../mainwindow.cpp:395 ../mainwindow.cpp:576
|
||||
#: ../mainwindow.ui:517 ../mainwindow.cpp:257 ../mainwindow.cpp:399
|
||||
#: ../mainwindow.cpp:415 ../mainwindow.cpp:596
|
||||
msgid "Play"
|
||||
msgstr "Hrať"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:559 ../mainwindow.cpp:246
|
||||
#: ../mainwindow.ui:559 ../mainwindow.cpp:259
|
||||
msgid "Stop after this track"
|
||||
msgstr "Zastaviť po tejto skladbe"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:333 ../mainwindow.cpp:354
|
||||
#: ../mainwindow.cpp:353 ../mainwindow.cpp:374
|
||||
msgid "&Show tray icon"
|
||||
msgstr "&Zobraziť tray ikonu"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:406 ../mainwindow.cpp:573
|
||||
#: ../mainwindow.cpp:426 ../mainwindow.cpp:593
|
||||
msgid "Pause"
|
||||
msgstr "Pauza"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:623
|
||||
#: ../mainwindow.cpp:643
|
||||
msgid "Set %1 to \"%2\"..."
|
||||
msgstr "Nastaviť %1 do \"%2\"..."
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:625
|
||||
#: ../mainwindow.cpp:645
|
||||
msgid "Edit tag \"%1\"..."
|
||||
msgstr "Upraviť tag \"%1\"..."
|
||||
|
||||
@ -907,7 +907,49 @@ msgid "Remove from playlist"
|
||||
msgstr "Odstrániť z playlistu"
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:728 ../mainwindow.cpp:358
|
||||
#: ../mainwindow.ui:764
|
||||
#, fuzzy
|
||||
msgid "Group by Artist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:772
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:780
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Year - Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:788
|
||||
#, fuzzy
|
||||
msgid "Group by Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:796
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:804
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:812
|
||||
#, fuzzy
|
||||
msgid "Advanced grouping..."
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:728 ../mainwindow.cpp:378
|
||||
msgid "&Hide tray icon"
|
||||
msgstr "&Skryť tray ikonu"
|
||||
|
||||
|
@ -700,13 +700,13 @@ msgid "Tag"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context Library
|
||||
#: ../library.cpp:161
|
||||
#: ../library.cpp:186
|
||||
#, fuzzy
|
||||
msgid "Various Artists"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context Library
|
||||
#: ../library.cpp:464 ../library.cpp:482
|
||||
#: ../library.cpp:642
|
||||
#, fuzzy
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
@ -832,8 +832,8 @@ msgid "Previous track"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:517 ../mainwindow.cpp:244 ../mainwindow.cpp:379
|
||||
#: ../mainwindow.cpp:395 ../mainwindow.cpp:576
|
||||
#: ../mainwindow.ui:517 ../mainwindow.cpp:257 ../mainwindow.cpp:399
|
||||
#: ../mainwindow.cpp:415 ../mainwindow.cpp:596
|
||||
#, fuzzy
|
||||
msgid "Play"
|
||||
msgstr ""
|
||||
@ -863,7 +863,7 @@ msgid "Ctrl+Q"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:559 ../mainwindow.cpp:246
|
||||
#: ../mainwindow.ui:559 ../mainwindow.cpp:259
|
||||
#, fuzzy
|
||||
msgid "Stop after this track"
|
||||
msgstr ""
|
||||
@ -989,7 +989,49 @@ msgid "Remove from playlist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:728 ../mainwindow.cpp:358
|
||||
#: ../mainwindow.ui:764
|
||||
#, fuzzy
|
||||
msgid "Group by Artist"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:772
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:780
|
||||
#, fuzzy
|
||||
msgid "Group by Artist/Year - Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:788
|
||||
#, fuzzy
|
||||
msgid "Group by Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:796
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:804
|
||||
#, fuzzy
|
||||
msgid "Group by Genre/Artist/Album"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:812
|
||||
#, fuzzy
|
||||
msgid "Advanced grouping..."
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.ui:728 ../mainwindow.cpp:378
|
||||
#, fuzzy
|
||||
msgid "&Hide tray icon"
|
||||
msgstr ""
|
||||
@ -1013,31 +1055,31 @@ msgid "Repeat mode"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:240
|
||||
#: ../mainwindow.cpp:253
|
||||
#, fuzzy
|
||||
msgid "Configure library..."
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:333 ../mainwindow.cpp:354
|
||||
#: ../mainwindow.cpp:353 ../mainwindow.cpp:374
|
||||
#, fuzzy
|
||||
msgid "&Show tray icon"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:406 ../mainwindow.cpp:573
|
||||
#: ../mainwindow.cpp:426 ../mainwindow.cpp:593
|
||||
#, fuzzy
|
||||
msgid "Pause"
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:623
|
||||
#: ../mainwindow.cpp:643
|
||||
#, fuzzy
|
||||
msgid "Set %1 to \"%2\"..."
|
||||
msgstr ""
|
||||
|
||||
#. ts-context MainWindow
|
||||
#: ../mainwindow.cpp:625
|
||||
#: ../mainwindow.cpp:645
|
||||
#, fuzzy
|
||||
msgid "Edit tag \"%1\"..."
|
||||
msgstr ""
|
||||
|
@ -87,7 +87,7 @@ add_test_file(song_test.cpp false)
|
||||
add_test_file(librarybackend_test.cpp false)
|
||||
add_test_file(albumcoverfetcher_test.cpp false)
|
||||
add_test_file(xspfparser_test.cpp false)
|
||||
add_test_file(library_test.cpp false)
|
||||
#add_test_file(library_test.cpp false)
|
||||
add_test_file(albumcovermanager_test.cpp true)
|
||||
add_test_file(songplaylistitem_test.cpp false)
|
||||
add_test_file(translations_test.cpp false)
|
||||
|
Loading…
x
Reference in New Issue
Block a user