2014-10-17 09:42:45 -04:00
|
|
|
/**
|
|
|
|
* @file
|
2013-12-31 15:44:44 -05:00
|
|
|
* Copyright 2013 (c) Anna Schumaker.
|
|
|
|
*/
|
2014-06-05 10:19:22 -04:00
|
|
|
#include <core/callback.h>
|
|
|
|
#include <core/queue.h>
|
|
|
|
#include <core/random.h>
|
2014-01-22 21:17:51 -05:00
|
|
|
|
2014-01-26 13:44:25 -05:00
|
|
|
#include <algorithm>
|
2014-01-22 21:17:51 -05:00
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
#define O_MINUTES (60)
|
|
|
|
#define O_HOURS (60 * O_MINUTES)
|
|
|
|
#define O_DAYS (24 * O_HOURS)
|
2013-12-31 15:44:44 -05:00
|
|
|
|
2014-04-01 20:28:19 -04:00
|
|
|
Queue :: Queue()
|
2014-04-13 12:26:32 -04:00
|
|
|
: _cur(-1), _flags(0), _length(0)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-04-13 18:38:49 -04:00
|
|
|
Queue :: Queue(unsigned int f)
|
|
|
|
: _cur(-1), _flags(f & Q_FLAG_MASK), _length(0)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-04-01 20:28:19 -04:00
|
|
|
Queue :: ~Queue()
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-04-01 20:28:19 -04:00
|
|
|
void Queue :: write(File &f)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2014-04-13 12:26:32 -04:00
|
|
|
f << _flags << " " << _tracks.size();
|
|
|
|
for (unsigned int i = 0; i < _tracks.size(); i++)
|
2014-11-02 10:02:35 -05:00
|
|
|
f << " " << _tracks[i]->index();
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2014-04-01 20:28:19 -04:00
|
|
|
void Queue :: read(File &f)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2014-04-13 12:26:32 -04:00
|
|
|
unsigned int n, id;
|
|
|
|
f >> _flags >> n;
|
|
|
|
_tracks.resize(n);
|
|
|
|
for (unsigned int i = 0; i < n; i++) {
|
|
|
|
f >> id;
|
|
|
|
_tracks[i] = tagdb :: lookup(id);
|
2014-11-24 16:25:50 -05:00
|
|
|
_length += _tracks[i]->length();
|
2014-04-13 12:26:32 -04:00
|
|
|
}
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2014-04-01 20:28:19 -04:00
|
|
|
void Queue :: set_flag(queue_flags f)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2014-04-13 12:26:32 -04:00
|
|
|
_flags |= f;
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2014-04-01 20:28:19 -04:00
|
|
|
void Queue :: unset_flag(queue_flags f)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2014-04-13 12:26:32 -04:00
|
|
|
_flags &= ~f;
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2014-04-13 12:26:32 -04:00
|
|
|
bool Queue :: has_flag(queue_flags f)
|
2014-01-02 21:58:18 -05:00
|
|
|
{
|
2014-04-13 12:26:32 -04:00
|
|
|
return (_flags & f) == (unsigned int)f;
|
2014-01-02 21:58:18 -05:00
|
|
|
}
|
|
|
|
|
2014-05-18 14:11:21 -04:00
|
|
|
static bool track_less_than(Track *lhs, Track *rhs,
|
|
|
|
std::vector<struct sort_info> &order)
|
2014-01-26 12:12:01 -05:00
|
|
|
{
|
|
|
|
int res;
|
2014-01-25 14:43:51 -05:00
|
|
|
|
2014-05-18 14:11:21 -04:00
|
|
|
for (unsigned int i = 0; i < order.size(); i++) {
|
|
|
|
if (order[i].ascending == true)
|
|
|
|
res = lhs->less_than(rhs, order[i].field);
|
2014-01-26 14:44:56 -05:00
|
|
|
else
|
2014-05-18 14:11:21 -04:00
|
|
|
res = rhs->less_than(lhs, order[i].field);
|
|
|
|
if (res == 0)
|
|
|
|
continue;
|
|
|
|
break;
|
2014-01-26 12:12:01 -05:00
|
|
|
}
|
2014-05-18 14:11:21 -04:00
|
|
|
return res < 0;
|
2014-01-25 14:43:51 -05:00
|
|
|
}
|
|
|
|
|
2014-04-01 20:28:19 -04:00
|
|
|
unsigned int Queue :: find_sorted_id(Track *rhs)
|
2014-01-25 14:43:51 -05:00
|
|
|
{
|
2014-03-29 11:44:39 -04:00
|
|
|
Track *lhs;
|
2014-04-13 12:26:32 -04:00
|
|
|
unsigned int begin = 0, end = (_tracks.size() - 1), mid;
|
2014-01-25 14:43:51 -05:00
|
|
|
|
2014-04-13 12:26:32 -04:00
|
|
|
if (_tracks.size() == 0)
|
2014-01-27 11:22:35 -05:00
|
|
|
return 0;
|
2014-01-26 10:41:13 -05:00
|
|
|
|
2014-01-28 09:42:38 -05:00
|
|
|
while (end > begin) {
|
|
|
|
mid = begin + ((end - begin) / 2);
|
2014-04-13 12:26:32 -04:00
|
|
|
lhs = _tracks[mid];
|
|
|
|
if (track_less_than(lhs, rhs, _sort_order))
|
2014-01-28 09:42:38 -05:00
|
|
|
begin = mid + 1;
|
|
|
|
else {
|
|
|
|
if (mid == begin)
|
|
|
|
return begin;
|
|
|
|
else
|
|
|
|
end = mid - 1;
|
2014-01-27 11:22:35 -05:00
|
|
|
}
|
2014-01-27 10:23:22 -05:00
|
|
|
}
|
|
|
|
|
2014-04-13 12:26:32 -04:00
|
|
|
lhs = _tracks[begin];
|
|
|
|
if (track_less_than(lhs, rhs, _sort_order))
|
2014-01-28 09:42:38 -05:00
|
|
|
return begin + 1;
|
|
|
|
return begin;
|
2014-01-25 14:43:51 -05:00
|
|
|
}
|
|
|
|
|
2014-05-11 10:53:48 -04:00
|
|
|
unsigned int Queue :: _add_at(Track *track, unsigned int pos)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2014-05-11 10:53:48 -04:00
|
|
|
_tracks.insert(_tracks.begin() + pos, track);
|
2014-11-24 16:25:50 -05:00
|
|
|
_length += track->length();
|
2014-05-11 10:53:48 -04:00
|
|
|
get_callbacks()->on_queue_track_add(this, pos);
|
|
|
|
return pos;
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2014-05-11 11:23:15 -04:00
|
|
|
void Queue :: _del_at(Track *track, unsigned int pos)
|
|
|
|
{
|
|
|
|
_tracks.erase(_tracks.begin() + pos);
|
2014-11-24 16:25:50 -05:00
|
|
|
_length -= track->length();
|
2014-05-11 11:23:15 -04:00
|
|
|
get_callbacks()->on_queue_track_del(this, pos);
|
|
|
|
}
|
|
|
|
|
2014-05-11 10:53:48 -04:00
|
|
|
unsigned int Queue :: add(Track *track)
|
2014-01-02 21:58:18 -05:00
|
|
|
{
|
2014-05-11 10:53:48 -04:00
|
|
|
unsigned int id = _tracks.size();
|
|
|
|
if (_sort_order.size() > 0)
|
|
|
|
id = find_sorted_id(track);
|
|
|
|
return _add_at(track, id);
|
2014-01-02 21:58:18 -05:00
|
|
|
}
|
|
|
|
|
2014-05-11 11:23:15 -04:00
|
|
|
void Queue :: del(Track *track)
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2014-05-11 11:23:15 -04:00
|
|
|
for (unsigned int i = 0; i < _tracks.size(); i++) {
|
2014-05-11 18:32:53 -04:00
|
|
|
if (_tracks[i] == track)
|
2014-05-11 11:23:15 -04:00
|
|
|
_del_at(track, i);
|
|
|
|
}
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2014-05-11 11:23:15 -04:00
|
|
|
void Queue :: del(unsigned int id)
|
2014-01-16 22:05:36 -05:00
|
|
|
{
|
2014-05-11 11:23:15 -04:00
|
|
|
_del_at(_tracks[id], id);
|
2014-01-16 22:05:36 -05:00
|
|
|
}
|
|
|
|
|
2014-05-11 18:32:53 -04:00
|
|
|
void Queue :: updated(Track *track)
|
2014-01-29 22:45:01 -05:00
|
|
|
{
|
2014-04-13 12:26:32 -04:00
|
|
|
for (unsigned int i = 0; i < _tracks.size(); i++) {
|
2014-05-11 18:32:53 -04:00
|
|
|
if (_tracks[i] == track)
|
2014-01-29 22:45:01 -05:00
|
|
|
get_callbacks()->on_queue_track_changed(this, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-18 11:08:58 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-04-01 20:28:19 -04:00
|
|
|
unsigned int Queue :: size()
|
2013-12-31 15:44:44 -05:00
|
|
|
{
|
2014-04-13 12:26:32 -04:00
|
|
|
return _tracks.size();
|
2013-12-31 15:44:44 -05:00
|
|
|
}
|
|
|
|
|
2014-05-11 19:52:08 -04:00
|
|
|
const std::string Queue :: size_str()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << size();
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
const std::string Queue :: length_str()
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
unsigned int factor[4] = { O_DAYS, O_HOURS, O_MINUTES, 1 };
|
|
|
|
std::string fields[4] = { "day", "hour", "minute", "second" };
|
|
|
|
unsigned int len = _length;
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < 4; i++) {
|
|
|
|
unsigned int dur = len / factor[i];
|
|
|
|
len -= dur * factor[i];
|
|
|
|
|
|
|
|
if (dur > 0) {
|
|
|
|
ss << dur << " " << fields[i];
|
|
|
|
if (dur > 1)
|
|
|
|
ss << "s";
|
|
|
|
if (len > 0)
|
|
|
|
ss << ", ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2014-01-26 13:44:25 -05:00
|
|
|
class SortTracks {
|
|
|
|
public:
|
2014-05-18 14:11:21 -04:00
|
|
|
std::vector<struct sort_info> fields;
|
|
|
|
SortTracks(std::vector<sort_info> f) : fields(f) {}
|
|
|
|
bool operator()(Track *lhs, Track *rhs)
|
2014-01-26 13:44:25 -05:00
|
|
|
{
|
|
|
|
return track_less_than(lhs, rhs, fields);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-05-18 14:11:21 -04:00
|
|
|
void Queue :: sort(sort_t field, bool reset)
|
2014-01-26 12:12:01 -05:00
|
|
|
{
|
2014-05-18 14:11:21 -04:00
|
|
|
bool found = false;
|
|
|
|
struct sort_info info = { field, true };
|
2014-01-26 14:44:56 -05:00
|
|
|
|
2014-04-13 18:38:49 -04:00
|
|
|
if (_flags & Q_NO_SORT)
|
2014-01-26 14:49:07 -05:00
|
|
|
return;
|
2014-05-18 14:11:21 -04:00
|
|
|
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);
|
2014-01-26 14:49:07 -05:00
|
|
|
|
2014-04-13 12:26:32 -04:00
|
|
|
std::stable_sort(_tracks.begin(), _tracks.end(), SortTracks(_sort_order));
|
2014-01-26 14:44:56 -05:00
|
|
|
|
2014-04-13 12:26:32 -04:00
|
|
|
for (unsigned int i = 0; i < _tracks.size(); i++)
|
2014-01-26 13:44:25 -05:00
|
|
|
get_callbacks()->on_queue_track_changed(this, i);
|
2014-01-26 12:12:01 -05:00
|
|
|
}
|
|
|
|
|
2014-04-13 12:26:32 -04:00
|
|
|
Track *Queue :: operator[](unsigned int i)
|
2014-01-20 19:06:52 -05:00
|
|
|
{
|
2014-04-13 12:26:32 -04:00
|
|
|
return _tracks[i];
|
2014-01-20 19:06:52 -05:00
|
|
|
}
|
|
|
|
|
2014-05-18 14:24:46 -04:00
|
|
|
void Queue :: track_selected(unsigned int id)
|
2014-02-06 20:06:58 -05:00
|
|
|
{
|
2014-04-13 12:26:32 -04:00
|
|
|
_cur = id;
|
2014-05-18 14:24:46 -04:00
|
|
|
if (has_flag(Q_REPEAT) == false) {
|
2014-04-13 12:26:32 -04:00
|
|
|
del(_cur);
|
|
|
|
_cur--;
|
2014-02-06 20:06:58 -05:00
|
|
|
}
|
|
|
|
}
|