core/queue: Add queue operations vector

And a function to help with saving queues.  This patch also adds the
Q_SAVE_FLAGS and Q_SAVE_SORT queue flags to control if the queue should
be saved when flags are changed or when the queue is sorted.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
This commit is contained in:
Anna Schumaker 2015-11-23 08:36:29 -05:00
parent b3a8fa293b
commit ce55ef2421
12 changed files with 145 additions and 69 deletions

View File

@ -9,8 +9,6 @@
class RecentQueue : public queue
{
public:
RecentQueue() : queue(Q_ENABLED | Q_REPEAT | Q_NO_SORT) {}
unsigned int add(struct track *track)
{
del(track);
@ -25,9 +23,16 @@ static RecentQueue recent_queue;
static struct file deck_file;
TempQueue :: TempQueue() {}
TempQueue :: TempQueue()
{
queue_init(this, 0, NULL);
}
TempQueue :: TempQueue(bool random)
: queue(Q_ENABLED | (random ? Q_RANDOM : 0)) {}
{
queue_init(this, Q_ENABLED | (random ? Q_RANDOM : 0), NULL);
}
void TempQueue :: set_flag(queue_flags flag)
{
@ -91,7 +96,9 @@ void deck :: init()
bool upgraded = false;
std::list<TempQueue>::iterator it;
queue_init(&recent_queue, Q_ENABLED | Q_REPEAT | Q_NO_SORT, NULL);
file_init(&deck_file, "deck", 1);
if (!file_open(&deck_file, OPEN_READ))
return;

View File

@ -16,12 +16,9 @@ private:
public:
LibraryQueue() : queue(Q_ENABLED | Q_REPEAT)
LibraryQueue()
{
file_init(&f, "library.q", 0);
queue :: sort(COMPARE_ARTIST, true);
queue :: sort(COMPARE_YEAR, false);
queue :: sort(COMPARE_TRACK, false);
}
void save()
@ -154,12 +151,19 @@ void collection :: init()
{
struct db_entry *track, *next;
library_q.load();
queue_init(&library_q, Q_ENABLED | Q_REPEAT, NULL);
db_for_each(track, next, track_db_get()) {
if (TRACK(track)->tr_library->li_enabled)
library_q.add(TRACK(track));
}
library_q.load();
if (library_q.q_sort.size() == 0) {
library_q.sort(COMPARE_ARTIST, true);
library_q.sort(COMPARE_YEAR, false);
library_q.sort(COMPARE_TRACK, false);
}
}
struct library *collection :: add(const std::string &dir)

View File

@ -8,14 +8,6 @@
class PlaylistQueue : public queue {
public:
PlaylistQueue() : queue(Q_ENABLED | Q_REPEAT)
{
sort(COMPARE_ARTIST, true);
sort(COMPARE_YEAR, false);
sort(COMPARE_TRACK, false);
set_flag(Q_NO_SORT);
}
void clear()
{
while (queue_size(this) > 0)
@ -81,6 +73,12 @@ void playlist :: init()
{
struct set_iter it;
queue_init(&playlist_q, Q_ENABLED | Q_REPEAT, NULL);
playlist_q.sort(COMPARE_ARTIST, true);
playlist_q.sort(COMPARE_YEAR, false);
playlist_q.sort(COMPARE_TRACK, false);
playlist_q.set_flag(Q_NO_SORT);
index_init(&playlist_db, "playlist.db", true);
db_load(&playlist_db);
@ -94,6 +92,8 @@ void playlist :: init()
bool playlist :: has(struct track *track, const std::string &name)
{
if (playlist_db.db_size == 0)
return false;
return index_has(&playlist_db, name.c_str(), track->tr_dbe.dbe_index);
}

View File

@ -20,13 +20,21 @@ public:
} def_notify;
queue :: queue(unsigned int flags)
: q_cur(-1), q_flags(flags), q_length(0), q_notify(&def_notify)
{}
static inline void __queue_save(struct queue *queue, enum queue_flags flag)
{
if (queue->q_ops && queue_has_flag(queue, flag))
queue->q_ops->qop_save(queue, flag);
}
queue :: queue()
: q_cur(-1), q_flags(0), q_length(0), q_notify(&def_notify)
{}
void queue_init(struct queue *queue, unsigned int flags,
const struct queue_ops *ops)
{
queue->q_cur = -1;
queue->q_flags = flags;
queue->q_length = 0;
queue->q_notify = &def_notify;
queue->q_ops = ops;
}
queue :: ~queue()
{}
@ -53,11 +61,13 @@ void queue :: read(file &file)
void queue :: set_flag(queue_flags flag)
{
q_flags |= flag;
__queue_save(this, Q_SAVE_FLAGS);
}
void queue :: unset_flag(queue_flags flag)
{
q_flags &= ~flag;
__queue_save(this, Q_SAVE_FLAGS);
}
static bool track_less_than(struct track *lhs, struct track *rhs,
@ -210,4 +220,5 @@ void queue :: sort(compare_t field, bool reset)
for (unsigned int i = 0; i < q_tracks.size(); i++)
q_notify->on_track_updated(i);
__queue_save(this, Q_SAVE_SORT);
}

View File

@ -46,10 +46,10 @@ int main(int argc, char **argv)
exit(1);
gst :: init(&argc, &argv);
plist :: init();
core :: init();
plist :: init();
manager :: init();
init_tabs();
window = window_init();

View File

@ -147,8 +147,10 @@ static void on_favorite()
void plist :: track_loaded(struct track *track)
{
o_ban->set_active(playlist :: has(track, "Banned"));
o_fav->set_active(playlist :: has(track, "Favorites"));
if (p_tab) {
o_ban->set_active(playlist :: has(track, "Banned"));
o_fav->set_active(playlist :: has(track, "Favorites"));
}
}
void plist :: init()
@ -158,6 +160,8 @@ void plist :: init()
o_ban = gui :: get_widget<Gtk::ToggleButton>("o_ban");
o_fav = gui :: get_widget<Gtk::ToggleButton>("o_favorite");
track_loaded(audio :: current_track());
o_ban->signal_toggled().connect(sigc::ptr_fun(on_ban));
o_fav->signal_toggled().connect(sigc::ptr_fun(on_favorite));
}

View File

@ -17,10 +17,12 @@ extern "C" {
* Enum defining flags that effect a Queue's behavior.
*/
enum queue_flags {
Q_ENABLED = (1 << 0), /**< Queue is enabled. */
Q_RANDOM = (1 << 1), /**< Queue will pick songs randomly. */
Q_REPEAT = (1 << 2), /**< Queue will not remove songs when picked. */
Q_NO_SORT = (1 << 3), /**< Queue will not be sorted. */
Q_ENABLED = (1 << 0), /* Queue is enabled. */
Q_RANDOM = (1 << 1), /* Queue will pick songs randomly. */
Q_REPEAT = (1 << 2), /* Queue will not remove songs when picked. */
Q_NO_SORT = (1 << 3), /* Queue will not be sorted. */
Q_SAVE_FLAGS = (1 << 4), /* Queue will be saved when flags change. */
Q_SAVE_SORT = (1 << 5), /* Queue will be saved when sorted. */
};
@ -54,6 +56,12 @@ public:
};
struct queue_ops {
/* Called to have a higher layer save the queue. */
void (*qop_save)(struct queue *, enum queue_flags);
};
/**
* Struct for passing sort parameters.
*/
@ -81,18 +89,12 @@ struct queue {
std :: vector <struct track *> q_tracks; /* The queue's list of tracks. */
std :: vector <struct sort_info> q_sort; /* The queue's sort settings. */
const struct queue_ops *q_ops; /* The queue's operations vector. */
unsigned int find_sorted_id(struct track *);
unsigned int _add_at(struct track *, unsigned int);
/**
* Alternate queue constructor.
*
* @param flags Create a queue with _flags set to flags.
*/
queue(unsigned int);
queue(); /**< Default queue constructor. */
virtual ~queue(); /**< Queue destructor. */
/**
@ -163,6 +165,10 @@ struct queue {
};
/* Called to initialize a queue. */
void queue_init(struct queue *, unsigned int, const struct queue_ops *);
/* Called to check if the queue has a specific flag set. */
static inline bool queue_has_flag(struct queue *queue, enum queue_flags flag)
{

View File

@ -6,6 +6,7 @@ extern "C" {
#include <core/filter.h>
#include <core/tags/tags.h>
}
#include <core/deck.h>
#include <core/library.h>
#include "test.h"
@ -88,6 +89,7 @@ void test_init()
filter_init();
tags_init();
collection :: init();
deck :: init();
audio :: init();
track = audio :: current_track();

View File

@ -113,9 +113,10 @@ static void test_next_prev()
{
std::list<TempQueue>::iterator it = deck :: get_queues().begin();
queue *q = deck :: get_queue();
queue *q0 = &(*it++);
queue *q1 = &(*it++);
queue *q0 = deck :: get(0);
queue *q1 = deck :: get(1);
q0->q_notify = &test_notifier;
q0->unset_flag(Q_RANDOM);
for (unsigned int i = 0; i < 4; i++)
q0->add(track_get(i));

View File

@ -16,15 +16,14 @@ static void test_init()
{
queue *q = collection :: get_queue();
test_not_equal(q, Q_NULL);
test_equal(queue_has_flag(q, Q_ENABLED), true);
test_equal(queue_has_flag(q, Q_REPEAT), true);
test_cp_data_dir();
filter_init();
tags_init();
collection :: init();
test_not_equal(q, Q_NULL);
test_equal(queue_has_flag(q, Q_ENABLED), true);
test_equal(queue_has_flag(q, Q_REPEAT), true);
test_equal(queue_size(q), (unsigned)24);
}

View File

@ -17,20 +17,17 @@ static void test_init()
index_entry *ent;
queue *q = playlist :: get_queue();
test_not_equal(q, Q_NULL);
test_equal(queue_has_flag(q, Q_ENABLED), true);
test_equal(queue_has_flag(q, Q_REPEAT), true);
test_equal(queue_has_flag(q, Q_NO_SORT), true);
/* init should work even if playlist.db doesn't exist! */
playlist :: init();
test_cp_data_dir();
filter_init();
tags_init();
collection :: init();
playlist :: init();
test_not_equal(q, Q_NULL);
test_equal(queue_has_flag(q, Q_ENABLED), true);
test_equal(queue_has_flag(q, Q_REPEAT), true);
test_equal(queue_has_flag(q, Q_NO_SORT), true);
ent = playlist :: get_tracks("Banned");
test_equal(set_size(&ent->ie_set), (size_t)4);
test_equal(queue_size(collection :: get_queue()), (unsigned)20);

View File

@ -10,8 +10,10 @@ extern "C" {
#include "test.h"
unsigned int count_added = 0;
unsigned int count_added = 0;
unsigned int count_deleted = 0;
unsigned int count_flags = 0;
unsigned int count_sort = 0;
unsigned int count_updated = 0;
@ -24,6 +26,20 @@ public:
} test_notifier;
static void queue_op_save(struct queue *queue, enum queue_flags flag)
{
if (flag == Q_SAVE_FLAGS)
count_flags++;
else if (flag == Q_SAVE_SORT)
count_sort++;
}
static const struct queue_ops test_ops = {
queue_op_save,
};
static void __test_init_core()
{
struct library *library;
@ -60,48 +76,65 @@ static void test_init()
__test_init_core();
queue_init(&q, 0, NULL);
test_equal(q.q_cur, (unsigned int)-1);
test_equal(q.q_flags, 0);
test_equal(q.q_length, 0);
test_equal(q.q_sort.size(), (size_t)0);
test_equal(q.q_ops, NULL);
test_equal(queue_next(&q), (struct track *)NULL);
test_not_equal(q.q_notify, NULL);
q = queue(Q_ENABLED | Q_RANDOM);
queue_init(&q, Q_ENABLED | Q_RANDOM, &test_ops);
q.q_notify = &test_notifier;
test_equal(q.q_cur, (unsigned int )-1);
test_equal(q.q_flags, Q_ENABLED | Q_RANDOM);
test_equal(q.q_length, 0);
test_equal(q.q_sort.size(), 0);
test_equal(q.q_ops, &test_ops);
test_equal(queue_next(&q), (struct track *)NULL);
test_equal(q.q_notify, &test_notifier);
}
static void test_flags()
{
struct queue q(0);
struct queue q;
queue_init(&q, 0, &test_ops);
test_equal(q.q_flags, 0);
test_equal(queue_has_flag(&q, Q_ENABLED), false);
test_equal(queue_has_flag(&q, Q_RANDOM), false);
test_equal(queue_has_flag(&q, Q_REPEAT), false);
test_equal(queue_has_flag(&q, Q_NO_SORT), false);
test_equal(queue_has_flag(&q, Q_ENABLED), false);
test_equal(queue_has_flag(&q, Q_RANDOM), false);
test_equal(queue_has_flag(&q, Q_REPEAT), false);
test_equal(queue_has_flag(&q, Q_NO_SORT), false);
test_equal(queue_has_flag(&q, Q_SAVE_FLAGS), false);
test_equal(queue_has_flag(&q, Q_SAVE_SORT), false);
q.set_flag(Q_ENABLED);
test_equal(q.q_flags, Q_ENABLED);
test_equal(q.q_flags, Q_ENABLED);
test_equal(count_flags, 0);
q.unset_flag(Q_ENABLED);
test_equal(q.q_flags, 0);
test_equal(q.q_flags, 0);
test_equal(count_flags, 0);
q.set_flag(Q_SAVE_FLAGS);
q.set_flag(Q_ENABLED);
q.set_flag(Q_RANDOM);
q.set_flag(Q_REPEAT);
q.set_flag(Q_NO_SORT);
test_equal(queue_has_flag(&q, Q_ENABLED), true);
test_equal(queue_has_flag(&q, Q_RANDOM), true);
test_equal(queue_has_flag(&q, Q_REPEAT), true);
test_equal(queue_has_flag(&q, Q_NO_SORT), true);
test_equal(queue_has_flag(&q, Q_ENABLED), true);
test_equal(queue_has_flag(&q, Q_RANDOM), true);
test_equal(queue_has_flag(&q, Q_REPEAT), true);
test_equal(queue_has_flag(&q, Q_NO_SORT), true);
test_equal(queue_has_flag(&q, Q_SAVE_FLAGS), true);
test_equal(count_flags, 5);
q.unset_flag(Q_ENABLED);
q.unset_flag(Q_RANDOM);
q.unset_flag(Q_REPEAT);
q.unset_flag(Q_NO_SORT);
test_equal(count_flags, 9);
}
static void test_stress(unsigned int N)
@ -109,12 +142,14 @@ static void test_stress(unsigned int N)
unsigned int ex_length = 0;
unsigned int ex_size = N;
struct track *track;
struct queue q(0);
unsigned int i;
struct queue q;
count_added = 0;
count_deleted = 0;
count_updated = 0;
queue_init(&q, 0, &test_ops);
q.q_notify = &test_notifier;
/* Queue :: add() */
@ -180,10 +215,11 @@ static void test_stress_100K() { test_stress(100009); }
static void test_rand_select()
{
struct queue q(Q_ENABLED | Q_RANDOM);
unsigned int i;
struct queue q;
random_seed(0);
queue_init(&q, Q_ENABLED | Q_RANDOM, &test_ops);
/* Call next() on an empty queue. */
for (i = 0; i < 13; i++) {
@ -256,9 +292,10 @@ static void test_sorting()
unsigned int ex_title[] = { 6, 9, 8, 3, 2, 5, 1, 4, 11, 10, 12, 0, 7 };
unsigned int ex_co_ti[] = { 3, 2, 5, 1, 4, 0, 6, 9, 8, 11, 10, 12, 7 };
struct track *track;
struct queue q(0);
unsigned int i;
struct queue q;
queue_init(&q, Q_SAVE_SORT, &test_ops);
for (i = 0; i < 13; i++) {
track = track_get(i);
track->tr_count = (i < 6) ? 4 : 2;
@ -271,6 +308,7 @@ static void test_sorting()
test_loop_not_equal(track, NULL, i);
test_loop_equal(track->tr_dbe.dbe_index, ex_count[i], i);
} test_loop_passed();
test_equal(count_sort, 1);
q.set_flag(Q_NO_SORT);
q.sort(COMPARE_TITLE, true);
@ -287,6 +325,7 @@ static void test_sorting()
test_loop_not_equal(track, NULL, i);
test_loop_equal(track->tr_dbe.dbe_index, ex_title[i], i);
} test_loop_passed();
test_equal(count_sort, 2);
q.sort(COMPARE_COUNT, true);
q.sort(COMPARE_TITLE, false);
@ -296,7 +335,9 @@ static void test_sorting()
test_loop_not_equal(track, NULL, i);
test_loop_equal(track->tr_dbe.dbe_index, ex_co_ti[i], i);
} test_loop_passed();
test_equal(count_sort, 5);
q.unset_flag(Q_SAVE_SORT);
q.sort(COMPARE_ARTIST, true);
q.sort(COMPARE_ALBUM, false);
q.sort(COMPARE_TRACK, false);
@ -306,15 +347,19 @@ static void test_sorting()
test_loop_not_equal(track, NULL, i);
test_loop_equal(track->tr_dbe.dbe_index, 12 - i, i);
} test_loop_passed();
test_equal(count_sort, 5);
}
static void test_save_load()
{
struct queue q(Q_RANDOM), r(0);
struct track *track;
struct queue q, r;
unsigned int i;
struct file f;
queue_init(&q, Q_RANDOM, &test_ops);
queue_init(&r, 0, &test_ops);
for (i = 0; i < 13; i++)
q.add(track_get(i));
q.sort(COMPARE_TRACK, true);