Includes, comments and bugfixes

- Fix includes
- Use common regex (Song::kCoverRemoveDisc) for removing Disc/CD from album
- Remove Disc/CD from album when creating hash
- Make imobiledevice support compile
- Fix setting device on windows
This commit is contained in:
Jonas Kvinge
2018-05-01 00:41:33 +02:00
parent fccbd6790c
commit e337b7933b
518 changed files with 7003 additions and 4693 deletions

View File

@@ -20,45 +20,69 @@
#include "config.h"
#include <stdlib.h>
#include <memory>
#include <utility>
#include <algorithm>
#include <functional>
#include <memory>
#include <iterator>
#include <type_traits>
#include <unordered_map>
#include <stdbool.h>
#include <QApplication>
#include <QBuffer>
#include <QtGlobal>
#include <QObject>
#include <QCoreApplication>
#include <QDirIterator>
#include <QFileInfo>
#include <QLinkedList>
#include <QMimeData>
#include <QMutableListIterator>
#include <QSortFilterProxyModel>
#include <QUndoStack>
#include <QtAlgorithms>
#include <QtConcurrentRun>
#include <QtDebug>
#include <QFuture>
#include <QIODevice>
#include <QDataStream>
#include <QBuffer>
#include <QFile>
#include <QList>
#include <QMap>
#include <QSet>
#include <QMimeData>
#include <QVariant>
#include <QString>
#include <QStringList>
#include <QUrl>
#include <QColor>
#include <QFont>
#include <QBrush>
#include <QLinkedList>
#include <QUndoStack>
#include <QUndoCommand>
#include <QModelIndex>
#include <QAbstractListModel>
#include <QPersistentModelIndex>
#include <QMutableListIterator>
#include <QMutableLinkedListIterator>
#include <QFlags>
#include <QSettings>
#include "core/application.h"
#include "core/closure.h"
#include "core/logging.h"
#include "core/mimedata.h"
#include "core/tagreaderclient.h"
#include "collection/collection.h"
#include "collection/collectionbackend.h"
#include "collection/collectionplaylistitem.h"
#include "playlist.h"
#include "playlistitem.h"
#include "playlistview.h"
#include "playlistsequence.h"
#include "playlistbackend.h"
#include "playlistfilter.h"
#include "playlistitemmimedata.h"
#include "playlistundocommands.h"
#include "playlistview.h"
#include "queue.h"
#include "songloaderinserter.h"
#include "songmimedata.h"
#include "songplaylistitem.h"
#include "core/application.h"
#include "core/closure.h"
#include "core/logging.h"
//#include "core/qhash_qurl.h"
#include "core/tagreaderclient.h"
#include "core/timeconstants.h"
#include "collection/collection.h"
#include "collection/collectionbackend.h"
#include "collection/collectionmodel.h"
#include "collection/collectionplaylistitem.h"
#include "tagreadermessages.pb.h"
using std::placeholders::_1;
using std::placeholders::_2;
@@ -292,8 +316,7 @@ QVariant Playlist::data(const QModelIndex &index, int role) const {
case Qt::ForegroundRole:
if (data(index, Role_IsCurrent).toBool()) {
// Ignore any custom colours for the currently playing item - they might
// clash with the glowing current track indicator.
// Ignore any custom colours for the currently playing item - they might clash with the glowing current track indicator.
return QVariant();
}
@@ -307,8 +330,7 @@ QVariant Playlist::data(const QModelIndex &index, int role) const {
case Qt::BackgroundRole:
if (data(index, Role_IsCurrent).toBool()) {
// Ignore any custom colours for the currently playing item - they might
// clash with the glowing current track indicator.
// Ignore any custom colours for the currently playing item - they might clash with the glowing current track indicator.
return QVariant();
}
@@ -342,7 +364,7 @@ bool Playlist::setData(const QModelIndex &index, const QVariant &value, int role
if (!set_column_value(song, (Column)index.column(), value)) return false;
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile( song.url().toLocalFile(), song);
NewClosure(reply, SIGNAL(Finished(bool)), this, SLOT(SongSaveComplete(TagReaderReply*,QPersistentModelIndex)), reply, QPersistentModelIndex(index));
NewClosure(reply, SIGNAL(Finished(bool)), this, SLOT(SongSaveComplete(TagReaderReply*, QPersistentModelIndex)), reply, QPersistentModelIndex(index));
return true;
@@ -409,13 +431,11 @@ int Playlist::NextVirtualIndex(int i, bool ignore_repeat_track) const {
return i;
}
// If we're not bothered about whether a song is on the same album then
// return the next virtual index, whatever it is.
// If we're not bothered about whether a song is on the same album then return the next virtual index, whatever it is.
if (!album_only) {
++i;
// Advance i until we find any track that is in the filter, skipping
// the selected to be skipped
// Advance i until we find any track that is in the filter, skipping the selected to be skipped
while (i < virtual_items_.count() && (!FilterContainsVirtualIndex(i) || item_at(virtual_items_[i])->GetShouldSkip())) {
++i;
}
@@ -454,8 +474,7 @@ int Playlist::PreviousVirtualIndex(int i, bool ignore_repeat_track) const {
return i;
}
// If we're not bothered about whether a song is on the same album then
// return the previous virtual index, whatever it is.
// If we're not bothered about whether a song is on the same album then return the previous virtual index, whatever it is.
if (!album_only) {
--i;
@@ -563,8 +582,7 @@ void Playlist::set_current_row(int i, bool is_stopping) {
current_virtual_index_ = -1;
}
else if (is_shuffled_ && current_virtual_index_ == -1) {
// This is the first thing we're playing so we want to make sure the array
// is shuffled
// This is the first thing we're playing so we want to make sure the array is shuffled
ReshuffleIndices();
// Bring the one we've been asked to play to the start of the list
@@ -629,8 +647,7 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
if (const SongMimeData *song_data = qobject_cast<const SongMimeData*>(data)) {
// Dragged from a collection
// We want to check if these songs are from the actual local file backend,
// if they are we treat them differently.
// We want to check if these songs are from the actual local file backend, if they are we treat them differently.
if (song_data->backend && song_data->backend->songs_table() == Collection::kSongsTable)
InsertSongItems<CollectionPlaylistItem>(song_data->songs, row, play_now, enqueue_now);
else
@@ -672,8 +689,7 @@ bool Playlist::dropMimeData(const QMimeData *data, Qt::DropAction action, int ro
for (int row : source_rows) items << source_playlist->item_at(row);
if (items.count() > kUndoItemLimit) {
// Too big to keep in the undo stack. Also clear the stack because it
// might have been invalidated.
// Too big to keep in the undo stack. Also clear the stack because it might have been invalidated.
InsertItemsWithoutUndo(items, row, false);
undo_stack_->clear();
}
@@ -725,8 +741,7 @@ void Playlist::MoveItemsWithoutUndo(const QList<int> &source_rows, int pos) {
pos = items_.count();
}
// Take the items out of the list first, keeping track of whether the
// insertion point changes
// Take the items out of the list first, keeping track of whether the insertion point changes
int offset = 0;
int start = pos;
for (int source_row : source_rows) {
@@ -749,7 +764,8 @@ void Playlist::MoveItemsWithoutUndo(const QList<int> &source_rows, int pos) {
if (dest_offset != -1) {
// This index was moved
changePersistentIndex(pidx, index(start + dest_offset, pidx.column(), QModelIndex()));
} else {
}
else {
int d = 0;
for (int source_row : source_rows) {
if (pidx.row() > source_row) d--;
@@ -763,11 +779,11 @@ void Playlist::MoveItemsWithoutUndo(const QList<int> &source_rows, int pos) {
layoutChanged();
Save();
}
void Playlist::MoveItemsWithoutUndo(int start, const QList<int> &dest_rows) {
layoutAboutToBeChanged();
PlaylistItemList moved_items;
@@ -833,8 +849,7 @@ void Playlist::InsertItems(const PlaylistItemList &itemsIn, int pos, bool play_n
const int song_count = songs.length();
QSet<Song> vetoed;
for (SongInsertVetoListener *listener : veto_listeners_) {
for (const Song &song :
listener->AboutToInsertSongs(GetAllSongs(), songs)) {
for (const Song &song : listener->AboutToInsertSongs(GetAllSongs(), songs)) {
// avoid veto-ing a song multiple times
vetoed.insert(song);
}
@@ -865,8 +880,7 @@ void Playlist::InsertItems(const PlaylistItemList &itemsIn, int pos, bool play_n
const int start = pos == -1 ? items_.count() : pos;
if (items.count() > kUndoItemLimit) {
// Too big to keep in the undo stack. Also clear the stack because it
// might have been invalidated.
// Too big to keep in the undo stack. Also clear the stack because it might have been invalidated.
InsertItemsWithoutUndo(items, pos, enqueue);
undo_stack_->clear();
} else {
@@ -943,12 +957,10 @@ void Playlist::InsertSongsOrCollectionItems(const SongList &songs, int pos, bool
void Playlist::UpdateItems(const SongList &songs) {
qLog(Debug) << "Updating playlist with new tracks' info";
// We first convert our songs list into a linked list (a 'real' list),
// because removals are faster with QLinkedList.
// We first convert our songs list into a linked list (a 'real' list), because removals are faster with QLinkedList.
// Next, we walk through the list of playlist's items then the list of songs
// we want to update: if an item corresponds to the song (we rely on URL for
// this), we update the item with the new metadata, then we remove song from
// our list because we will not need to check it again.
// we want to update: if an item corresponds to the song (we rely on URL for this), we update the item with the new metadata,
// then we remove song from our list because we will not need to check it again.
// And we also update undo actions.
QLinkedList<Song> songs_list;
for (const Song &song : songs) songs_list.append(song);
@@ -994,8 +1006,7 @@ QMimeData *Playlist::mimeData(const QModelIndexList &indexes) const {
if (indexes.isEmpty()) return nullptr;
// We only want one index per row, but we can't just take column 0 because
// the user might have hidden it.
// We only want one index per row, but we can't just take column 0 because the user might have hidden it.
const int first_column = indexes.first().column();
QMimeData *data = new QMimeData;
@@ -1164,8 +1175,7 @@ void Playlist::sort(int column, Qt::SortOrder order) {
qStableSort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column_Album, order, _1, _2));
}
else if (column == Column_Filename) {
// When sorting by full paths we also expect a hierarchical order. This
// returns a breath-first ordering of paths.
// When sorting by full paths we also expect a hierarchical order. This returns a breath-first ordering of paths.
qStableSort(begin, new_items.end(), std::bind(&Playlist::CompareItems, Column_Filename, order, _1, _2));
qStableSort(begin, new_items.end(), std::bind(&Playlist::ComparePathDepths, order, _1, _2));
}
@@ -1250,8 +1260,7 @@ void Playlist::ItemsLoaded(QFuture<PlaylistItemList> future) {
PlaylistItemList items = future.result();
// backend returns empty elements for collection items which it couldn't
// match (because they got deleted); we don't need those
// Backend returns empty elements for collection items which it couldn't match (because they got deleted); we don't need those
QMutableListIterator<PlaylistItemPtr> it(items);
while (it.hasNext()) {
PlaylistItemPtr item = it.next();
@@ -1267,8 +1276,7 @@ void Playlist::ItemsLoaded(QFuture<PlaylistItemList> future) {
PlaylistBackend::Playlist p = backend_->GetPlaylist(id_);
// the newly loaded list of items might be shorter than it was before so
// look out for a bad last_played index
// The newly loaded list of items might be shorter than it was before so look out for a bad last_played index
last_played_item_index_ = p.last_played == -1 || p.last_played >= rowCount() ? QModelIndex() : index(p.last_played);
emit RestoreFinished();
@@ -1276,7 +1284,7 @@ void Playlist::ItemsLoaded(QFuture<PlaylistItemList> future) {
QSettings s;
s.beginGroup(kSettingsGroup);
// should we gray out deleted songs asynchronously on startup?
// Should we gray out deleted songs asynchronously on startup?
if (s.value("greyoutdeleted", false).toBool()) {
QtConcurrent::run(this, &Playlist::InvalidateDeletedSongs);
}
@@ -1287,16 +1295,14 @@ static bool DescendingIntLessThan(int a, int b) { return a > b; }
void Playlist::RemoveItemsWithoutUndo(const QList<int> &indicesIn) {
// Sort the indices descending because removing elements 'backwards'
// is easier - indices don't 'move' in the process.
// Sort the indices descending because removing elements 'backwards' is easier - indices don't 'move' in the process.
QList<int> indices = indicesIn;
qSort(indices.begin(), indices.end(), DescendingIntLessThan);
for (int j = 0; j < indices.count(); j++) {
int beginning = indices[j], end = indices[j];
// Splits the indices into sequences. For example this: [1, 2, 4],
// will get split into [1, 2] and [4].
// Splits the indices into sequences. For example this: [1, 2, 4], will get split into [1, 2] and [4].
while (j != indices.count() - 1 && indices[j] == indices[j + 1] + 1) {
beginning--;
j++;
@@ -1315,8 +1321,7 @@ bool Playlist::removeRows(int row, int count, const QModelIndex &parent) {
}
if (count > kUndoItemLimit) {
// Too big to keep in the undo stack. Also clear the stack because it
// might have been invalidated.
// Too big to keep in the undo stack. Also clear the stack because it might have been invalidated.
RemoveItemsWithoutUndo(row, count);
undo_stack_->clear();
}
@@ -1337,14 +1342,12 @@ bool Playlist::removeRows(QList<int> &rows) {
return false;
}
// start from the end to be sure that indices won't 'move' during
// the removal process
// Start from the end to be sure that indices won't 'move' during the removal process
qSort(rows.begin(), rows.end(), qGreater<int>());
QList<int> part;
while (!rows.isEmpty()) {
// we're splitting the input list into sequences of consecutive
// numbers
// we're splitting the input list into sequences of consecutive numbers
part.append(rows.takeFirst());
while (!rows.isEmpty() && rows.first() == part.last() - 1) {
part.append(rows.takeFirst());
@@ -1492,11 +1495,11 @@ void Playlist::Clear() {
const int count = items_.count();
if (count > kUndoItemLimit) {
// Too big to keep in the undo stack. Also clear the stack because it
// might have been invalidated.
// Too big to keep in the undo stack. Also clear the stack because it might have been invalidated.
RemoveItemsWithoutUndo(0, count);
undo_stack_->clear();
} else {
}
else {
undo_stack_->push(new PlaylistUndoCommands::RemoveItems(this, 0, count));
}
@@ -1520,8 +1523,7 @@ void Playlist::RemoveItemsNotInQueue() {
start++;
}
// Figure out how many rows to remove - keep going until we find a row
// that is in the queue
// Figure out how many rows to remove - keep going until we find a row that is in the queue
int count = 1;
forever {
if (start + count >= rowCount()) break;
@@ -1608,8 +1610,7 @@ void Playlist::ReshuffleIndices() {
return;
}
// If the user is already playing a song, advance the begin iterator to
// only shuffle items that haven't been played yet.
// If the user is already playing a song, advance the begin iterator to only shuffle items that haven't been played yet.
QList<int>::iterator begin = virtual_items_.begin();
QList<int>::iterator end = virtual_items_.end();
if (current_virtual_index_ != -1)
@@ -1642,8 +1643,7 @@ void Playlist::ReshuffleIndices() {
std::random_shuffle(shuffled_album_keys.begin(), shuffled_album_keys.end());
// If the user is currently playing a song, force its album to be first
// Or if the song was not playing but it was selected, force its album
// to be first.
// Or if the song was not playing but it was selected, force its album to be first.
if (current_virtual_index_ != -1 || current_row() != -1) {
const QString key = items_[current_row()]->Metadata().AlbumKey();
const int pos = shuffled_album_keys.indexOf(key);
@@ -1741,8 +1741,7 @@ void Playlist::InformOfCurrentSongChange() {
emit dataChanged(index(current_item_index_.row(), 0), index(current_item_index_.row(), ColumnCount - 1));
// if the song is invalid, we won't play it - there's no point in
// informing anybody about the change
// if the song is invalid, we won't play it - there's no point in informing anybody about the change
const Song metadata(current_item_metadata());
if (metadata.is_valid()) {
emit CurrentSongChanged(metadata);
@@ -1845,7 +1844,7 @@ void Playlist::RemoveUnavailableSongs() {
PlaylistItemPtr item = items_[row];
const Song &song = item->Metadata();
// check only local files
// Check only local files
if (song.url().isLocalFile() && !QFile::exists(song.url().toLocalFile())) {
rows_to_remove.append(row);
}
@@ -1862,12 +1861,12 @@ bool Playlist::ApplyValidityOnCurrentSong(const QUrl &url, bool valid) {
if (current) {
Song current_song = current->Metadata();
// if validity has changed, reload the item
// If validity has changed, reload the item
if(!current_song.is_cdda() && current_song.url() == url && current_song.is_valid() != QFile::exists(current_song.url().toLocalFile())) {
ReloadItems(QList<int>() << current_row());
}
// gray out the song if it's now broken; otherwise undo the gray color
// Gray out the song if it's now broken; otherwise undo the gray color
if (valid) {
current->RemoveForegroundColor(kInvalidSongPriority);
} else {