/* * Copyright 2013 (c) Anna Schumaker. */ #include #include #include #include #include #define O_MINUTES (60) #define O_HOURS (60 * O_MINUTES) #define O_DAYS (24 * O_HOURS) Queue :: Queue() : _cur(-1), _flags(0), _length(0) { } Queue :: Queue(unsigned int f) : _cur(-1), _flags(f & Q_FLAG_MASK), _length(0) { } Queue :: ~Queue() { } void Queue :: write(File &f) { f << _flags << " " << _tracks.size(); for (unsigned int i = 0; i < _tracks.size(); i++) f << " " << _tracks[i]; } void Queue :: read(File &f) { 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); } } void Queue :: set_flag(queue_flags f) { _flags |= f; } void Queue :: unset_flag(queue_flags f) { _flags &= ~f; } bool Queue :: has_flag(queue_flags f) { return (_flags & f) == (unsigned int)f; } static bool track_less_than(Track *lhs, Track *rhs, std::vector &order) { int res; for (unsigned int i = 0; i < order.size(); i++) { if (order[i].ascending == true) res = lhs->less_than(rhs, order[i].field); else res = rhs->less_than(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; get_callbacks()->on_queue_track_add(this, pos); if (!(_flags & Q_DISABLE_CHANGED_SIZE)) get_callbacks()->on_queue_changed(); return pos; } void Queue :: _del_at(Track *track, unsigned int pos) { _tracks.erase(_tracks.begin() + pos); _length -= track->length; get_callbacks()->on_queue_track_del(this, pos); if (!(_flags & Q_DISABLE_CHANGED_SIZE)) get_callbacks()->on_queue_changed(); } 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(Track *track) { for (unsigned int i = 0; i < _tracks.size(); i++) { if (_tracks[i] == track) _del_at(track, i); } } void Queue :: del(unsigned int id) { _del_at(_tracks[id], id); } void Queue :: updated(Track *track) { for (unsigned int i = 0; i < _tracks.size(); i++) { if (_tracks[i] == track) get_callbacks()->on_queue_track_changed(this, 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(); } 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(); } class SortTracks { public: std::vector fields; SortTracks(std::vector 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++) get_callbacks()->on_queue_track_changed(this, i); get_callbacks()->on_queue_changed(); } Track *Queue :: operator[](unsigned int i) { return _tracks[i]; } void Queue :: path_selected(unsigned int id) { _cur = id; if (!(_flags &Q_REPEAT)) { del(_cur); _cur--; } }