~ubuntu-branches/ubuntu/precise/rhythmbox/precise-201203091205

« back to all changes in this revision

Viewing changes to shell/rb-play-order-random.c

Tags: upstream-0.9.2cvs20060102
ImportĀ upstreamĀ versionĀ 0.9.2cvs20060102

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
2
3
 *  arch-tag: Implementation of base class for weighted random play orders
3
4
 *
4
5
 *  Copyright (C) 2003 Jeffrey Yasskin <jyasskin@mail.utexas.edu>
29
30
 * will not see any changes to their history of played songs.
30
31
 */
31
32
 
 
33
#include <string.h>
 
34
 
32
35
#include "rb-play-order-random-by-age.h"
33
36
 
34
37
#include "rb-debug.h"
35
38
#include "rhythmdb.h"
36
39
#include "rb-history.h"
37
 
#include <string.h>
38
40
 
39
41
static void rb_random_play_order_class_init (RBRandomPlayOrderClass *klass);
40
42
static void rb_random_play_order_init (RBRandomPlayOrder *rorder);
47
49
static void rb_random_play_order_go_previous (RBPlayOrder* porder);
48
50
 
49
51
static void rb_random_db_changed (RBPlayOrder *porder, RhythmDB *db);
50
 
static void rb_random_playing_entry_changed (RBPlayOrder *porder, RhythmDBEntry *entry);
51
 
static void rb_random_entry_view_changed (RBPlayOrder *porder);
 
52
static void rb_random_playing_entry_changed (RBPlayOrder *porder, 
 
53
                                             RhythmDBEntry *old_entry, 
 
54
                                             RhythmDBEntry *new_entry);
 
55
static void rb_random_query_model_changed (RBPlayOrder *porder);
52
56
static void rb_random_db_entry_deleted (RBPlayOrder *porder, RhythmDBEntry *entry);
53
57
 
54
 
static void rb_random_handle_entry_view_changed (RBRandomPlayOrder *rorder);
55
 
static void rb_random_filter_history (RBRandomPlayOrder *rorder, RBEntryView *entry_view);
 
58
static void rb_random_handle_query_model_changed (RBRandomPlayOrder *rorder);
 
59
static void rb_random_filter_history (RBRandomPlayOrder *rorder, RhythmDBQueryModel *model);
56
60
 
57
61
struct RBRandomPlayOrderPrivate
58
62
{
62
66
         * over the real one when go_{next,previous} are called. */
63
67
        RBHistory *tentative_history;
64
68
 
65
 
        gboolean entry_view_changed;
 
69
        gboolean query_model_changed;
66
70
};
67
71
 
68
 
static RBPlayOrderClass *parent_class = NULL;
69
 
 
70
 
GType
71
 
rb_random_play_order_get_type (void)
72
 
{
73
 
        static GType rb_random_play_order_type = 0;
74
 
 
75
 
        if (rb_random_play_order_type == 0)
76
 
        {
77
 
                static const GTypeInfo our_info =
78
 
                {
79
 
                        sizeof (RBRandomPlayOrderClass),
80
 
                        NULL,
81
 
                        NULL,
82
 
                        (GClassInitFunc) rb_random_play_order_class_init,
83
 
                        NULL,
84
 
                        NULL,
85
 
                        sizeof (RBRandomPlayOrder),
86
 
                        0,
87
 
                        (GInstanceInitFunc) rb_random_play_order_init
88
 
                };
89
 
 
90
 
                rb_random_play_order_type = g_type_register_static (RB_TYPE_PLAY_ORDER,
91
 
                                "RBRandomPlayOrder",
92
 
                                &our_info, 0);
93
 
        }
94
 
 
95
 
        return rb_random_play_order_type;
96
 
}
 
72
G_DEFINE_TYPE (RBRandomPlayOrder, rb_random_play_order, RB_TYPE_PLAY_ORDER)
 
73
#define RB_RANDOM_PLAY_ORDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_RANDOM_PLAY_ORDER, RBRandomPlayOrderPrivate))
 
74
 
97
75
 
98
76
static void
99
77
rb_random_play_order_class_init (RBRandomPlayOrderClass *klass)
101
79
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
102
80
        RBPlayOrderClass *porder;
103
81
 
104
 
        parent_class = g_type_class_peek_parent (klass);
105
 
 
106
82
        object_class->finalize = rb_random_play_order_finalize;
107
83
 
108
 
 
109
84
        porder = RB_PLAY_ORDER_CLASS (klass);
110
85
        porder->db_changed = rb_random_db_changed;
111
86
        porder->playing_entry_changed = rb_random_playing_entry_changed;
112
 
        porder->entry_added = (void (*)(RBPlayOrder*,RhythmDBEntry*))rb_random_entry_view_changed;
113
 
        porder->entry_removed = (void (*)(RBPlayOrder*,RhythmDBEntry*))rb_random_entry_view_changed;
114
 
        porder->entries_replaced = rb_random_entry_view_changed;
 
87
        porder->entry_added = (void (*)(RBPlayOrder*,RhythmDBEntry*))rb_random_query_model_changed;
 
88
        porder->entry_removed = (void (*)(RBPlayOrder*,RhythmDBEntry*))rb_random_query_model_changed;
 
89
        porder->query_model_changed = rb_random_query_model_changed;
115
90
        porder->db_entry_deleted = rb_random_db_entry_deleted;
116
91
 
117
92
        porder->get_next = rb_random_play_order_get_next;
118
93
        porder->go_next = rb_random_play_order_go_next;
119
94
        porder->get_previous = rb_random_play_order_get_previous;
120
95
        porder->go_previous = rb_random_play_order_go_previous;
 
96
 
 
97
        g_type_class_add_private (klass, sizeof (RBRandomPlayOrderPrivate));
121
98
}
122
99
 
123
100
static void
124
101
rb_random_play_order_init (RBRandomPlayOrder *rorder)
125
102
{
126
 
        rorder->priv = g_new0 (RBRandomPlayOrderPrivate, 1);
 
103
        rorder->priv = RB_RANDOM_PLAY_ORDER_GET_PRIVATE (rorder);
127
104
 
128
105
        rorder->priv->history = rb_history_new (TRUE,
129
106
                                                (GFunc) rb_play_order_unref_entry_swapped,
130
107
                                                rb_play_order_get_db (RB_PLAY_ORDER (rorder)));
131
108
        rb_history_set_maximum_size (rorder->priv->history, 50);
132
109
 
133
 
        rorder->priv->entry_view_changed = TRUE;
 
110
        rorder->priv->query_model_changed = TRUE;
134
111
}
135
112
 
136
113
static void
146
123
        g_object_unref (G_OBJECT (rorder->priv->history));
147
124
        if (rorder->priv->tentative_history)
148
125
                g_object_unref (G_OBJECT (rorder->priv->tentative_history));
149
 
        g_free (rorder->priv);
150
126
 
151
 
        G_OBJECT_CLASS (parent_class)->finalize (object);
 
127
        G_OBJECT_CLASS (rb_random_play_order_parent_class)->finalize (object);
152
128
}
153
129
 
154
130
static double
176
152
} EntryWeight;
177
153
 
178
154
static GArray *
179
 
get_entry_view_contents (RBRandomPlayOrder *rorder, RBEntryView *entry_view)
 
155
get_query_model_contents (RBRandomPlayOrder *rorder, RhythmDBQueryModel *model)
180
156
{
181
157
        guint num_entries;
182
158
        guint i;
183
159
        RhythmDB *db;
184
 
        double total_weight;
 
160
        double weight = 0.0;
 
161
        double cumulative_weight = 0.0;
 
162
        GtkTreeIter iter;
185
163
        GArray *result = g_array_new (FALSE, FALSE, sizeof (EntryWeight));
186
164
 
187
 
        if (entry_view == NULL)
 
165
        if (model == NULL)
188
166
                return result;
189
167
 
190
 
        num_entries = rb_entry_view_get_num_entries (entry_view);
 
168
        num_entries = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (model), NULL);
191
169
        if (num_entries == 0)
192
170
                return result;
193
171
 
194
172
        g_array_set_size (result, num_entries);
195
 
        g_object_get (G_OBJECT (entry_view),
196
 
                      "db", &db,
197
 
                      NULL);
198
 
 
199
 
        g_array_index (result, EntryWeight, 0).entry = rb_entry_view_get_first_entry (entry_view);
200
 
        g_array_index (result, EntryWeight, 0).weight
201
 
                = rb_random_play_order_get_entry_weight (rorder, db, g_array_index (result, EntryWeight, 0).entry);
202
 
        for (i=1; i<num_entries; ++i) {
203
 
                g_array_index (result, EntryWeight, i).entry
204
 
                        = rb_entry_view_get_next_from_entry (entry_view, g_array_index (result, EntryWeight, i-1).entry);
205
 
                g_array_index (result, EntryWeight, i).weight
206
 
                        = rb_random_play_order_get_entry_weight (rorder, db, g_array_index (result, EntryWeight, i).entry);
207
 
 
208
 
        }
209
 
 
210
 
        total_weight = 0.0;
211
 
        for (i=0; i < num_entries; ++i) {
212
 
                g_array_index (result, EntryWeight, i).cumulative_weight = total_weight;
213
 
                total_weight += g_array_index (result, EntryWeight, i).weight;
214
 
        }
 
173
        db = rb_play_order_get_db (RB_PLAY_ORDER (rorder));
 
174
 
 
175
        if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter))
 
176
                return result;
 
177
 
 
178
        i = 0;
 
179
        do {
 
180
                RhythmDBEntry *entry = rhythmdb_query_model_iter_to_entry (model, &iter);
 
181
                if (!entry)
 
182
                        continue;
 
183
                weight = rb_random_play_order_get_entry_weight (rorder, db, entry);
 
184
 
 
185
                g_array_index (result, EntryWeight, i).entry = entry;
 
186
                g_array_index (result, EntryWeight, i).weight = weight;
 
187
                g_array_index (result, EntryWeight, i).cumulative_weight = cumulative_weight;
 
188
                cumulative_weight += weight;
 
189
                i++;
 
190
        } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (model), &iter));
215
191
 
216
192
        return result;
217
193
}
218
194
 
219
195
static void
220
 
rb_random_handle_entry_view_changed (RBRandomPlayOrder *rorder)
 
196
rb_random_handle_query_model_changed (RBRandomPlayOrder *rorder)
221
197
{
222
 
        if (rorder->priv->entry_view_changed) {
223
 
                RBEntryView *entry_view;
224
 
                entry_view = rb_play_order_get_entry_view (RB_PLAY_ORDER (rorder));
225
 
 
226
 
                rb_random_filter_history (rorder, entry_view);
227
 
 
228
 
                rorder->priv->entry_view_changed = FALSE;
229
 
        }
 
198
        RhythmDBQueryModel *model;
 
199
 
 
200
        if (!rorder->priv->query_model_changed)
 
201
                return;
 
202
 
 
203
        model = rb_play_order_get_query_model (RB_PLAY_ORDER (rorder));
 
204
        rb_random_filter_history (rorder, model);
 
205
        rorder->priv->query_model_changed = FALSE;
230
206
}
231
207
 
232
208
static void
233
 
rb_random_filter_history (RBRandomPlayOrder *rorder, RBEntryView *entry_view)
 
209
rb_random_filter_history (RBRandomPlayOrder *rorder, RhythmDBQueryModel *model)
234
210
{
235
211
        GPtrArray *history_contents;
236
212
        int i;
241
217
        }
242
218
        history_contents = rb_history_dump (rorder->priv->history);
243
219
        for (i=0; i < history_contents->len; ++i) {
244
 
                if (!entry_view || !rb_entry_view_get_entry_contained (entry_view, g_ptr_array_index (history_contents, i))) {
 
220
                gboolean remove = TRUE;
 
221
                if (model) {
 
222
                        GtkTreeIter iter;
 
223
                        if (rhythmdb_query_model_entry_to_iter (model, g_ptr_array_index (history_contents, i), &iter))
 
224
                                remove = FALSE;
 
225
                }
 
226
 
 
227
                if (remove) {
245
228
                        if (!rorder->priv->tentative_history)
246
229
                                rorder->priv->tentative_history
247
230
                                        = rb_history_clone (rorder->priv->history,
248
231
                                                            (GFunc) rb_play_order_ref_entry_swapped,
249
232
                                                            rb_play_order_get_db (RB_PLAY_ORDER (rorder)));
250
 
                        rb_history_remove_entry (rorder->priv->tentative_history, g_ptr_array_index (history_contents, i));
 
233
                        rb_history_remove_entry (rorder->priv->tentative_history, 
 
234
                                                 g_ptr_array_index (history_contents, i));
251
235
                }
252
236
        }
253
237
 
282
266
static RhythmDBEntry*
283
267
rb_random_play_order_pick_entry (RBRandomPlayOrder *rorder)
284
268
{
285
 
        /* This is O(N) because we traverse the entry-view to get the entries
 
269
        /* This is O(N) because we traverse the query model to get the entries
286
270
         * and weights.
287
271
         *
288
272
         * The general idea of this algorithm is that there is a line segment
297
281
        int high, low;
298
282
        GArray *entry_weights;
299
283
        RhythmDBEntry *entry;
300
 
        RBEntryView *entry_view;
301
 
 
302
 
        entry_view = rb_play_order_get_entry_view (RB_PLAY_ORDER (rorder));
303
 
 
304
 
        entry_weights = get_entry_view_contents (rorder, entry_view);
 
284
        RhythmDBQueryModel *model;
 
285
 
 
286
        model = rb_play_order_get_query_model (RB_PLAY_ORDER (rorder));
 
287
 
 
288
        entry_weights = get_query_model_contents (rorder, model);
305
289
 
306
290
        total_weight = rb_random_get_total_weight (entry_weights);
307
291
        if (total_weight == 0.0)
330
314
{
331
315
        RBRandomPlayOrder *rorder;
332
316
        RhythmDBEntry *entry;
 
317
        RBHistory *history;
333
318
 
334
319
        g_return_val_if_fail (porder != NULL, NULL);
335
320
        g_return_val_if_fail (RB_IS_RANDOM_PLAY_ORDER (porder), NULL);
336
321
 
337
322
        rorder = RB_RANDOM_PLAY_ORDER (porder);
338
323
 
339
 
        rb_random_handle_entry_view_changed (rorder);
 
324
        rb_random_handle_query_model_changed (rorder);
 
325
        history = get_history (rorder);
340
326
 
341
 
        if (rb_history_current (get_history (rorder)) == NULL
342
 
                        || (rb_play_order_get_playing_entry (porder) == rb_history_current (get_history (rorder))
343
 
                                && rb_history_current (get_history (rorder)) == rb_history_last (get_history (rorder)))) {
 
327
        entry = rb_play_order_get_playing_entry (porder);
 
328
        if (rb_history_current (history) == NULL
 
329
            || (entry == rb_history_current (history)
 
330
                && rb_history_current (history) == rb_history_last (history))) {
344
331
 
345
332
                rb_debug ("choosing random entry");
346
333
                entry = rb_random_play_order_pick_entry (rorder);
 
334
                if (entry) {
 
335
                        rhythmdb_entry_ref (rb_play_order_get_db (porder), entry);
 
336
                        rb_history_append (history, entry);
 
337
                }
347
338
        } else {
348
339
                rb_debug ("choosing enqueued entry");
349
 
                if (rb_play_order_get_playing_entry (porder) == rb_history_current (get_history (rorder)))
350
 
                        entry = rb_history_next (get_history (rorder));
 
340
                if (entry == rb_history_current (history))
 
341
                        entry = rb_history_next (history);
351
342
                else
352
 
                        entry = rb_history_current (get_history (rorder));
 
343
                        entry = rb_history_current (history);
353
344
        }
354
345
 
355
346
        return entry;
359
350
rb_random_play_order_go_next (RBPlayOrder* porder)
360
351
{
361
352
        RBRandomPlayOrder *rorder;
 
353
        RhythmDBEntry *entry;
 
354
        RBHistory *history;
362
355
 
363
356
        g_return_if_fail (porder != NULL);
364
357
        g_return_if_fail (RB_IS_RANDOM_PLAY_ORDER (porder));
365
358
 
366
359
        rorder = RB_RANDOM_PLAY_ORDER (porder);
367
 
 
368
 
        if (rb_play_order_get_playing_entry (porder) == rb_history_current (get_history (rorder)))
369
 
                rb_history_go_next (get_history (rorder));
370
 
        else {
371
 
                /* Leave the current entry current */
372
 
        }
 
360
        history = get_history (rorder);
 
361
        
 
362
        g_object_get (G_OBJECT (rorder), "playing-entry", &entry, NULL);
 
363
        g_assert (entry == NULL || entry == rb_history_current (history));
 
364
        if (entry == rb_history_current (history))
 
365
                rb_history_go_next (history);
 
366
        rb_play_order_set_playing_entry (porder, rb_history_current (history));
373
367
}
374
368
 
375
369
static RhythmDBEntry*
379
373
 
380
374
        g_return_val_if_fail (porder != NULL, NULL);
381
375
        g_return_val_if_fail (RB_IS_RANDOM_PLAY_ORDER (porder), NULL);
382
 
        /* It doesn't make sense to call get_previous when the player is stopped */
383
 
        g_return_val_if_fail (rb_play_order_player_is_playing (porder), NULL);
384
376
 
385
377
        rorder = RB_RANDOM_PLAY_ORDER (porder);
386
378
 
387
 
        rb_random_handle_entry_view_changed (rorder);
 
379
        rb_random_handle_query_model_changed (rorder);
388
380
 
389
381
        rb_debug ("choosing history entry");
390
382
        return rb_history_previous (get_history (rorder));
394
386
rb_random_play_order_go_previous (RBPlayOrder* porder)
395
387
{
396
388
        RBRandomPlayOrder *rorder;
 
389
        RBHistory *history;
397
390
 
398
391
        g_return_if_fail (porder != NULL);
399
392
        g_return_if_fail (RB_IS_RANDOM_PLAY_ORDER (porder));
400
 
        /* It doesn't make sense to call get_previous when the player is stopped */
 
393
        /* It doesn't make sense to call go_previous when the player is stopped */
401
394
        g_return_if_fail (rb_play_order_player_is_playing (porder));
402
395
 
403
396
        rorder = RB_RANDOM_PLAY_ORDER (porder);
 
397
        history = get_history (rorder);
404
398
 
405
 
        rb_history_go_previous (get_history (rorder));
 
399
        rb_history_go_previous (history);
 
400
        rb_play_order_set_playing_entry (porder, rb_history_current (history));
406
401
}
407
402
 
408
403
static void
418
413
}
419
414
 
420
415
static void
421
 
rb_random_playing_entry_changed (RBPlayOrder *porder, RhythmDBEntry *entry)
 
416
rb_random_playing_entry_changed (RBPlayOrder *porder, 
 
417
                                 RhythmDBEntry *old_entry,
 
418
                                 RhythmDBEntry *new_entry)
422
419
{
423
420
        RBRandomPlayOrder *rorder;
424
421
 
427
424
 
428
425
        rb_random_commit_history (rorder);
429
426
 
430
 
        if (entry) {
431
 
                if (entry == rb_history_current (get_history (rorder))) {
 
427
        if (new_entry) {
 
428
                if (new_entry == rb_history_current (get_history (rorder))) {
432
429
                        /* Do nothing */
433
430
                } else {
434
 
                        rhythmdb_entry_ref (rb_play_order_get_db (porder), entry);
435
 
                        rb_history_set_playing (get_history (rorder), entry);
 
431
                        rhythmdb_entry_ref (rb_play_order_get_db (porder), new_entry);
 
432
                        rb_history_set_playing (get_history (rorder), new_entry);
436
433
                }
437
434
        }
438
435
}
439
436
 
440
437
static void
441
 
rb_random_entry_view_changed (RBPlayOrder *porder)
 
438
rb_random_query_model_changed (RBPlayOrder *porder)
442
439
{
443
440
        g_return_if_fail (RB_IS_RANDOM_PLAY_ORDER (porder));
444
 
        RB_RANDOM_PLAY_ORDER (porder)->priv->entry_view_changed = TRUE;
 
441
        RB_RANDOM_PLAY_ORDER (porder)->priv->query_model_changed = TRUE;
445
442
}
446
443
 
447
444
static void