/** * Copyright 2013 (c) Anna Schumaker. */ #include extern "C" { #include } #include #include #include 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_writef(&file, "%u %zu", _flags, _tracks.size()); for (unsigned int i = 0; i < _tracks.size(); i++) file_writef(&file, " %u", _tracks[i]->tr_dbe.dbe_index); } void Queue :: read(file &file) { unsigned int n, id; file_readf(&file, "%u %u", &_flags, &n); _tracks.resize(n); for (unsigned int i = 0; i < n; i++) { file_readf(&file, "%u", &id); _tracks[i] = track_get(id); _length += _tracks[i]->tr_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; } static bool track_less_than(struct track *lhs, struct track *rhs, std::vector &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(struct track *rhs) { struct 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(struct track *track, unsigned int pos) { _tracks.insert(_tracks.begin() + pos, track); _length += track->tr_length; _notify->on_track_added(pos); return pos; } unsigned int Queue :: add(struct 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]->tr_length; _tracks.erase(_tracks.begin() + index); _notify->on_track_removed(index); } void Queue :: del(struct track *track) { for (unsigned int i = 0; i < _tracks.size(); i++) { while ((i < _tracks.size()) && (_tracks[i] == track)) del(i); } } void Queue :: updated(struct track *track) { for (unsigned int i = 0; i < _tracks.size(); i++) { if (_tracks[i] == track) _notify->on_track_updated(i); } } struct track *Queue :: next() { struct track *res; if (_tracks.size() == 0) return NULL; else if (_tracks.size() == 1) _cur = 0; else if (_flags & Q_RANDOM) _cur += random_range(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 fields; SortTracks(std::vector f) : fields(f) {} bool operator()(struct track *lhs, struct track *rhs) { return track_less_than(lhs, rhs, fields); } }; void Queue :: sort(compare_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); } struct 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--; } }