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:
@@ -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 {
|
||||
|
||||
@@ -23,13 +23,31 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QList>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QFuture>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QMimeData>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QColor>
|
||||
#include <QModelIndex>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QPersistentModelIndex>
|
||||
#include <QUndoStack>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "playlistitem.h"
|
||||
#include "playlistsequence.h"
|
||||
#include "core/tagreaderclient.h"
|
||||
#include "core/song.h"
|
||||
|
||||
class CollectionBackend;
|
||||
class PlaylistBackend;
|
||||
@@ -37,33 +55,29 @@ class PlaylistFilter;
|
||||
class Queue;
|
||||
class TaskManager;
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class QUndoStack;
|
||||
|
||||
namespace PlaylistUndoCommands {
|
||||
class InsertItems;
|
||||
class RemoveItems;
|
||||
class MoveItems;
|
||||
class ReOrderItems;
|
||||
class SortItems;
|
||||
class RemoveItems;
|
||||
class ShuffleItems;
|
||||
class SortItems;
|
||||
}
|
||||
|
||||
typedef QMap<int, Qt::Alignment> ColumnAlignmentMap;
|
||||
Q_DECLARE_METATYPE(Qt::Alignment);
|
||||
Q_DECLARE_METATYPE(ColumnAlignmentMap);
|
||||
|
||||
// Objects that may prevent a song being added to the playlist. When there
|
||||
// is something about to be inserted into it, Playlist notifies all of it's
|
||||
// listeners about the fact and every one of them picks 'invalid' songs.
|
||||
// Objects that may prevent a song being added to the playlist.
|
||||
// When there is something about to be inserted into it,
|
||||
// Playlist notifies all of it's listeners about the fact and every one of them picks 'invalid' songs.
|
||||
class SongInsertVetoListener : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// Listener returns a list of 'invalid' songs. 'old_songs' are songs that are
|
||||
// currently in the playlist and 'new_songs' are the songs about to be added if
|
||||
// nobody exercises a veto.
|
||||
virtual SongList AboutToInsertSongs(const SongList& old_songs, const SongList& new_songs) = 0;
|
||||
// Listener returns a list of 'invalid' songs.
|
||||
// 'old_songs' are songs that are currently in the playlist and 'new_songs' are the songs about to be added if nobody exercises a veto.
|
||||
virtual SongList AboutToInsertSongs(const SongList &old_songs, const SongList &new_songs) = 0;
|
||||
};
|
||||
|
||||
class Playlist : public QAbstractListModel {
|
||||
@@ -75,10 +89,10 @@ class Playlist : public QAbstractListModel {
|
||||
friend class PlaylistUndoCommands::ReOrderItems;
|
||||
|
||||
public:
|
||||
Playlist(PlaylistBackend *backend, TaskManager *task_manager, CollectionBackend *collection, int id, const QString& special_type = QString(), bool favorite = false, QObject *parent = nullptr);
|
||||
Playlist(PlaylistBackend *backend, TaskManager *task_manager, CollectionBackend *collection, int id, const QString &special_type = QString(), bool favorite = false, QObject *parent = nullptr);
|
||||
~Playlist();
|
||||
|
||||
void SkipTracks(const QModelIndexList& source_indexes);
|
||||
void SkipTracks(const QModelIndexList &source_indexes);
|
||||
|
||||
// Always add new columns to the end of this enum - the values are persisted
|
||||
enum Column {
|
||||
@@ -123,8 +137,7 @@ class Playlist : public QAbstractListModel {
|
||||
Path_Automatic = 0, // Automatically select path type
|
||||
Path_Absolute, // Always use absolute paths
|
||||
Path_Relative, // Always use relative paths
|
||||
Path_Ask_User, // Only used in preferences: to ask user which of the
|
||||
// previous values he wants to use.
|
||||
Path_Ask_User, // Only used in preferences: to ask user which of the previous values he wants to use.
|
||||
};
|
||||
|
||||
static const char *kCddaMimeType;
|
||||
@@ -151,7 +164,7 @@ class Playlist : public QAbstractListModel {
|
||||
static QString abbreviated_column_name(Column column);
|
||||
|
||||
static bool column_is_editable(Playlist::Column column);
|
||||
static bool set_column_value(Song& song, Column column, const QVariant& value);
|
||||
static bool set_column_value(Song &song, Column column, const QVariant &value);
|
||||
|
||||
// Persistence
|
||||
void Save() const;
|
||||
@@ -162,7 +175,7 @@ class Playlist : public QAbstractListModel {
|
||||
Queue *queue() const { return queue_; }
|
||||
|
||||
int id() const { return id_; }
|
||||
const QString& ui_path() const { return ui_path_; }
|
||||
const QString &ui_path() const { return ui_path_; }
|
||||
void set_ui_path(const QString &path) { ui_path_ = path; }
|
||||
bool is_favorite() const { return favorite_; }
|
||||
void set_favorite(bool favorite) { favorite_ = favorite; }
|
||||
@@ -207,14 +220,12 @@ class Playlist : public QAbstractListModel {
|
||||
void ReshuffleIndices();
|
||||
|
||||
// If this playlist contains the current item, this method will apply the "valid" flag on it.
|
||||
// If the "valid" flag is false, the song will be greyed out. Otherwise the grey color will
|
||||
// be undone.
|
||||
// If the "valid" flag is false, the song will be greyed out. Otherwise the grey color will be undone.
|
||||
// If the song is a local file and it's valid but non existent or invalid but exists, the
|
||||
// song will be reloaded to even out the situation because obviously something has changed.
|
||||
// This returns true if this playlist had current item when the method was invoked.
|
||||
bool ApplyValidityOnCurrentSong(const QUrl &url, bool valid);
|
||||
// Grays out and reloads all deleted songs in all playlists. Also, "ungreys" those songs
|
||||
// which were once deleted but now got restored somehow.
|
||||
// Grays out and reloads all deleted songs in all playlists. Also, "ungreys" those songs which were once deleted but now got restored somehow.
|
||||
void InvalidateDeletedSongs();
|
||||
// Removes from the playlist all local files that don't exist anymore.
|
||||
void RemoveDeletedSongs();
|
||||
@@ -223,8 +234,7 @@ class Playlist : public QAbstractListModel {
|
||||
void ReloadItems(const QList<int> &rows);
|
||||
void InformOfCurrentSongChange();
|
||||
|
||||
// Registers an object which will get notifications when new songs
|
||||
// are about to be inserted into this playlist.
|
||||
// Registers an object which will get notifications when new songs are about to be inserted into this playlist.
|
||||
void AddSongInsertVetoListener(SongInsertVetoListener *listener);
|
||||
// Unregisters a SongInsertVetoListener object.
|
||||
void RemoveSongInsertVetoListener(SongInsertVetoListener *listener);
|
||||
@@ -276,15 +286,13 @@ signals:
|
||||
void EditingFinished(const QModelIndex &index);
|
||||
void PlayRequested(const QModelIndex &index);
|
||||
|
||||
// Signals that the underlying list of items was changed, meaning that
|
||||
// something was added to it, removed from it or the ordering changed.
|
||||
// Signals that the underlying list of items was changed, meaning that something was added to it, removed from it or the ordering changed.
|
||||
void PlaylistChanged();
|
||||
void DynamicModeChanged(bool dynamic);
|
||||
|
||||
void Error(const QString &message);
|
||||
|
||||
// Signals that the queue has changed, meaning that the remaining queued
|
||||
// items should update their position.
|
||||
// Signals that the queue has changed, meaning that the remaining queued items should update their position.
|
||||
void QueueChanged();
|
||||
|
||||
private:
|
||||
@@ -296,8 +304,7 @@ private:
|
||||
template <typename T>
|
||||
void InsertSongItems(const SongList &songs, int pos, bool play_now, bool enqueue);
|
||||
|
||||
// Modify the playlist without changing the undo stack. These are used by
|
||||
// our friends in PlaylistUndoCommands
|
||||
// Modify the playlist without changing the undo stack. These are used by our friends in PlaylistUndoCommands
|
||||
void InsertItemsWithoutUndo(const PlaylistItemList &items, int pos, bool enqueue = false);
|
||||
PlaylistItemList RemoveItemsWithoutUndo(int pos, int count);
|
||||
void MoveItemsWithoutUndo(const QList<int> &source_rows, int pos);
|
||||
@@ -335,10 +342,9 @@ private:
|
||||
bool favorite_;
|
||||
|
||||
PlaylistItemList items_;
|
||||
QList<int> virtual_items_; // Contains the indices into items_ in the order
|
||||
// that they will be played.
|
||||
// A map of collection ID to playlist item - for fast lookups when collection
|
||||
// items change.
|
||||
// Contains the indices into items_ in the order that they will be played.
|
||||
QList<int> virtual_items_;
|
||||
// A map of collection ID to playlist item - for fast lookups when collection items change.
|
||||
QMultiMap<int, PlaylistItemPtr> collection_items_by_id_;
|
||||
|
||||
QPersistentModelIndex current_item_index_;
|
||||
|
||||
@@ -18,16 +18,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistbackend.h"
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QIODevice>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QByteArray>
|
||||
#include <QHash>
|
||||
#include <QMutexLocker>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QtDebug>
|
||||
|
||||
@@ -38,7 +45,9 @@
|
||||
#include "core/song.h"
|
||||
#include "collection/collectionbackend.h"
|
||||
#include "collection/sqlrow.h"
|
||||
#include "playlist/songplaylistitem.h"
|
||||
#include "playlistitem.h"
|
||||
#include "songplaylistitem.h"
|
||||
#include "playlistbackend.h"
|
||||
#include "playlistparsers/cueparser.h"
|
||||
|
||||
using std::placeholders::_1;
|
||||
@@ -46,7 +55,7 @@ using std::shared_ptr;
|
||||
|
||||
const int PlaylistBackend::kSongTableJoins = 2;
|
||||
|
||||
PlaylistBackend::PlaylistBackend(Application* app, QObject* parent)
|
||||
PlaylistBackend::PlaylistBackend(Application *app, QObject *parent)
|
||||
: QObject(parent), app_(app), db_(app_->database()) {}
|
||||
|
||||
PlaylistBackend::PlaylistList PlaylistBackend::GetAllPlaylists() {
|
||||
@@ -63,8 +72,6 @@ PlaylistBackend::PlaylistList PlaylistBackend::GetAllFavoritePlaylists() {
|
||||
|
||||
PlaylistBackend::PlaylistList PlaylistBackend::GetPlaylists(GetPlaylistsFlags flags) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
@@ -157,12 +164,10 @@ QSqlQuery PlaylistBackend::GetPlaylistRows(int playlist) {
|
||||
QList<PlaylistItemPtr> PlaylistBackend::GetPlaylistItems(int playlist) {
|
||||
|
||||
QSqlQuery q = GetPlaylistRows(playlist);
|
||||
// Note that as this only accesses the query, not the db, we don't need the
|
||||
// mutex.
|
||||
// Note that as this only accesses the query, not the db, we don't need the mutex.
|
||||
if (db_->CheckErrors(q)) return QList<PlaylistItemPtr>();
|
||||
|
||||
// it's probable that we'll have a few songs associated with the
|
||||
// same CUE so we're caching results of parsing CUEs
|
||||
// it's probable that we'll have a few songs associated with the same CUE so we're caching results of parsing CUEs
|
||||
std::shared_ptr<NewSongFromQueryState> state_ptr(new NewSongFromQueryState());
|
||||
QList<PlaylistItemPtr> playlistitems;
|
||||
while (q.next()) {
|
||||
@@ -175,12 +180,10 @@ QList<PlaylistItemPtr> PlaylistBackend::GetPlaylistItems(int playlist) {
|
||||
QList<Song> PlaylistBackend::GetPlaylistSongs(int playlist) {
|
||||
|
||||
QSqlQuery q = GetPlaylistRows(playlist);
|
||||
// Note that as this only accesses the query, not the db, we don't need the
|
||||
// mutex.
|
||||
// Note that as this only accesses the query, not the db, we don't need the mutex.
|
||||
if (db_->CheckErrors(q)) return QList<Song>();
|
||||
|
||||
// it's probable that we'll have a few songs associated with the
|
||||
// same CUE so we're caching results of parsing CUEs
|
||||
// it's probable that we'll have a few songs associated with the same CUE so we're caching results of parsing CUEs
|
||||
std::shared_ptr<NewSongFromQueryState> state_ptr(new NewSongFromQueryState());
|
||||
QList<Song> songs;
|
||||
while (q.next()) {
|
||||
@@ -248,10 +251,8 @@ PlaylistItemPtr PlaylistBackend::RestoreCueData(PlaylistItemPtr item, std::share
|
||||
}
|
||||
|
||||
for (const Song& from_list : song_list) {
|
||||
if (from_list.url().toEncoded() == song.url().toEncoded() &&
|
||||
from_list.beginning_nanosec() == song.beginning_nanosec()) {
|
||||
// we found a matching section; replace the input
|
||||
// item with a new one containing CUE metadata
|
||||
if (from_list.url().toEncoded() == song.url().toEncoded() && from_list.beginning_nanosec() == song.beginning_nanosec()) {
|
||||
// we found a matching section; replace the input item with a new one containing CUE metadata
|
||||
return PlaylistItemPtr(new SongPlaylistItem(from_list));
|
||||
}
|
||||
}
|
||||
@@ -268,7 +269,7 @@ void PlaylistBackend::SavePlaylistAsync(int playlist, const PlaylistItemList &it
|
||||
|
||||
}
|
||||
|
||||
void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList& items, int last_played) {
|
||||
void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList &items, int last_played) {
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
@@ -308,7 +309,7 @@ void PlaylistBackend::SavePlaylist(int playlist, const PlaylistItemList& items,
|
||||
|
||||
}
|
||||
|
||||
int PlaylistBackend::CreatePlaylist(const QString& name, const QString& special_type) {
|
||||
int PlaylistBackend::CreatePlaylist(const QString &name, const QString &special_type) {
|
||||
|
||||
QMutexLocker l(db_->Mutex());
|
||||
QSqlDatabase db(db_->Connect());
|
||||
|
||||
@@ -23,11 +23,20 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
#include <QHash>
|
||||
#include <QList>
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QSqlQuery>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "collection/sqlrow.h"
|
||||
#include "playlistitem.h"
|
||||
|
||||
class Application;
|
||||
|
||||
@@ -18,25 +18,43 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <QApplication>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QAction>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QPoint>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QSize>
|
||||
#include <QFont>
|
||||
#include <QIcon>
|
||||
#include <QColor>
|
||||
#include <QFrame>
|
||||
#include <QPalette>
|
||||
#include <QModelIndex>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTimer>
|
||||
#include <QTimeLine>
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QKeySequence>
|
||||
#include <QToolButton>
|
||||
#include <QUndoStack>
|
||||
#include <QtEvents>
|
||||
#include <QSettings>
|
||||
|
||||
#include "core/iconloader.h"
|
||||
#include "playlist.h"
|
||||
#include "playlisttabbar.h"
|
||||
#include "playlistview.h"
|
||||
#include "playlistcontainer.h"
|
||||
#include "playlistmanager.h"
|
||||
#include "ui_playlistcontainer.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "playlistparsers/playlistparser.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTimeLine>
|
||||
#include <QTimer>
|
||||
#include <QUndoStack>
|
||||
#include "ui_playlistcontainer.h"
|
||||
#include "3rdparty/qocoa/qsearchfield.h"
|
||||
|
||||
const char *PlaylistContainer::kSettingsGroup = "Playlist";
|
||||
const int PlaylistContainer::kFilterDelayMs = 100;
|
||||
@@ -127,7 +145,7 @@ void PlaylistContainer::SetActions(QAction *new_playlist, QAction *load_playlist
|
||||
}
|
||||
|
||||
void PlaylistContainer::SetManager(PlaylistManager *manager) {
|
||||
|
||||
|
||||
manager_ = manager;
|
||||
ui_->tab_bar->SetManager(manager);
|
||||
|
||||
@@ -149,7 +167,7 @@ void PlaylistContainer::SetManager(PlaylistManager *manager) {
|
||||
void PlaylistContainer::SetViewModel(Playlist *playlist) {
|
||||
|
||||
if (view()->selectionModel()) {
|
||||
disconnect(view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(SelectionChanged()));
|
||||
disconnect(view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(SelectionChanged()));
|
||||
}
|
||||
if (playlist_ && playlist_->proxy()) {
|
||||
disconnect(playlist_->proxy(), SIGNAL(modelReset()), this, SLOT(UpdateNoMatchesLabel()));
|
||||
@@ -172,7 +190,7 @@ void PlaylistContainer::SetViewModel(Playlist *playlist) {
|
||||
view()->selectionModel()->select(manager_->current_selection(), QItemSelectionModel::ClearAndSelect);
|
||||
playlist->IgnoreSorting(false);
|
||||
|
||||
connect(view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(SelectionChanged()));
|
||||
connect(view()->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(SelectionChanged()));
|
||||
emit ViewSelectionModelChanged();
|
||||
|
||||
// Update filter
|
||||
@@ -180,11 +198,11 @@ void PlaylistContainer::SetViewModel(Playlist *playlist) {
|
||||
|
||||
// Update the no matches label
|
||||
connect(playlist_->proxy(), SIGNAL(modelReset()), SLOT(UpdateNoMatchesLabel()));
|
||||
connect(playlist_->proxy(), SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
|
||||
connect(playlist_->proxy(), SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
|
||||
connect(playlist_->proxy(), SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(UpdateNoMatchesLabel()));
|
||||
connect(playlist_->proxy(), SIGNAL(rowsRemoved(QModelIndex, int, int)), SLOT(UpdateNoMatchesLabel()));
|
||||
connect(playlist_, SIGNAL(modelReset()), SLOT(UpdateNoMatchesLabel()));
|
||||
connect(playlist_, SIGNAL(rowsInserted(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
|
||||
connect(playlist_, SIGNAL(rowsRemoved(QModelIndex,int,int)), SLOT(UpdateNoMatchesLabel()));
|
||||
connect(playlist_, SIGNAL(rowsInserted(QModelIndex, int, int)), SLOT(UpdateNoMatchesLabel()));
|
||||
connect(playlist_, SIGNAL(rowsRemoved(QModelIndex, int, int)), SLOT(UpdateNoMatchesLabel()));
|
||||
UpdateNoMatchesLabel();
|
||||
|
||||
// Ensure that tab is current
|
||||
@@ -241,13 +259,11 @@ void PlaylistContainer::PlaylistAdded(int id, const QString &name, bool favorite
|
||||
}
|
||||
|
||||
if (ui_->tab_bar->count() > 1) {
|
||||
// Have to do this here because sizeHint() is only valid when there's a
|
||||
// tab in the bar.
|
||||
// Have to do this here because sizeHint() is only valid when there's a tab in the bar.
|
||||
tab_bar_animation_->setFrameRange(0, ui_->tab_bar->sizeHint().height());
|
||||
|
||||
if (!isVisible()) {
|
||||
// Skip the animation since the window is hidden (eg. if we're still
|
||||
// loading the UI).
|
||||
// Skip the animation since the window is hidden (eg. if we're still loading the UI).
|
||||
tab_bar_visible_ = true;
|
||||
ui_->tab_bar->setMaximumHeight(tab_bar_animation_->endFrame());
|
||||
} else {
|
||||
@@ -271,8 +287,6 @@ void PlaylistContainer::PlaylistRenamed(int id, const QString &new_name) {
|
||||
void PlaylistContainer::NewPlaylist() { manager_->New(tr("Playlist")); }
|
||||
|
||||
void PlaylistContainer::LoadPlaylist() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QString filename = settings_.value("last_load_playlist").toString();
|
||||
filename = QFileDialog::getOpenFileName(this, tr("Load playlist"), filename, manager_->parser()->filters());
|
||||
@@ -296,8 +310,7 @@ void PlaylistContainer::ClearPlaylist() {
|
||||
|
||||
void PlaylistContainer::GoToNextPlaylistTab() {
|
||||
// Get the next tab' id
|
||||
int id_next = ui_->tab_bar->id_of((ui_->tab_bar->currentIndex() + 1) %
|
||||
ui_->tab_bar->count());
|
||||
int id_next = ui_->tab_bar->id_of((ui_->tab_bar->currentIndex() + 1) % ui_->tab_bar->count());
|
||||
// Switch to next tab
|
||||
manager_->SetCurrentPlaylist(id_next);
|
||||
}
|
||||
@@ -330,8 +343,7 @@ void PlaylistContainer::SetTabBarHeight(int height) {
|
||||
|
||||
void PlaylistContainer::MaybeUpdateFilter() {
|
||||
|
||||
// delaying the filter update on small playlists is undesirable
|
||||
// and an empty filter applies very quickly, too
|
||||
// delaying the filter update on small playlists is undesirable and an empty filter applies very quickly, too
|
||||
if (manager_->current()->rowCount() < kFilterDelayPlaylistSizeThreshold || ui_->filter->text().isEmpty()) {
|
||||
UpdateFilter();
|
||||
}
|
||||
|
||||
@@ -23,19 +23,28 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
#include <QTimer>
|
||||
#include <QTimeLine>
|
||||
#include <QSettings>
|
||||
#include <QAction>
|
||||
#include <QEvent>
|
||||
#include <QLabel>
|
||||
#include <QtEvents>
|
||||
|
||||
class Ui_PlaylistContainer;
|
||||
class QKeyEvent;
|
||||
class QResizeEvent;
|
||||
|
||||
class LineEditInterface;
|
||||
class Playlist;
|
||||
class PlaylistManager;
|
||||
class PlaylistView;
|
||||
|
||||
class QTimeLine;
|
||||
class QTimer;
|
||||
class QLabel;
|
||||
class Ui_PlaylistContainer;
|
||||
|
||||
class PlaylistContainer : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -20,29 +20,55 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFuture>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractItemView>
|
||||
#include <QCompleter>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFuture>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
#include <QHeaderView>
|
||||
#include <QHelpEvent>
|
||||
#include <QLinearGradient>
|
||||
#include <QLineEdit>
|
||||
#include <QLocale>
|
||||
#include <QMetaType>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QUrl>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QColor>
|
||||
#include <QPen>
|
||||
#include <QBrush>
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
#include <QSize>
|
||||
#include <QLineEdit>
|
||||
#include <QScrollBar>
|
||||
#include <QTextDocument>
|
||||
#include <QToolTip>
|
||||
#include <QTreeView>
|
||||
#include <QWhatsThis>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QStyleOptionViewItem>
|
||||
#include <QtDebug>
|
||||
#include <QtEvents>
|
||||
#include <QLinearGradient>
|
||||
|
||||
#include "playlistdelegates.h"
|
||||
|
||||
#include "queue.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/song.h"
|
||||
#include "core/urlhandler.h"
|
||||
#include "core/utilities.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "collection/collectionbackend.h"
|
||||
#include "widgets/trackslider.h"
|
||||
#include "playlist/playlist.h"
|
||||
#include "playlistdelegates.h"
|
||||
|
||||
#ifdef Q_OS_DARWIN
|
||||
#include "core/mac_utilities.h"
|
||||
@@ -202,8 +228,7 @@ QStyleOptionViewItemV4 PlaylistDelegateBase::Adjusted(const QStyleOptionViewItem
|
||||
QStyleOptionViewItemV4 ret(option);
|
||||
|
||||
if (index.data(Playlist::Role_IsCurrent).toBool()) {
|
||||
// Move the text in a bit on the first column for the song that's currently
|
||||
// playing
|
||||
// Move the text in a bit on the first column for the song that's currently playing
|
||||
ret.rect.setLeft(ret.rect.left() + 20);
|
||||
}
|
||||
|
||||
@@ -213,9 +238,7 @@ QStyleOptionViewItemV4 PlaylistDelegateBase::Adjusted(const QStyleOptionViewItem
|
||||
|
||||
bool PlaylistDelegateBase::helpEvent(QHelpEvent *event, QAbstractItemView *view, const QStyleOptionViewItem &option, const QModelIndex &index) {
|
||||
|
||||
// This function is copied from QAbstractItemDelegate, and changed to show
|
||||
// displayText() in the tooltip, rather than the index's naked
|
||||
// Qt::ToolTipRole text.
|
||||
// This function is copied from QAbstractItemDelegate, and changed to show displayText() in the tooltip, rather than the index's naked Qt::ToolTipRole text.
|
||||
|
||||
Q_UNUSED(option);
|
||||
|
||||
@@ -246,7 +269,8 @@ bool PlaylistDelegateBase::helpEvent(QHelpEvent *event, QAbstractItemView *view,
|
||||
is_elided = displayed_text.width() < real_text.width();
|
||||
if (is_elided) {
|
||||
QToolTip::showText(he->globalPos(), text, view);
|
||||
} else { // in case that another text was previously displayed
|
||||
}
|
||||
else { // in case that another text was previously displayed
|
||||
QToolTip::hideText();
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -23,16 +23,36 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QFuture>
|
||||
#include <QCompleter>
|
||||
#include <QLocale>
|
||||
#include <QVariant>
|
||||
#include <QUrl>
|
||||
#include <QPixmap>
|
||||
#include <QPixmapCache>
|
||||
#include <QPainter>
|
||||
#include <QRect>
|
||||
#include <QColor>
|
||||
#include <QSize>
|
||||
#include <QFont>
|
||||
#include <QString>
|
||||
#include <QStringListModel>
|
||||
#include <QModelIndex>
|
||||
#include <QStyleOption>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QAbstractItemView>
|
||||
#include <QStyleOptionViewItem>
|
||||
#include <QHelpEvent>
|
||||
#include <QLineEdit>
|
||||
#include <QTreeView>
|
||||
|
||||
#include "playlist.h"
|
||||
#include "collection/collection.h"
|
||||
#include "widgets/ratingwidget.h"
|
||||
|
||||
class CollectionBackend;
|
||||
class Player;
|
||||
|
||||
class QueuedItemDelegate : public QStyledItemDelegate {
|
||||
@@ -142,8 +162,7 @@ class TagCompletionItemDelegate : public PlaylistDelegateBase {
|
||||
public:
|
||||
TagCompletionItemDelegate(QObject *parent, CollectionBackend *backend, Playlist::Column column) : PlaylistDelegateBase(parent), backend_(backend), column_(column) {};
|
||||
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const;
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
private:
|
||||
CollectionBackend *backend_;
|
||||
|
||||
@@ -20,11 +20,18 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QRegExp>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "playlist/playlist.h"
|
||||
#include "playlistfilter.h"
|
||||
#include "playlistfilterparser.h"
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
PlaylistFilter::PlaylistFilter(QObject *parent)
|
||||
: QSortFilterProxyModel(parent),
|
||||
filter_tree_(new NopFilter),
|
||||
|
||||
@@ -23,13 +23,18 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QScopedPointer>
|
||||
#include <QString>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "playlist.h"
|
||||
|
||||
#include <QSet>
|
||||
|
||||
class FilterTree;
|
||||
|
||||
class PlaylistFilter : public QSortFilterProxyModel {
|
||||
|
||||
@@ -20,12 +20,21 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistfilterparser.h"
|
||||
#include "playlist.h"
|
||||
#include "core/logging.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QChar>
|
||||
#include <QScopedPointer>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QtAlgorithms>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include "playlist.h"
|
||||
#include "playlistfilterparser.h"
|
||||
|
||||
class SearchTermComparator {
|
||||
public:
|
||||
virtual ~SearchTermComparator() {}
|
||||
@@ -143,11 +152,9 @@ class LeComparator : public SearchTermComparator {
|
||||
int search_term_;
|
||||
};
|
||||
|
||||
// The length field of the playlist (entries) contains a
|
||||
// song's running time in nano seconds. However, We don't
|
||||
// really care about nano seconds, just seconds. Thus, with
|
||||
// this decorator we drop the last 9 digits, if that many
|
||||
// are present.
|
||||
// The length field of the playlist (entries) contains a song's running time in nano seconds.
|
||||
// However, We don't really care about nano seconds, just seconds.
|
||||
// Thus, with this decorator we drop the last 9 digits, if that many are present.
|
||||
class DropTailComparatorDecorator : public SearchTermComparator {
|
||||
public:
|
||||
explicit DropTailComparatorDecorator(SearchTermComparator *cmp) : cmp_(cmp) {}
|
||||
@@ -178,8 +185,7 @@ class FilterTerm : public FilterTree {
|
||||
public:
|
||||
explicit FilterTerm(SearchTermComparator *comparator, const QList<int> &columns) : cmp_(comparator), columns_(columns) {}
|
||||
|
||||
virtual bool accept(int row, const QModelIndex &parent,
|
||||
const QAbstractItemModel *const model) const {
|
||||
virtual bool accept(int row, const QModelIndex &parent, const QAbstractItemModel *const model) const {
|
||||
for (int i : columns_) {
|
||||
QModelIndex idx(model->index(row, i, parent));
|
||||
if (cmp_->Matches(idx.data().toString().toLower())) return true;
|
||||
@@ -399,8 +405,7 @@ FilterTree *FilterParser::parseSearchTerm() {
|
||||
*iter_ == '-') {
|
||||
break;
|
||||
} else if (buf_.isEmpty()) {
|
||||
// we don't know whether there is a column part in this search term
|
||||
// thus we assume the latter and just try and read a prefix
|
||||
// we don't know whether there is a column part in this search term thus we assume the latter and just try and read a prefix
|
||||
if (prefix.isEmpty() && (*iter_ == '>' || *iter_ == '<' || *iter_ == '=' || *iter_ == '!')) {
|
||||
prefix += *iter_;
|
||||
}
|
||||
@@ -435,8 +440,7 @@ FilterTree *FilterParser::createSearchTermTreeNode(
|
||||
cmp = new NeComparator(search);
|
||||
}
|
||||
else if (!col.isEmpty() && columns_.contains(col) && numerical_columns_.contains(columns_[col])) {
|
||||
// the length column contains the time in seconds (nano seconds, actually -
|
||||
// the "nano" part is handled by the DropTailComparatorDecorator, though).
|
||||
// the length column contains the time in seconds (nano seconds, actually - the "nano" part is handled by the DropTailComparatorDecorator, though).
|
||||
int search_value;
|
||||
if (columns_[col] == Playlist::Column_Length) {
|
||||
search_value = parseTime(search);
|
||||
|
||||
@@ -23,12 +23,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QMap>
|
||||
#include <QModelIndex>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
class QAbstractItemModel;
|
||||
class QModelIndex;
|
||||
|
||||
// structure for filter parse tree
|
||||
class FilterTree {
|
||||
@@ -80,9 +82,7 @@ class FilterParser {
|
||||
void advance();
|
||||
FilterTree *parseOrGroup();
|
||||
FilterTree *parseAndGroup();
|
||||
// check if iter is at the start of 'AND'
|
||||
// if so, step over it and return true
|
||||
// it not, return false and leave iter where it was
|
||||
// check if iter is at the start of 'AND' if so, step over it and return true if not, return false and leave iter where it was
|
||||
bool checkAnd();
|
||||
// check if iter is at the start of 'OR'
|
||||
bool checkOr(bool step_over = true);
|
||||
|
||||
@@ -20,13 +20,23 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistheader.h"
|
||||
#include "playlistview.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QtDebug>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QWidget>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QFlags>
|
||||
#include <QMenu>
|
||||
#include <QSignalMapper>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QtAlgorithms>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "playlistheader.h"
|
||||
#include "playlistview.h"
|
||||
|
||||
PlaylistHeader::PlaylistHeader(Qt::Orientation orientation, PlaylistView *view, QWidget *parent)
|
||||
: StretchHeaderView(orientation, parent),
|
||||
|
||||
@@ -23,13 +23,21 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QList>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QSignalMapper>
|
||||
#include <QString>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "widgets/stretchheaderview.h"
|
||||
|
||||
class PlaylistView;
|
||||
|
||||
class QMenu;
|
||||
class QSignalMapper;
|
||||
|
||||
class PlaylistHeader : public StretchHeaderView {
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -20,17 +20,22 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistitem.h"
|
||||
#include "songplaylistitem.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/song.h"
|
||||
#include "collection/collection.h"
|
||||
#include "collection/collectionplaylistitem.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QSqlQuery>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFuture>
|
||||
#include <QString>
|
||||
#include <QColor>
|
||||
#include <QSqlQuery>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "core/logging.h"
|
||||
#include "core/song.h"
|
||||
|
||||
#include "collection/collection.h"
|
||||
#include "collection/collectionplaylistitem.h"
|
||||
#include "playlistitem.h"
|
||||
#include "songplaylistitem.h"
|
||||
|
||||
PlaylistItem::~PlaylistItem() {
|
||||
}
|
||||
|
||||
@@ -24,16 +24,24 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QFuture>
|
||||
#include <QMap>
|
||||
#include <QFlags>
|
||||
#include <QMetaType>
|
||||
#include <QStandardItem>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QColor>
|
||||
#include <QVector>
|
||||
#include <QAction>
|
||||
#include <QSqlQuery>
|
||||
|
||||
#include "core/song.h"
|
||||
|
||||
class QAction;
|
||||
class SqlRow;
|
||||
|
||||
class PlaylistItem : public std::enable_shared_from_this<PlaylistItem> {
|
||||
@@ -87,11 +95,8 @@ class PlaylistItem : public std::enable_shared_from_this<PlaylistItem> {
|
||||
QColor GetCurrentForegroundColor() const;
|
||||
bool HasCurrentForegroundColor() const;
|
||||
|
||||
// Convenience function to find out whether this item is from the local
|
||||
// collection, as opposed to a device, a file on disk, or a stream.
|
||||
// Remember that even if this returns true, the collection item might be
|
||||
// invalid so you might want to check that its id is not equal to -1
|
||||
// before actually using it.
|
||||
// Convenience function to find out whether this item is from the local collection, as opposed to a device, a file on disk, or a stream.
|
||||
// Remember that even if this returns true, the collection item might be invalid so you might want to check that its id is not equal to -1 before actually using it.
|
||||
virtual bool IsLocalCollectionItem() const { return false; }
|
||||
void SetShouldSkip(bool val);
|
||||
bool GetShouldSkip() const;
|
||||
|
||||
@@ -23,8 +23,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistitem.h"
|
||||
#include <QObject>
|
||||
|
||||
#include "core/mimedata.h"
|
||||
#include "playlistitem.h"
|
||||
|
||||
class PlaylistItemMimeData : public MimeData {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -20,23 +20,39 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QContextMenuEvent>
|
||||
#include <QInputDialog>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QAction>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QIcon>
|
||||
#include <QSize>
|
||||
#include <QStandardItemModel>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QPersistentModelIndex>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
#include <QToolButton>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/player.h"
|
||||
#include "playlist.h"
|
||||
#include "playlistbackend.h"
|
||||
#include "playlistlistview.h"
|
||||
#include "playlistlistcontainer.h"
|
||||
#include "playlistlistmodel.h"
|
||||
#include "playlistmanager.h"
|
||||
#include "ui_playlistlistcontainer.h"
|
||||
#include "core/application.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/iconloader.h"
|
||||
|
||||
class PlaylistListSortFilterModel : public QSortFilterProxyModel {
|
||||
public:
|
||||
@@ -50,8 +66,7 @@ public:
|
||||
if (ret < 0) return true;
|
||||
if (ret > 0) return false;
|
||||
|
||||
// Now use the source model row order to ensure we always get a
|
||||
// deterministic sorting even when two items are named the same.
|
||||
// Now use the source model row order to ensure we always get a deterministic sorting even when two items are named the same.
|
||||
return left.row() < right.row();
|
||||
}
|
||||
};
|
||||
@@ -152,7 +167,7 @@ void PlaylistListContainer::SetApplication(Application *app) {
|
||||
connect(manager, SIGNAL(CurrentChanged(Playlist*)), SLOT(CurrentChanged(Playlist*)));
|
||||
connect(manager, SIGNAL(ActiveChanged(Playlist*)), SLOT(ActiveChanged(Playlist*)));
|
||||
|
||||
connect(model_, SIGNAL(PlaylistRenamed(int,QString)), manager, SLOT(Rename(int,QString)));
|
||||
connect(model_, SIGNAL(PlaylistRenamed(int, QString)), manager, SLOT(Rename(int, QString)));
|
||||
|
||||
connect(player, SIGNAL(Paused()), SLOT(ActivePaused()));
|
||||
connect(player, SIGNAL(Playing()), SLOT(ActivePlaying()));
|
||||
@@ -187,8 +202,7 @@ void PlaylistListContainer::AddPlaylist(int id, const QString &name, bool favori
|
||||
}
|
||||
|
||||
if (model_->PlaylistById(id)) {
|
||||
// We know about this playlist already - it was probably one of the open
|
||||
// ones that was loaded on startup.
|
||||
// We know about this playlist already - it was probably one of the open ones that was loaded on startup.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,14 +23,19 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistbackend.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QStandardItem>
|
||||
#include <QtEvents>
|
||||
|
||||
class QMenu;
|
||||
class QSortFilterProxyModel;
|
||||
class QStandardItemModel;
|
||||
|
||||
class QModelIndex;
|
||||
class Application;
|
||||
class Playlist;
|
||||
class PlaylistListModel;
|
||||
|
||||
@@ -20,10 +20,17 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistlistmodel.h"
|
||||
#include "core/logging.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QFlags>
|
||||
#include <QMimeData>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QIcon>
|
||||
#include <QStandardItemModel>
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include "playlistlistmodel.h"
|
||||
|
||||
PlaylistListModel::PlaylistListModel(QObject *parent) : QStandardItemModel(parent), dropping_rows_(false) {
|
||||
|
||||
@@ -112,7 +119,7 @@ void PlaylistListModel::AddRowItem(QStandardItem *item, const QString &parent_pa
|
||||
|
||||
}
|
||||
|
||||
void PlaylistListModel::RowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) {
|
||||
void PlaylistListModel::RowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) {
|
||||
|
||||
for (int i = start; i <= end; ++i) {
|
||||
const QModelIndex idx = index(i, 0, parent);
|
||||
|
||||
@@ -23,7 +23,17 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QStandardItemModel>
|
||||
#include <QMap>
|
||||
#include <QIcon>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QMimeData>
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
class PlaylistListModel : public QStandardItemModel {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -20,9 +20,16 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistlistview.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFlags>
|
||||
#include <QFont>
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
#include <QRect>
|
||||
|
||||
#include "playlistlistview.h"
|
||||
|
||||
PlaylistListView::PlaylistListView(QWidget *parent)
|
||||
: AutoExpandingTreeView(parent) {}
|
||||
|
||||
@@ -18,8 +18,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PLAYLISTVIEW_H
|
||||
#define PLAYLISTVIEW_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
#include <QPaintEvent>
|
||||
|
||||
#include "widgets/autoexpandingtreeview.h"
|
||||
|
||||
class PlaylistListView : public AutoExpandingTreeView {
|
||||
@@ -31,5 +39,7 @@ class PlaylistListView : public AutoExpandingTreeView {
|
||||
|
||||
protected:
|
||||
// QWidget
|
||||
void paintEvent(QPaintEvent* event);
|
||||
void paintEvent(QPaintEvent *event);
|
||||
};
|
||||
|
||||
#endif // PLAYLISTVIEW_H
|
||||
|
||||
@@ -20,29 +20,45 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QDialog>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFuture>
|
||||
#include <QDir>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFuture>
|
||||
#include <QMessageBox>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
#include <QRegExp>
|
||||
#include <QUrl>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "playlistmanager.h"
|
||||
|
||||
#include "playlistbackend.h"
|
||||
#include "playlistcontainer.h"
|
||||
#include "playlistmanager.h"
|
||||
#include "playlistsaveoptionsdialog.h"
|
||||
#include "playlistview.h"
|
||||
#include "core/application.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/songloader.h"
|
||||
#include "core/utilities.h"
|
||||
#include "collection/collectionbackend.h"
|
||||
#include "collection/collectionplaylistitem.h"
|
||||
#include "playlist.h"
|
||||
#include "playlistbackend.h"
|
||||
#include "playlistcontainer.h"
|
||||
#include "playlistmanager.h"
|
||||
#include "playlistitem.h"
|
||||
#include "playlistview.h"
|
||||
#include "playlistsaveoptionsdialog.h"
|
||||
#include "playlistparsers/playlistparser.h"
|
||||
|
||||
class ParserBase;
|
||||
|
||||
PlaylistManager::PlaylistManager(Application *app, QObject *parent)
|
||||
: PlaylistManagerInterface(app, parent),
|
||||
app_(app),
|
||||
@@ -176,9 +192,7 @@ void PlaylistManager::Save(int id, const QString &filename, Playlist::Path path_
|
||||
parser_->Save(playlist(id)->GetAllSongs(), filename, path_type);
|
||||
}
|
||||
else {
|
||||
// Playlist is not in the playlist manager: probably save action was
|
||||
// triggered
|
||||
// from the left side bar and the playlist isn't loaded.
|
||||
// Playlist is not in the playlist manager: probably save action was triggered from the left side bar and the playlist isn't loaded.
|
||||
QFuture<QList<Song>> future = QtConcurrent::run(playlist_backend_, &PlaylistBackend::GetPlaylistSongs, id);
|
||||
|
||||
NewClosure(future, this, SLOT(ItemsLoadedForSavePlaylist(QFuture<SongList>, QString, Playlist::Path)), future, filename, path_type);
|
||||
@@ -272,17 +286,14 @@ void PlaylistManager::Rename(int id, const QString &new_name) {
|
||||
void PlaylistManager::Favorite(int id, bool favorite) {
|
||||
|
||||
if (playlists_.contains(id)) {
|
||||
// If playlists_ contains this playlist, its means it's opened: star or
|
||||
// unstar it.
|
||||
// If playlists_ contains this playlist, its means it's opened: star or unstar it.
|
||||
playlist_backend_->FavoritePlaylist(id, favorite);
|
||||
playlists_[id].p->set_favorite(favorite);
|
||||
}
|
||||
else {
|
||||
Q_ASSERT(!favorite);
|
||||
// Otherwise it means user wants to remove this playlist from the left
|
||||
// panel,
|
||||
// while it's not visible in the playlist tabbar either, because it has been
|
||||
// closed: delete it.
|
||||
// Otherwise it means user wants to remove this playlist from the left panel,
|
||||
// while it's not visible in the playlist tabbar either, because it has been closed: delete it.
|
||||
playlist_backend_->RemovePlaylist(id);
|
||||
}
|
||||
emit PlaylistFavorited(id, favorite);
|
||||
@@ -359,9 +370,8 @@ void PlaylistManager::SetActivePlaylist(int id) {
|
||||
void PlaylistManager::SetActiveToCurrent() {
|
||||
|
||||
// Check if we need to update the active playlist.
|
||||
// By calling SetActiveToCurrent, the playlist manager emits the signal
|
||||
// "ActiveChanged". This signal causes the network remote module to
|
||||
// send all playlists to the clients, even no change happend.
|
||||
// By calling SetActiveToCurrent, the playlist manager emits the signal "ActiveChanged".
|
||||
// This signal causes the network remote module to send all playlists to the clients, even no change happend.
|
||||
if (current_id() != active_id()) {
|
||||
SetActivePlaylist(current_id());
|
||||
}
|
||||
|
||||
@@ -23,11 +23,16 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QItemSelection>
|
||||
#include <QMap>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QFuture>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QModelIndex>
|
||||
#include <QItemSelectionModel>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "playlist.h"
|
||||
@@ -38,10 +43,6 @@ class PlaylistBackend;
|
||||
class PlaylistContainer;
|
||||
class PlaylistParser;
|
||||
class PlaylistSequence;
|
||||
class TaskManager;
|
||||
|
||||
class QModelIndex;
|
||||
class QUrl;
|
||||
|
||||
class PlaylistManagerInterface : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -76,22 +77,22 @@ public:
|
||||
virtual PlaylistContainer *playlist_container() const = 0;
|
||||
|
||||
public slots:
|
||||
virtual void New(const QString& name, const SongList& songs = SongList(), const QString& special_type = QString()) = 0;
|
||||
virtual void Load(const QString& filename) = 0;
|
||||
virtual void Save(int id, const QString& filename, Playlist::Path path_type) = 0;
|
||||
virtual void Rename(int id, const QString& new_name) = 0;
|
||||
virtual void New(const QString &name, const SongList& songs = SongList(), const QString &special_type = QString()) = 0;
|
||||
virtual void Load(const QString &filename) = 0;
|
||||
virtual void Save(int id, const QString &filename, Playlist::Path path_type) = 0;
|
||||
virtual void Rename(int id, const QString &new_name) = 0;
|
||||
virtual void Delete(int id) = 0;
|
||||
virtual bool Close(int id) = 0;
|
||||
virtual void Open(int id) = 0;
|
||||
virtual void ChangePlaylistOrder(const QList<int>& ids) = 0;
|
||||
|
||||
virtual void SongChangeRequestProcessed(const QUrl& url, bool valid) = 0;
|
||||
virtual void SongChangeRequestProcessed(const QUrl &url, bool valid) = 0;
|
||||
|
||||
virtual void SetCurrentPlaylist(int id) = 0;
|
||||
virtual void SetActivePlaylist(int id) = 0;
|
||||
virtual void SetActiveToCurrent() = 0;
|
||||
|
||||
virtual void SelectionChanged(const QItemSelection& selection) = 0;
|
||||
virtual void SelectionChanged(const QItemSelection &selection) = 0;
|
||||
|
||||
// Convenience slots that defer to either current() or active()
|
||||
virtual void ClearCurrent() = 0;
|
||||
@@ -105,22 +106,21 @@ public slots:
|
||||
signals:
|
||||
void PlaylistManagerInitialized();
|
||||
|
||||
void PlaylistAdded(int id, const QString& name, bool favorite);
|
||||
void PlaylistAdded(int id, const QString &name, bool favorite);
|
||||
void PlaylistDeleted(int id);
|
||||
void PlaylistClosed(int id);
|
||||
void PlaylistRenamed(int id, const QString& new_name);
|
||||
void PlaylistRenamed(int id, const QString &new_name);
|
||||
void PlaylistFavorited(int id, bool favorite);
|
||||
void CurrentChanged(Playlist *new_playlist);
|
||||
void ActiveChanged(Playlist *new_playlist);
|
||||
|
||||
void Error(const QString& message);
|
||||
void SummaryTextChanged(const QString& summary);
|
||||
void Error(const QString &message);
|
||||
void SummaryTextChanged(const QString &summary);
|
||||
|
||||
// Forwarded from individual playlists
|
||||
void CurrentSongChanged(const Song& song);
|
||||
|
||||
// Signals that one of manager's playlists has changed (new items, new
|
||||
// ordering etc.) - the argument shows which.
|
||||
// Signals that one of manager's playlists has changed (new items, new ordering etc.) - the argument shows which.
|
||||
void PlaylistChanged(Playlist *playlist);
|
||||
void EditingFinished(const QModelIndex& index);
|
||||
void PlayRequested(const QModelIndex& index);
|
||||
@@ -168,12 +168,12 @@ class PlaylistManager : public PlaylistManagerInterface {
|
||||
PlaylistContainer *playlist_container() const { return playlist_container_; }
|
||||
|
||||
public slots:
|
||||
void New(const QString& name, const SongList& songs = SongList(), const QString& special_type = QString());
|
||||
void Load(const QString& filename);
|
||||
void Save(int id, const QString& filename, Playlist::Path path_type);
|
||||
void New(const QString &name, const SongList &songs = SongList(), const QString &special_type = QString());
|
||||
void Load(const QString &filename);
|
||||
void Save(int id, const QString &filename, Playlist::Path path_type);
|
||||
// Display a file dialog to let user choose a file before saving the file
|
||||
void SaveWithUI(int id, const QString& playlist_name);
|
||||
void Rename(int id, const QString& new_name);
|
||||
void SaveWithUI(int id, const QString &playlist_name);
|
||||
void Rename(int id, const QString &new_name);
|
||||
void Favorite(int id, bool favorite);
|
||||
void Delete(int id);
|
||||
bool Close(int id);
|
||||
@@ -184,7 +184,7 @@ public slots:
|
||||
void SetActivePlaylist(int id);
|
||||
void SetActiveToCurrent();
|
||||
|
||||
void SelectionChanged(const QItemSelection& selection);
|
||||
void SelectionChanged(const QItemSelection &selection);
|
||||
|
||||
// Makes a playlist current if it's open already, or opens it and makes it current if it is hidden.
|
||||
void SetCurrentOrOpen(int id);
|
||||
@@ -216,7 +216,7 @@ public slots:
|
||||
void ItemsLoadedForSavePlaylist(QFuture<SongList> future, const QString& filename, Playlist::Path path_type);
|
||||
|
||||
private:
|
||||
Playlist *AddPlaylist(int id, const QString& name, const QString& special_type, const QString& ui_path, bool favorite);
|
||||
Playlist *AddPlaylist(int id, const QString& name, const QString &special_type, const QString& ui_path, bool favorite);
|
||||
|
||||
private:
|
||||
struct Data {
|
||||
|
||||
@@ -20,13 +20,17 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistsaveoptionsdialog.h"
|
||||
|
||||
#include "ui_playlistsaveoptionsdialog.h"
|
||||
#include "playlistparsers/parserbase.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
#include <QVariant>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QSettings>
|
||||
|
||||
#include "playlist.h"
|
||||
#include "playlistsaveoptionsdialog.h"
|
||||
#include "ui_playlistsaveoptionsdialog.h"
|
||||
|
||||
const char *PlaylistSaveOptionsDialog::kSettingsGroup = "PlaylistSaveOptionsDialog";
|
||||
|
||||
PlaylistSaveOptionsDialog::PlaylistSaveOptionsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::PlaylistSaveOptionsDialog) {
|
||||
|
||||
@@ -23,7 +23,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
#include "playlist.h"
|
||||
|
||||
|
||||
@@ -20,15 +20,21 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QMenu>
|
||||
#include <QSize>
|
||||
#include <QVariant>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QToolButton>
|
||||
|
||||
#include "core/iconloader.h"
|
||||
#include "core/settingsprovider.h"
|
||||
#include "playlistsequence.h"
|
||||
#include "ui_playlistsequence.h"
|
||||
#include "core/iconloader.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QActionGroup>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
#include <QPainter>
|
||||
|
||||
const char *PlaylistSequence::kSettingsGroup = "PlaylistSequence";
|
||||
|
||||
@@ -40,8 +46,7 @@ PlaylistSequence::PlaylistSequence(QWidget *parent, SettingsProvider *settings)
|
||||
shuffle_menu_(new QMenu(this)),
|
||||
loading_(false),
|
||||
repeat_mode_(Repeat_Off),
|
||||
shuffle_mode_(Shuffle_Off),
|
||||
dynamic_(false)
|
||||
shuffle_mode_(Shuffle_Off)
|
||||
{
|
||||
|
||||
ui_->setupUi(this);
|
||||
@@ -189,7 +194,6 @@ void PlaylistSequence::SetShuffleMode(ShuffleMode mode) {
|
||||
case Shuffle_Albums: ui_->action_shuffle_albums->setChecked(true); break;
|
||||
}
|
||||
|
||||
|
||||
if (mode != shuffle_mode_) {
|
||||
shuffle_mode_ = mode;
|
||||
emit ShuffleModeChanged(mode);
|
||||
@@ -199,23 +203,12 @@ void PlaylistSequence::SetShuffleMode(ShuffleMode mode) {
|
||||
|
||||
}
|
||||
|
||||
void PlaylistSequence::SetUsingDynamicPlaylist(bool dynamic) {
|
||||
|
||||
dynamic_ = dynamic;
|
||||
const QString not_available(tr("Not available while using a dynamic playlist"));
|
||||
|
||||
setEnabled(!dynamic);
|
||||
ui_->shuffle->setToolTip(dynamic ? not_available : tr("Shuffle"));
|
||||
ui_->repeat->setToolTip(dynamic ? not_available : tr("Repeat"));
|
||||
|
||||
}
|
||||
|
||||
PlaylistSequence::ShuffleMode PlaylistSequence::shuffle_mode() const {
|
||||
return dynamic_ ? Shuffle_Off : shuffle_mode_;
|
||||
return shuffle_mode_;
|
||||
}
|
||||
|
||||
PlaylistSequence::RepeatMode PlaylistSequence::repeat_mode() const {
|
||||
return dynamic_ ? Repeat_Off : repeat_mode_;
|
||||
return repeat_mode_;
|
||||
}
|
||||
|
||||
//called from global shortcut
|
||||
|
||||
@@ -24,13 +24,17 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
#include <QPixmap>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
|
||||
#include "core/settingsprovider.h"
|
||||
|
||||
class QMenu;
|
||||
|
||||
class SettingsProvider;
|
||||
class Ui_PlaylistSequence;
|
||||
|
||||
class PlaylistSequence : public QWidget {
|
||||
@@ -68,7 +72,6 @@ class PlaylistSequence : public QWidget {
|
||||
void SetShuffleMode(PlaylistSequence::ShuffleMode mode);
|
||||
void CycleShuffleMode();
|
||||
void CycleRepeatMode();
|
||||
void SetUsingDynamicPlaylist(bool dynamic);
|
||||
|
||||
signals:
|
||||
void RepeatModeChanged(PlaylistSequence::RepeatMode mode);
|
||||
@@ -94,7 +97,7 @@ class PlaylistSequence : public QWidget {
|
||||
bool loading_;
|
||||
RepeatMode repeat_mode_;
|
||||
ShuffleMode shuffle_mode_;
|
||||
bool dynamic_;
|
||||
|
||||
};
|
||||
|
||||
#endif // PLAYLISTSEQUENCE_H
|
||||
|
||||
@@ -20,25 +20,39 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
#include <QAction>
|
||||
#include <QGridLayout>
|
||||
#include <QInputDialog>
|
||||
#include <QLayout>
|
||||
#include <QLineEdit>
|
||||
#include <QMimeData>
|
||||
#include <QRect>
|
||||
#include <QSize>
|
||||
#include <QToolTip>
|
||||
#include <QLayoutItem>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QTabBar>
|
||||
#include <QCheckBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QtEvents>
|
||||
#include <QSettings>
|
||||
|
||||
#include "core/iconloader.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/mimedata.h"
|
||||
#include "core/song.h"
|
||||
#include "widgets/favoritewidget.h"
|
||||
#include "widgets/renametablineedit.h"
|
||||
#include "playlist.h"
|
||||
#include "playlistmanager.h"
|
||||
#include "playlisttabbar.h"
|
||||
#include "playlistview.h"
|
||||
#include "songmimedata.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "widgets/renametablineedit.h"
|
||||
#include "widgets/favoritewidget.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QInputDialog>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QToolTip>
|
||||
|
||||
const char *PlaylistTabBar::kSettingsGroup = "PlaylistTabBar";
|
||||
|
||||
@@ -91,8 +105,7 @@ void PlaylistTabBar::SetManager(PlaylistManager *manager) {
|
||||
|
||||
void PlaylistTabBar::PlaylistManagerInitialized() {
|
||||
|
||||
// Signal that we are done loading and thus further changes should be
|
||||
// committed to the db.
|
||||
// Signal that we are done loading and thus further changes should be committed to the db.
|
||||
initialized_ = true;
|
||||
disconnect(manager_, SIGNAL(PlaylistManagerInitialized()), this, SLOT(PlaylistManagerInitialized()));
|
||||
|
||||
@@ -100,7 +113,7 @@ void PlaylistTabBar::PlaylistManagerInitialized() {
|
||||
|
||||
void PlaylistTabBar::contextMenuEvent(QContextMenuEvent *e) {
|
||||
|
||||
//we need to finish the renaming action before showing context menu
|
||||
// We need to finish the renaming action before showing context menu
|
||||
if (rename_editor_->isVisible()) {
|
||||
//discard any change
|
||||
HideEditor();
|
||||
@@ -128,10 +141,10 @@ void PlaylistTabBar::mouseReleaseEvent(QMouseEvent *e) {
|
||||
}
|
||||
|
||||
void PlaylistTabBar::mouseDoubleClickEvent(QMouseEvent *e) {
|
||||
|
||||
|
||||
int index = tabAt(e->pos());
|
||||
|
||||
// discard a double click with the middle button
|
||||
// Discard a double click with the middle button
|
||||
if (e->button() != Qt::MidButton) {
|
||||
if (index == -1) {
|
||||
new_->activate(QAction::Trigger);
|
||||
@@ -172,10 +185,10 @@ void PlaylistTabBar::RenameInline() {
|
||||
|
||||
void PlaylistTabBar::HideEditor() {
|
||||
|
||||
//editingFinished() will be called twice due to Qt bug #40, so we reuse the same instance, don't delete it
|
||||
// editingFinished() will be called twice due to Qt bug #40, so we reuse the same instance, don't delete it
|
||||
rename_editor_->setVisible(false);
|
||||
|
||||
// hack to give back focus to playlist view
|
||||
// Hack to give back focus to playlist view
|
||||
manager_->SetCurrentPlaylist(manager_->current()->id());
|
||||
|
||||
}
|
||||
@@ -232,10 +245,8 @@ void PlaylistTabBar::Close() {
|
||||
}
|
||||
}
|
||||
|
||||
// Close the playlist. If the playlist is not a favorite playlist, it will be
|
||||
// deleted, as it will not be visible after being closed. Otherwise, the tab
|
||||
// is closed but the playlist still exists and can be resurrected from the
|
||||
// "Playlists" tab.
|
||||
// Close the playlist. If the playlist is not a favorite playlist, it will be deleted, as it will not be visible after being closed.
|
||||
// Otherwise, the tab is closed but the playlist still exists and can be resurrected from the "Playlists" tab.
|
||||
emit Close(playlist_id);
|
||||
|
||||
// Select the nearest tab.
|
||||
@@ -305,8 +316,8 @@ void PlaylistTabBar::CurrentIndexChanged(int index) {
|
||||
if (!suppress_current_changed_) emit CurrentIdChanged(tabData(index).toInt());
|
||||
}
|
||||
|
||||
void PlaylistTabBar::InsertTab(int id, int index, const QString &text,
|
||||
bool favorite) {
|
||||
void PlaylistTabBar::InsertTab(int id, int index, const QString &text, bool favorite) {
|
||||
|
||||
suppress_current_changed_ = true;
|
||||
insertTab(index, text);
|
||||
setTabData(index, id);
|
||||
@@ -319,8 +330,7 @@ void PlaylistTabBar::InsertTab(int id, int index, const QString &text,
|
||||
setTabButton(index, QTabBar::LeftSide, widget);
|
||||
suppress_current_changed_ = false;
|
||||
|
||||
// If we are still starting up, we don't need to do this, as the
|
||||
// tab ordering after startup will be the same as was already in the db.
|
||||
// If we are still starting up, we don't need to do this, as the tab ordering after startup will be the same as was already in the db.
|
||||
if (initialized_) {
|
||||
if (currentIndex() == index) emit CurrentIdChanged(id);
|
||||
|
||||
@@ -330,11 +340,13 @@ void PlaylistTabBar::InsertTab(int id, int index, const QString &text,
|
||||
}
|
||||
|
||||
void PlaylistTabBar::TabMoved() {
|
||||
|
||||
QList<int> ids;
|
||||
for (int i = 0; i < count(); ++i) {
|
||||
ids << tabData(i).toInt();
|
||||
}
|
||||
emit PlaylistOrderChanged(ids);
|
||||
|
||||
}
|
||||
|
||||
void PlaylistTabBar::dragEnterEvent(QDragEnterEvent *e) {
|
||||
@@ -364,6 +376,7 @@ void PlaylistTabBar::dragLeaveEvent(QDragLeaveEvent*) {
|
||||
}
|
||||
|
||||
void PlaylistTabBar::timerEvent(QTimerEvent *e) {
|
||||
|
||||
QTabBar::timerEvent(e);
|
||||
|
||||
if (e->timerId() == drag_hover_timer_.timerId()) {
|
||||
|
||||
@@ -23,15 +23,31 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QBasicTimer>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
#include <QTabBar>
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
#include <QtEvents>
|
||||
|
||||
class QEvent;
|
||||
class QContextMenuEvent;
|
||||
class QDragEnterEvent;
|
||||
class QDragLeaveEvent;
|
||||
class QDragMoveEvent;
|
||||
class QDropEvent;
|
||||
class QMouseEvent;
|
||||
class QTimerEvent;
|
||||
|
||||
class PlaylistManager;
|
||||
class RenameTabLineEdit;
|
||||
|
||||
class QMenu;
|
||||
|
||||
class PlaylistTabBar : public QTabBar {
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -20,8 +20,16 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistundocommands.h"
|
||||
#include <memory>
|
||||
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
#include <QUndoStack>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "playlist.h"
|
||||
#include "playlistitem.h"
|
||||
#include "playlistundocommands.h"
|
||||
|
||||
namespace PlaylistUndoCommands {
|
||||
|
||||
@@ -66,8 +74,7 @@ RemoveItems::RemoveItems(Playlist *playlist, int pos, int count) : Base(playlist
|
||||
|
||||
void RemoveItems::redo() {
|
||||
for (int i = 0; i < ranges_.count(); ++i)
|
||||
ranges_[i].items_ =
|
||||
playlist_->RemoveItemsWithoutUndo(ranges_[i].pos_, ranges_[i].count_);
|
||||
ranges_[i].items_ = playlist_->RemoveItemsWithoutUndo(ranges_[i].pos_, ranges_[i].count_);
|
||||
}
|
||||
|
||||
void RemoveItems::undo() {
|
||||
@@ -111,9 +118,9 @@ void ReOrderItems::undo() { playlist_->ReOrderWithoutUndo(old_items_); }
|
||||
void ReOrderItems::redo() { playlist_->ReOrderWithoutUndo(new_items_); }
|
||||
|
||||
SortItems::SortItems(Playlist* playlist, int column, Qt::SortOrder order, const PlaylistItemList &new_items)
|
||||
: ReOrderItems(playlist, new_items),
|
||||
column_(column),
|
||||
order_(order)
|
||||
: ReOrderItems(playlist, new_items)
|
||||
//column_(column),
|
||||
//order_(order)
|
||||
{
|
||||
setText(tr("sort songs"));
|
||||
}
|
||||
|
||||
@@ -23,14 +23,18 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QList>
|
||||
#include <QUndoStack>
|
||||
|
||||
#include "playlistitem.h"
|
||||
|
||||
class Playlist;
|
||||
|
||||
namespace PlaylistUndoCommands {
|
||||
|
||||
enum Types {
|
||||
Type_RemoveItems = 0,
|
||||
};
|
||||
@@ -52,9 +56,8 @@ namespace PlaylistUndoCommands {
|
||||
void undo();
|
||||
void redo();
|
||||
// When load is async, items have already been pushed, so we need to update them.
|
||||
// This function try to find the equivalent item, and replace it with the
|
||||
// new (completely loaded) one.
|
||||
// return true if the was found (and updated), false otherwise
|
||||
// This function try to find the equivalent item, and replace it with the new (completely loaded) one.
|
||||
// Return true if the was found (and updated), false otherwise
|
||||
bool UpdateItem(const PlaylistItemPtr &updated_item);
|
||||
|
||||
private:
|
||||
@@ -110,11 +113,11 @@ namespace PlaylistUndoCommands {
|
||||
|
||||
class SortItems : public ReOrderItems {
|
||||
public:
|
||||
SortItems(Playlist *playlist, int column, Qt::SortOrder order, const PlaylistItemList &new_items);
|
||||
SortItems(Playlist *playlist, int column, Qt::SortOrder order, const PlaylistItemList &new_items);
|
||||
|
||||
private:
|
||||
int column_;
|
||||
Qt::SortOrder order_;
|
||||
//int column_;
|
||||
//Qt::SortOrder order_;
|
||||
};
|
||||
|
||||
class ShuffleItems : public ReOrderItems {
|
||||
|
||||
@@ -22,33 +22,60 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <QCommonStyle>
|
||||
#include <QClipboard>
|
||||
#include <QPainter>
|
||||
#include <QHeaderView>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
#include <QTimer>
|
||||
#include <QKeyEvent>
|
||||
#include <QApplication>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QScrollBar>
|
||||
#include <QTimeLine>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QList>
|
||||
#include <QAbstractItemView>
|
||||
#include <QByteArray>
|
||||
#include <QClipboard>
|
||||
#include <QCommonStyle>
|
||||
#include <QFontMetrics>
|
||||
#include <QHeaderView>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QKeySequence>
|
||||
#include <QMimeData>
|
||||
#include <QSize>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTimeLine>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringBuilder>
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QPainter>
|
||||
#include <QPalette>
|
||||
#include <QColor>
|
||||
#include <QBrush>
|
||||
#include <QPen>
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
#include <QRegion>
|
||||
#include <QtAlgorithms>
|
||||
#include <QStyleOptionHeader>
|
||||
#include <QStyleOptionViewItem>
|
||||
#include <QProxyStyle>
|
||||
#include <QTreeView>
|
||||
#include <QLinearGradient>
|
||||
#include <QScrollBar>
|
||||
#include <QtEvents>
|
||||
#include <QSettings>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/player.h"
|
||||
#include "core/qt_blurimage.h"
|
||||
#include "core/song.h"
|
||||
#include "playlist.h"
|
||||
#include "playlistview.h"
|
||||
#include "playlistdelegates.h"
|
||||
#include "playlistheader.h"
|
||||
#include "core/application.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/player.h"
|
||||
#include "core/iconloader.h"
|
||||
#include "core/qt_blurimage.h"
|
||||
#include "playlistview.h"
|
||||
#include "covermanager/currentartloader.h"
|
||||
#include "settings/appearancesettingspage.h"
|
||||
#include "settings/playbacksettingspage.h"
|
||||
#include "settings/playlistsettingspage.h"
|
||||
#include "settings/appearancesettingspage.h"
|
||||
|
||||
const int PlaylistView::kStateVersion = 6;
|
||||
const int PlaylistView::kGlowIntensitySteps = 24;
|
||||
@@ -72,7 +99,7 @@ void PlaylistProxyStyle::drawControl(ControlElement element, const QStyleOption
|
||||
const QString &text = header_option->text;
|
||||
const QFontMetrics &font_metrics = header_option->fontMetrics;
|
||||
|
||||
// spaces added to make transition less abrupt
|
||||
// Spaces added to make transition less abrupt
|
||||
if (rect.width() < font_metrics.width(text + " ")) {
|
||||
const Playlist::Column column = static_cast<Playlist::Column>(header_option->section);
|
||||
QStyleOptionHeader new_option(*header_option);
|
||||
@@ -132,8 +159,6 @@ PlaylistView::PlaylistView(QWidget *parent)
|
||||
drag_over_(false)
|
||||
{
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
setHeader(header_);
|
||||
header_->setSectionsMovable(true);
|
||||
setStyle(style_);
|
||||
@@ -248,8 +273,7 @@ void PlaylistView::setModel(QAbstractItemModel *m) {
|
||||
disconnect(model(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(InvalidateCachedCurrentPixmap()));
|
||||
//disconnect(model(), SIGNAL(layoutAboutToBeChanged()), this, SLOT(RatingHoverOut()));
|
||||
// When changing the model, always invalidate the current pixmap.
|
||||
// If a remote client uses "stop after", without invaliding the stop
|
||||
// mark would not appear.
|
||||
// If a remote client uses "stop after", without invaliding the stop mark would not appear.
|
||||
InvalidateCachedCurrentPixmap();
|
||||
}
|
||||
|
||||
@@ -323,8 +347,6 @@ void PlaylistView::SaveGeometry() {
|
||||
|
||||
void PlaylistView::ReloadBarPixmaps() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
currenttrack_bar_left_ = LoadBarPixmap(":/pictures/currenttrack_bar_left.png");
|
||||
currenttrack_bar_mid_ = LoadBarPixmap(":/pictures/currenttrack_bar_mid.png");
|
||||
currenttrack_bar_right_ = LoadBarPixmap(":/pictures/currenttrack_bar_right.png");
|
||||
@@ -413,13 +435,11 @@ void PlaylistView::drawRow(QPainter *painter, const QStyleOptionViewItem &option
|
||||
opt.palette.setColor(QPalette::AlternateBase, Qt::transparent);
|
||||
opt.decorationSize = QSize(20, 20);
|
||||
|
||||
// Draw the actual row data on top. We cache this, because it's fairly
|
||||
// expensive (1-2ms), and we do it many times per second.
|
||||
// Draw the actual row data on top. We cache this, because it's fairly expensive (1-2ms), and we do it many times per second.
|
||||
const bool cache_dirty = cached_current_row_rect_ != opt.rect || cached_current_row_row_ != index.row() || cached_current_row_.isNull();
|
||||
|
||||
// We can't update the cache if we're not drawing the entire region,
|
||||
// QTreeView clips its drawing to only the columns in the region, so it
|
||||
// wouldn't update the whole pixmap properly.
|
||||
// QTreeView clips its drawing to only the columns in the region, so it wouldn't update the whole pixmap properly.
|
||||
const bool whole_region = current_paint_region_.boundingRect().width() == viewport()->width();
|
||||
|
||||
if (!cache_dirty) {
|
||||
@@ -560,8 +580,7 @@ void PlaylistView::RemoveSelected(bool deleting_from_disk) {
|
||||
// Store the last selected row, which is the last in the list
|
||||
int last_row = selection.last().top();
|
||||
|
||||
// Sort the selection so we remove the items at the *bottom* first, ensuring
|
||||
// we don't have to mess around with changing row numbers
|
||||
// Sort the selection so we remove the items at the *bottom* first, ensuring we don't have to mess around with changing row numbers
|
||||
qSort(selection.begin(), selection.end(), CompareSelectionRanges);
|
||||
|
||||
for (const QItemSelectionRange &range : selection) {
|
||||
@@ -580,8 +599,7 @@ void PlaylistView::RemoveSelected(bool deleting_from_disk) {
|
||||
|
||||
// Select the new current item, we want always the item after the last selected
|
||||
if (new_index.isValid()) {
|
||||
// Workaround to update keyboard selected row, if it's not the first row
|
||||
// (this also triggers selection)
|
||||
// Workaround to update keyboard selected row, if it's not the first row (this also triggers selection)
|
||||
if (new_row != 0)
|
||||
keyPressEvent(new QKeyEvent(QEvent::KeyPress, Qt::Key_Down, Qt::NoModifier));
|
||||
// Update visual selection with the entire row
|
||||
@@ -677,8 +695,6 @@ void PlaylistView::leaveEvent(QEvent *e) {
|
||||
}
|
||||
|
||||
void PlaylistView::mousePressEvent(QMouseEvent *event) {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
if (editTriggers() & QAbstractItemView::NoEditTriggers) {
|
||||
QTreeView::mousePressEvent(event);
|
||||
@@ -710,8 +726,7 @@ void PlaylistView::scrollContentsBy(int dx, int dy) {
|
||||
}
|
||||
|
||||
void PlaylistView::InhibitAutoscrollTimeout() {
|
||||
// For 30 seconds after the user clicks on or scrolls the playlist we promise
|
||||
// not to automatically scroll the view to keep up with a track change.
|
||||
// For 30 seconds after the user clicks on or scrolls the playlist we promise not to automatically scroll the view to keep up with a track change.
|
||||
inhibit_autoscroll_ = false;
|
||||
}
|
||||
|
||||
@@ -766,11 +781,9 @@ void PlaylistView::paintEvent(QPaintEvent *event) {
|
||||
|
||||
// Reimplemented to draw the background image.
|
||||
// Reimplemented also to draw the drop indicator
|
||||
// When the user is dragging some stuff over the playlist paintEvent gets
|
||||
// called for the entire viewport every time the user moves the mouse.
|
||||
// The drawTree is kinda expensive, so we cache the result and draw from the
|
||||
// cache while the user is dragging. The cached pixmap gets invalidated in
|
||||
// dragLeaveEvent, dropEvent and scrollContentsBy.
|
||||
// When the user is dragging some stuff over the playlist paintEvent gets called for the entire viewport every time the user moves the mouse.
|
||||
// The drawTree is kinda expensive, so we cache the result and draw from the cache while the user is dragging.
|
||||
// The cached pixmap gets invalidated in dragLeaveEvent, dropEvent and scrollContentsBy.
|
||||
|
||||
// Draw background
|
||||
if (background_image_type_ == Custom || background_image_type_ == Album) {
|
||||
@@ -908,8 +921,6 @@ void PlaylistView::PlaylistDestroyed() {
|
||||
}
|
||||
|
||||
void PlaylistView::ReloadSettings() {
|
||||
|
||||
//qLog(Debug) << __PRETTY_FUNCTION__;
|
||||
|
||||
QSettings s;
|
||||
|
||||
@@ -979,10 +990,9 @@ void PlaylistView::ReloadSettings() {
|
||||
int opacity_level = s.value("opacity_level", kDefaultOpacityLevel).toInt();
|
||||
s.endGroup();
|
||||
// Check if background properties have changed.
|
||||
// We change properties only if they have actually changed, to avoid to call
|
||||
// set_background_image when it is not needed, as this will cause the fading
|
||||
// animation to start again. This also avoid to do useless
|
||||
// "force_background_redraw".
|
||||
// We change properties only if they have actually changed, to avoid to call set_background_image when it is not needed,
|
||||
// as this will cause the fading animation to start again.
|
||||
// This also avoid to do useless "force_background_redraw".
|
||||
|
||||
if (!background_initialized_ || background_image_filename != background_image_filename_ || background_type != background_image_type_ || blur_radius_ != blur_radius || opacity_level_ != opacity_level) {
|
||||
background_initialized_ = true;
|
||||
@@ -998,10 +1008,8 @@ void PlaylistView::ReloadSettings() {
|
||||
set_background_image(current_song_cover_art_);
|
||||
}
|
||||
else {
|
||||
// User changed background image type to something that will not be
|
||||
// painted through paintEvent: reset all background images.
|
||||
// This avoid to use old (deprecated) images for fading when selecting
|
||||
// Album or Custom background image type later.
|
||||
// User changed background image type to something that will not be painted through paintEvent: reset all background images.
|
||||
// This avoid to use old (deprecated) images for fading when selecting Album or Custom background image type later.
|
||||
//set_background_image(QImage(":/pictures/playlistbg.png"));
|
||||
set_background_image(QImage());
|
||||
cached_scaled_background_image_ = QPixmap();
|
||||
@@ -1064,8 +1072,7 @@ void PlaylistView::rowsInserted(const QModelIndex &parent, int start, int end) {
|
||||
QTreeView::rowsInserted(parent, start, end);
|
||||
|
||||
if (at_end) {
|
||||
// If the rows were inserted at the end of the playlist then let's scroll
|
||||
// the view so the user can see.
|
||||
// If the rows were inserted at the end of the playlist then let's scroll the view so the user can see.
|
||||
scrollTo(model()->index(start, 0, parent), QAbstractItemView::PositionAtTop);
|
||||
}
|
||||
|
||||
@@ -1211,10 +1218,8 @@ void PlaylistView::focusInEvent(QFocusEvent *event) {
|
||||
|
||||
if (event->reason() == Qt::TabFocusReason ||
|
||||
event->reason() == Qt::BacktabFocusReason) {
|
||||
// If there's a current item but no selection it probably means the list was
|
||||
// filtered, and the selected item does not match the filter. If there's
|
||||
// only 1 item in the view it is now impossible to select that item without
|
||||
// using the mouse.
|
||||
// If there's a current item but no selection it probably means the list was filtered, and the selected item does not match the filter.
|
||||
// If there's only 1 item in the view it is now impossible to select that item without using the mouse.
|
||||
const QModelIndex ¤t = selectionModel()->currentIndex();
|
||||
if (current.isValid() && selectionModel()->selectedIndexes().isEmpty()) {
|
||||
QItemSelection new_selection(current.sibling(current.row(), 0), current.sibling(current.row(), current.model()->columnCount(current.parent()) - 1));
|
||||
|
||||
@@ -24,25 +24,56 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QBasicTimer>
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QImage>
|
||||
#include <QPixmap>
|
||||
#include <QRect>
|
||||
#include <QRegion>
|
||||
#include <QStyle>
|
||||
#include <QStyleOption>
|
||||
#include <QProxyStyle>
|
||||
#include <QTreeView>
|
||||
#include <QPoint>
|
||||
#include <QTimer>
|
||||
#include <QBasicTimer>
|
||||
#include <QTimeLine>
|
||||
#include <QCommonStyle>
|
||||
#include <QPainter>
|
||||
#include <QAbstractItemDelegate>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QStyleOptionViewItem>
|
||||
#include <QtEvents>
|
||||
|
||||
#include "playlist.h"
|
||||
|
||||
class QCommonStyle;
|
||||
class QEvent;
|
||||
class QShowEvent;
|
||||
class QContextMenuEvent;
|
||||
class QDragEnterEvent;
|
||||
class QDragLeaveEvent;
|
||||
class QDragMoveEvent;
|
||||
class QDropEvent;
|
||||
class QFocusEvent;
|
||||
class QHideEvent;
|
||||
class QKeyEvent;
|
||||
class QMouseEvent;
|
||||
class QPaintEvent;
|
||||
class QTimerEvent;
|
||||
|
||||
class Application;
|
||||
class Song;
|
||||
class CollectionBackend;
|
||||
class PlaylistHeader;
|
||||
class QTimeLine;
|
||||
|
||||
|
||||
// This proxy style works around a bug/feature introduced in Qt 4.7's QGtkStyle
|
||||
// that uses Gtk to paint row backgrounds, ignoring any custom brush or palette
|
||||
// the caller set in the QStyleOption. That breaks our currently playing track
|
||||
// animation, which relies on the background painted by Qt to be transparent.
|
||||
// that uses Gtk to paint row backgrounds, ignoring any custom brush or palette the caller set in the QStyleOption.
|
||||
// That breaks our currently playing track animation, which relies on the background painted by Qt to be transparent.
|
||||
// This proxy style uses QCommonStyle to paint the affected elements.
|
||||
// This class is used by the global search view as well.
|
||||
class PlaylistProxyStyle : public QProxyStyle {
|
||||
@@ -164,8 +195,7 @@ class PlaylistView : public QTreeView {
|
||||
background_image_type_ = bg;
|
||||
emit BackgroundPropertyChanged();
|
||||
}
|
||||
// Save image as the background_image_ after applying some modifications
|
||||
// (opacity, ...).
|
||||
// Save image as the background_image_ after applying some modifications (opacity, ...).
|
||||
// Should be used instead of modifying background_image_ directly
|
||||
void set_background_image(const QImage &image);
|
||||
|
||||
@@ -190,9 +220,9 @@ class PlaylistView : public QTreeView {
|
||||
|
||||
bool background_initialized_;
|
||||
BackgroundImageType background_image_type_;
|
||||
// Stores the background image to be displayed. As we want this image to be
|
||||
// particular (in terms of format, opacity), you should probably use
|
||||
// set_background_image_type instead of modifying background_image_ directly
|
||||
// Stores the background image to be displayed.
|
||||
// As we want this image to be particular (in terms of format, opacity),
|
||||
// you should probably use set_background_image_type instead of modifying background_image_ directly
|
||||
QImage background_image_;
|
||||
int blur_radius_;
|
||||
int opacity_level_;
|
||||
|
||||
@@ -20,11 +20,24 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "queue.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QIODevice>
|
||||
#include <QDataStream>
|
||||
#include <QBuffer>
|
||||
#include <QFlags>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QStringBuilder>
|
||||
#include <QMimeData>
|
||||
#include <QtDebug>
|
||||
#include <QtAlgorithms>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractProxyModel>
|
||||
#include <QPersistentModelIndex>
|
||||
|
||||
#include "playlist.h"
|
||||
#include "queue.h"
|
||||
|
||||
const char *Queue::kRowsMimetype = "application/x-strawberry-queue-rows";
|
||||
|
||||
@@ -63,15 +76,15 @@ QModelIndex Queue::mapToSource(const QModelIndex &proxy_index) const {
|
||||
void Queue::setSourceModel(QAbstractItemModel *source_model) {
|
||||
|
||||
if (sourceModel()) {
|
||||
disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(SourceDataChanged(QModelIndex,QModelIndex)));
|
||||
disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(SourceLayoutChanged()));
|
||||
disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(SourceDataChanged(QModelIndex, QModelIndex)));
|
||||
disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(SourceLayoutChanged()));
|
||||
disconnect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(SourceLayoutChanged()));
|
||||
}
|
||||
|
||||
QAbstractProxyModel::setSourceModel(source_model);
|
||||
|
||||
connect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(SourceDataChanged(QModelIndex,QModelIndex)));
|
||||
connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(SourceLayoutChanged()));
|
||||
connect(sourceModel(), SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(SourceDataChanged(QModelIndex, QModelIndex)));
|
||||
connect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(SourceLayoutChanged()));
|
||||
connect(sourceModel(), SIGNAL(layoutChanged()), this, SLOT(SourceLayoutChanged()));
|
||||
|
||||
}
|
||||
@@ -94,7 +107,6 @@ void Queue::SourceLayoutChanged() {
|
||||
beginRemoveRows(QModelIndex(), i, i);
|
||||
source_indexes_.removeAt(i);
|
||||
endRemoveRows();
|
||||
|
||||
--i;
|
||||
}
|
||||
}
|
||||
@@ -181,8 +193,7 @@ void Queue::Move(const QList<int> &proxy_rows, int pos) {
|
||||
layoutAboutToBeChanged();
|
||||
QList<QPersistentModelIndex> moved_items;
|
||||
|
||||
// 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;
|
||||
for (int row : proxy_rows) {
|
||||
moved_items << source_indexes_.takeAt(row - offset);
|
||||
@@ -343,15 +354,15 @@ QVariant Queue::headerData(int section, Qt::Orientation orientation, int role) c
|
||||
|
||||
void Queue::Remove(QList<int> &proxy_rows) {
|
||||
|
||||
// order the rows
|
||||
// Order the rows
|
||||
qStableSort(proxy_rows);
|
||||
|
||||
// reflects immediately changes in the playlist
|
||||
// Reflects immediately changes in the playlist
|
||||
layoutAboutToBeChanged();
|
||||
|
||||
int removed_rows = 0;
|
||||
for (int row : proxy_rows) {
|
||||
// after the first row, the row number needs to be updated
|
||||
// After the first row, the row number needs to be updated
|
||||
const int real_row = row - removed_rows;
|
||||
beginRemoveRows(QModelIndex(), real_row, real_row);
|
||||
source_indexes_.removeAt(real_row);
|
||||
|
||||
@@ -23,9 +23,16 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlist.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QAbstractProxyModel>
|
||||
#include <QList>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMimeData>
|
||||
|
||||
class Queue : public QAbstractProxyModel {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -18,18 +18,26 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QKeySequence>
|
||||
#include <QList>
|
||||
#include <QPushButton>
|
||||
#include <QShortcut>
|
||||
#include <QTreeView>
|
||||
#include <QtAlgorithms>
|
||||
|
||||
#include "core/iconloader.h"
|
||||
#include "playlist.h"
|
||||
#include "playlistdelegates.h"
|
||||
#include "playlistmanager.h"
|
||||
#include "queue.h"
|
||||
#include "queuemanager.h"
|
||||
#include "ui_queuemanager.h"
|
||||
#include "core/iconloader.h"
|
||||
|
||||
#include <QKeySequence>
|
||||
#include <QShortcut>
|
||||
|
||||
QueueManager::QueueManager(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
@@ -75,8 +83,8 @@ void QueueManager::SetPlaylistManager(PlaylistManager *manager) {
|
||||
void QueueManager::CurrentPlaylistChanged(Playlist *playlist) {
|
||||
|
||||
if (current_playlist_) {
|
||||
disconnect(current_playlist_->queue(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(UpdateButtonState()));
|
||||
disconnect(current_playlist_->queue(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(UpdateButtonState()));
|
||||
disconnect(current_playlist_->queue(), SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(UpdateButtonState()));
|
||||
disconnect(current_playlist_->queue(), SIGNAL(rowsRemoved(QModelIndex, int, int)), this, SLOT(UpdateButtonState()));
|
||||
disconnect(current_playlist_->queue(), SIGNAL(layoutChanged()), this, SLOT(UpdateButtonState()));
|
||||
disconnect(current_playlist_, SIGNAL(destroyed()), this, SLOT(PlaylistDestroyed()));
|
||||
}
|
||||
|
||||
@@ -23,14 +23,15 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
#include <QString>
|
||||
|
||||
class Playlist;
|
||||
class PlaylistManager;
|
||||
class Ui_QueueManager;
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
class QueueManager : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -58,4 +59,3 @@ private:
|
||||
};
|
||||
|
||||
#endif // QUEUEMANAGER_H
|
||||
|
||||
|
||||
@@ -21,12 +21,16 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <QtConcurrentRun>
|
||||
#include <QtAlgorithms>
|
||||
#include <QList>
|
||||
#include <QUrl>
|
||||
|
||||
#include "playlist.h"
|
||||
#include "songloaderinserter.h"
|
||||
#include "core/closure.h"
|
||||
#include "core/logging.h"
|
||||
#include "core/songloader.h"
|
||||
#include "core/taskmanager.h"
|
||||
#include "playlist.h"
|
||||
#include "songloaderinserter.h"
|
||||
|
||||
SongLoaderInserter::SongLoaderInserter(TaskManager *task_manager, CollectionBackendInterface *collection, const Player *player)
|
||||
: task_manager_(task_manager),
|
||||
@@ -50,7 +54,7 @@ void SongLoaderInserter::Load(Playlist *destination, int row, bool play_now, boo
|
||||
connect(this, SIGNAL(PreloadFinished()), SLOT(InsertSongs()));
|
||||
connect(this, SIGNAL(EffectiveLoadFinished(const SongList&)), destination, SLOT(UpdateItems(const SongList&)));
|
||||
|
||||
for (const QUrl& url : urls) {
|
||||
for (const QUrl &url : urls) {
|
||||
SongLoader *loader = new SongLoader(collection_, player_, this);
|
||||
|
||||
SongLoader::Result ret = loader->Load(url);
|
||||
@@ -122,8 +126,7 @@ void SongLoaderInserter::AudioCDTagsLoaded(bool success) {
|
||||
}
|
||||
|
||||
void SongLoaderInserter::InsertSongs() {
|
||||
// Insert songs (that haven't been completely loaded) to allow user to see
|
||||
// and play them while not loaded completely
|
||||
// Insert songs (that haven't been completely loaded) to allow user to see and play them while not loaded completely
|
||||
if (destination_) {
|
||||
destination_->InsertSongsOrCollectionItems(songs_, row_, play_now_, enqueue_);
|
||||
}
|
||||
@@ -140,9 +143,8 @@ void SongLoaderInserter::AsyncLoad() {
|
||||
loader->LoadFilenamesBlocking();
|
||||
task_manager_->SetTaskProgress(async_load_id, ++async_progress);
|
||||
if (i == 0) {
|
||||
// Load everything from the first song. It'll start playing as soon as
|
||||
// we emit PreloadFinished, so it needs to have the duration set to show
|
||||
// properly in the UI.
|
||||
// Load everything from the first song.
|
||||
// It'll start playing as soon as we emit PreloadFinished, so it needs to have the duration set to show properly in the UI.
|
||||
loader->LoadMetadataBlocking();
|
||||
}
|
||||
songs_ << loader->songs();
|
||||
|
||||
@@ -23,19 +23,20 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QList>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "core/song.h"
|
||||
|
||||
class CollectionBackendInterface;
|
||||
class Player;
|
||||
class Playlist;
|
||||
class SongLoader;
|
||||
class TaskManager;
|
||||
|
||||
class QModelIndex;
|
||||
class CollectionBackendInterface;
|
||||
class Playlist;
|
||||
|
||||
class SongLoaderInserter : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QMimeData>
|
||||
|
||||
#include "core/mimedata.h"
|
||||
|
||||
@@ -20,15 +20,14 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistbackend.h"
|
||||
#include "songplaylistitem.h"
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QUrl>
|
||||
|
||||
#include "core/tagreaderclient.h"
|
||||
|
||||
#include "collection/sqlrow.h"
|
||||
|
||||
#include <QtDebug>
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
#include "playlistitem.h"
|
||||
#include "songplaylistitem.h"
|
||||
|
||||
SongPlaylistItem::SongPlaylistItem(const QString &type) : PlaylistItem(type) {}
|
||||
|
||||
|
||||
@@ -23,17 +23,21 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "playlistitem.h"
|
||||
#include <stdbool.h>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
#include "core/song.h"
|
||||
#include "collection/sqlrow.h"
|
||||
#include "playlistitem.h"
|
||||
|
||||
class SongPlaylistItem : public PlaylistItem {
|
||||
public:
|
||||
SongPlaylistItem(const QString& type);
|
||||
SongPlaylistItem(const Song& song);
|
||||
SongPlaylistItem(const QString &type);
|
||||
SongPlaylistItem(const Song &song);
|
||||
|
||||
// Restores a stream- or file-related playlist item using query row.
|
||||
// If it's a file related playlist item, this will restore it's CUE
|
||||
// attributes (if any) but won't parse the CUE!
|
||||
// If it's a file related playlist item, this will restore it's CUE attributes (if any) but won't parse the CUE!
|
||||
bool InitFromQuery(const SqlRow& query);
|
||||
void Reload();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user