ocarina/core/queue.cpp

268 lines
5.1 KiB
C++
Raw Normal View History

/**
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/queue.h>
#include <core/random.h>
#include <core/string.h>
#include <algorithm>
#include <sstream>
static class DefaultNotifier : public QNotifier {
public:
DefaultNotifier() {};
void on_track_added(unsigned int pos) {};
void on_track_removed(unsigned int pos) {};
void on_track_updated(unsigned int pos) {};
} def_notify;
Queue :: Queue(unsigned int flags)
: _cur(-1), _flags(flags), _length(0), _notify(&def_notify)
{}
Queue :: Queue()
: _cur(-1), _flags(0), _length(0), _notify(&def_notify)
{}
Queue :: ~Queue()
{}
void Queue :: write(File &file)
{
file << _flags << " " << _tracks.size();
for (unsigned int i = 0; i < _tracks.size(); i++)
file << " " << _tracks[i]->index();
}
void Queue :: read(File &file)
{
unsigned int n, id;
file >> _flags >> n;
_tracks.resize(n);
for (unsigned int i = 0; i < n; i++) {
file >> id;
_tracks[i] = tags :: get_track(id);
_length += _tracks[i]->length();
}
}
void Queue :: set_flag(queue_flags flag)
{
_flags |= flag;
}
void Queue :: unset_flag(queue_flags flag)
{
_flags &= ~flag;
}
bool Queue :: has_flag(queue_flags flag)
{
return (_flags & flag) == (unsigned int)flag;
}
void Queue :: set_notifier(QNotifier *notify)
{
_notify = notify;
}
/*
* Returns:
* 0: lhs == rhs
* < 0: lhs < rhs, or rhs is empty
* > 0: lhs > rhs, or lhs is empty
*/
static inline int track_compare(Track *lhs, Track *rhs, sort_t field)
{
switch (field) {
case SORT_ARTIST:
return lhs->artist()->compare(rhs->artist());
case SORT_COUNT:
return lhs->count() - rhs->count();
case SORT_GENRE:
return lhs->genre()->compare(rhs->genre());
case SORT_LENGTH:
return lhs->length() - rhs->length();
case SORT_PLAYED:
return rhs->compare_date(rhs);
case SORT_TITLE:
return lhs->compare(rhs);
case SORT_TRACK:
return lhs->track() - rhs->track();
case SORT_YEAR:
if (lhs->album()->year() - rhs->album()->year() != 0)
return lhs->album()->year() - rhs->album()->year();
case SORT_ALBUM:
return lhs->album()->compare(rhs->album());
}
return 0;
}
static bool track_less_than(Track *lhs, Track *rhs,
std::vector<struct sort_info> &order)
{
int res;
for (unsigned int i = 0; i < order.size(); i++) {
if (order[i].ascending == true)
res = track_compare(lhs, rhs, order[i].field);
else
res = track_compare(rhs, lhs, order[i].field);
if (res == 0)
continue;
break;
}
return res < 0;
}
unsigned int Queue :: find_sorted_id(Track *rhs)
{
Track *lhs;
unsigned int begin = 0, end = (_tracks.size() - 1), mid;
if (_tracks.size() == 0)
return 0;
while (end > begin) {
mid = begin + ((end - begin) / 2);
lhs = _tracks[mid];
if (track_less_than(lhs, rhs, _sort_order))
begin = mid + 1;
else {
if (mid == begin)
return begin;
else
end = mid - 1;
}
}
lhs = _tracks[begin];
if (track_less_than(lhs, rhs, _sort_order))
return begin + 1;
return begin;
}
unsigned int Queue :: _add_at(Track *track, unsigned int pos)
{
_tracks.insert(_tracks.begin() + pos, track);
_length += track->length();
_notify->on_track_added(pos);
return pos;
}
unsigned int Queue :: add(Track *track)
{
unsigned int id = _tracks.size();
if (_sort_order.size() > 0)
id = find_sorted_id(track);
return _add_at(track, id);
}
void Queue :: del(unsigned int index)
{
_length -= _tracks[index]->length();
_tracks.erase(_tracks.begin() + index);
_notify->on_track_removed(index);
}
void Queue :: del(Track *track)
{
for (unsigned int i = 0; i < _tracks.size(); i++) {
while ((i < _tracks.size()) && (_tracks[i] == track))
del(i);
}
}
void Queue :: updated(Track *track)
{
for (unsigned int i = 0; i < _tracks.size(); i++) {
if (_tracks[i] == track)
_notify->on_track_updated(i);
}
}
Track *Queue :: next()
{
Track *res;
if (_tracks.size() == 0)
return NULL;
else if (_tracks.size() == 1)
_cur = 0;
else if (_flags & Q_RANDOM)
_cur += random(1, _tracks.size() / 2);
else
_cur++;
_cur %= _tracks.size();
res = _tracks[_cur];
if (!(_flags & Q_REPEAT)) {
del(_cur);
_cur--;
}
return res;
}
unsigned int Queue :: size()
{
return _tracks.size();
}
unsigned int Queue :: length()
{
return _length;
}
class SortTracks {
public:
std::vector<struct sort_info> fields;
SortTracks(std::vector<sort_info> f) : fields(f) {}
bool operator()(Track *lhs, Track *rhs)
{
return track_less_than(lhs, rhs, fields);
}
};
void Queue :: sort(sort_t field, bool reset)
{
bool found = false;
struct sort_info info = { field, true };
if (_flags & Q_NO_SORT)
return;
if (reset)
_sort_order.clear();
for (unsigned int i = 0; i < _sort_order.size(); i++) {
if (_sort_order[i].field == info.field) {
_sort_order[i].ascending = !_sort_order[i].ascending;
found = true;
break;
}
}
if (!found)
_sort_order.push_back(info);
std::stable_sort(_tracks.begin(), _tracks.end(), SortTracks(_sort_order));
for (unsigned int i = 0; i < _tracks.size(); i++)
_notify->on_track_updated(i);
}
Track *Queue :: operator[](unsigned int index)
{
return _tracks[index];
}
void Queue :: track_selected(unsigned int index)
{
_cur = index;
if (has_flag(Q_REPEAT) == false) {
del(_cur);
_cur--;
}
}