106
114
static gboolean rhythmdb_query_model_iter_parent (GtkTreeModel *tree_model,
107
115
GtkTreeIter *iter,
108
116
GtkTreeIter *child);
109
static GSequencePtr choose_sequence_element (GSequence *seq);
111
static gboolean idle_poll_model (RhythmDBQueryModel *model);
113
static const GtkTargetEntry rhythmdb_query_model_drag_types[] = { { "text/uri-list", 0, 0 },};
115
static GtkTargetList *rhythmdb_query_model_drag_target_list = NULL;
117
119
struct RhythmDBQueryModelUpdate
121
RhythmDBQueryModel *model;
120
123
RHYTHMDB_QUERY_MODEL_UPDATE_ROWS_INSERTED,
121
RHYTHMDB_QUERY_MODEL_UPDATE_ROW_CHANGED,
122
RHYTHMDB_QUERY_MODEL_UPDATE_ROW_DELETED,
123
124
RHYTHMDB_QUERY_MODEL_UPDATE_QUERY_COMPLETE,
125
126
RhythmDBEntry *entry;
126
127
GPtrArray *entries;
128
/* Only used for _ROW_CHANGED */
129
RhythmDBPropType prop;
130
static void rhythmdb_query_model_process_update (struct RhythmDBQueryModelUpdate *update);
132
static gboolean idle_process_update (struct RhythmDBQueryModelUpdate *update);
134
static const GtkTargetEntry rhythmdb_query_model_drag_types[] = { { "text/uri-list", 0, 0 },};
136
static GtkTargetList *rhythmdb_query_model_drag_target_list = NULL;
134
139
struct RhythmDBQueryModelPrivate
138
143
GCompareDataFunc sort_func;
139
144
gpointer sort_user_data;
145
GDestroyNotify sort_destroy_notify;
147
GPtrArray *query, *original_query;
145
151
GnomeVFSFileSize max_size;
150
155
gboolean connected;
154
157
glong total_duration;
155
158
GnomeVFSFileSize total_size;
157
160
GSequence *entries;
158
161
GHashTable *reverse_map;
160
GAsyncQueue *query_complete;
162
/* row_inserted/row_changed/row_deleted */
163
GAsyncQueue *pending_updates;
162
GSequence *limited_entries;
163
GHashTable *limited_reverse_map;
165
gint pending_update_count;
165
167
gboolean reorder_drag_and_drop;
177
PROP_SORT_DATA_DESTROY,
182
186
ENTRY_PROP_CHANGED,
186
192
static guint rhythmdb_query_model_signals[LAST_SIGNAL] = { 0 };
188
static GObjectClass *parent_class = NULL;
191
rhythmdb_query_model_get_type (void)
193
static GType rhythmdb_query_model_type = 0;
195
if (rhythmdb_query_model_type == 0)
197
static const GTypeInfo our_info =
199
sizeof (RhythmDBQueryModelClass),
202
(GClassInitFunc) rhythmdb_query_model_class_init,
205
sizeof (RhythmDBQueryModel),
207
(GInstanceInitFunc) rhythmdb_query_model_init
210
static const GInterfaceInfo tree_model_info =
212
(GInterfaceInitFunc) rhythmdb_query_model_tree_model_init,
217
static const GInterfaceInfo drag_source_info = {
218
(GInterfaceInitFunc) rhythmdb_query_model_drag_source_init,
223
static const GInterfaceInfo drag_dest_info = {
224
(GInterfaceInitFunc) rhythmdb_query_model_drag_dest_init,
229
rhythmdb_query_model_type = g_type_register_static (G_TYPE_OBJECT,
230
"RhythmDBQueryModel",
233
g_type_add_interface_static (rhythmdb_query_model_type,
237
g_type_add_interface_static (rhythmdb_query_model_type,
238
RB_TYPE_TREE_DRAG_SOURCE,
241
g_type_add_interface_static (rhythmdb_query_model_type,
242
RB_TYPE_TREE_DRAG_DEST,
246
return rhythmdb_query_model_type;
250
195
rhythmdb_query_model_class_init (RhythmDBQueryModelClass *klass)
252
197
GObjectClass *object_class = G_OBJECT_CLASS (klass);
254
parent_class = g_type_class_peek_parent (klass);
256
199
if (!rhythmdb_query_model_drag_target_list)
257
200
rhythmdb_query_model_drag_target_list
258
201
= gtk_target_list_new (rhythmdb_query_model_drag_types,
310
260
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
262
g_object_class_install_property (object_class,
264
g_param_spec_int ("max-time",
266
"maximum time (seconds)",
268
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
312
270
rhythmdb_query_model_signals[ENTRY_PROP_CHANGED] =
313
271
g_signal_new ("entry-prop-changed",
314
272
RHYTHMDB_TYPE_QUERY_MODEL,
315
273
G_SIGNAL_RUN_LAST,
316
274
G_STRUCT_OFFSET (RhythmDBQueryModelClass, entry_prop_changed),
318
rb_marshal_VOID__POINTER_INT_POINTER_POINTER,
276
rhythmdb_marshal_VOID__POINTER_INT_POINTER_POINTER,
319
277
G_TYPE_NONE, 4, G_TYPE_POINTER,
320
278
G_TYPE_INT, G_TYPE_POINTER, G_TYPE_POINTER);
279
rhythmdb_query_model_signals[ENTRY_REMOVED] =
280
g_signal_new ("entry-removed",
281
RHYTHMDB_TYPE_QUERY_MODEL,
283
G_STRUCT_OFFSET (RhythmDBQueryModelClass, entry_removed),
285
rhythmdb_marshal_VOID__POINTER,
286
G_TYPE_NONE, 1, G_TYPE_POINTER);
287
rhythmdb_query_model_signals[NON_ENTRY_DROPPED] =
288
g_signal_new ("non-entry-dropped",
289
RHYTHMDB_TYPE_QUERY_MODEL,
291
G_STRUCT_OFFSET (RhythmDBQueryModelClass, non_entry_dropped),
293
rhythmdb_marshal_VOID__POINTER,
294
G_TYPE_NONE, 1, G_TYPE_STRING);
321
295
rhythmdb_query_model_signals[COMPLETE] =
322
296
g_signal_new ("complete",
323
297
RHYTHMDB_TYPE_QUERY_MODEL,
592
548
model->priv->connected = connected;
596
rhythmdb_query_model_finish_complete (RhythmDBQueryModel *model)
598
if (!rb_thread_helpers_in_main_thread ())
599
g_async_queue_pop (model->priv->query_complete);
603
552
rhythmdb_query_model_has_pending_changes (RhythmDBQueryModel *model)
605
return g_async_queue_length (model->priv->pending_updates) > 0;
608
static inline GSequencePtr
609
choose_sequence_element (GSequence *seq)
611
return g_sequence_get_ptr_at_pos (seq, 0);
614
/* Threading: should be entered via database thread, with db lock held
554
return g_atomic_int_get (&model->priv->pending_update_count) > 0;
617
558
rhythmdb_query_model_entry_added_cb (RhythmDB *db, RhythmDBEntry *entry,
618
559
RhythmDBQueryModel *model)
620
if (G_LIKELY (model->priv->query)) {
621
if (model->priv->max_count > 0
622
&& g_hash_table_size (model->priv->reverse_map) >= model->priv->max_count)
561
if (model->priv->query) {
562
if (rhythmdb_entry_get_boolean (entry, RHYTHMDB_PROP_HIDDEN))
624
/* Check size later */
626
565
if (rhythmdb_evaluate_query (db, model->priv->query, entry)) {
627
rhythmdb_query_model_add_entry (model, entry);
566
rhythmdb_query_model_do_insert (model, entry);
633
572
rhythmdb_query_model_entry_changed_cb (RhythmDB *db, RhythmDBEntry *entry,
634
RhythmDBPropType prop, const GValue *old,
635
const GValue *new, RhythmDBQueryModel *model)
573
GSList *changes, RhythmDBQueryModel *model)
637
if (!model->priv->connected) {
641
if (g_hash_table_lookup (model->priv->reverse_map, entry) != NULL) {
642
struct RhythmDBQueryModelUpdate *update;
644
if (model->priv->query &&
645
!rhythmdb_evaluate_query (db, model->priv->query, entry)) {
646
rhythmdb_query_model_remove_entry (model, entry);
650
rb_debug ("queueing entry change");
652
update = g_new0 (struct RhythmDBQueryModelUpdate, 1);
653
update->type = RHYTHMDB_QUERY_MODEL_UPDATE_ROW_CHANGED;
654
update->entry = entry;
656
g_value_init (&update->old, G_VALUE_TYPE (old));
657
g_value_copy (old, &update->old);
658
g_value_init (&update->new, G_VALUE_TYPE (new));
659
g_value_copy (new, &update->new);
661
/* Called with a locked database */
662
rhythmdb_entry_ref_unlocked (model->priv->db, entry);
664
g_async_queue_push (model->priv->pending_updates, update);
666
/* the changed entry may now satisfy the query so we test it */
667
rhythmdb_query_model_entry_added_cb (db, entry, model);
575
gboolean hidden = FALSE;
578
if (!model->priv->connected)
582
hidden = rhythmdb_entry_get_boolean (entry, RHYTHMDB_PROP_HIDDEN);
584
if (g_hash_table_lookup (model->priv->reverse_map, entry) == NULL) {
585
if (hidden == FALSE) {
586
/* the changed entry may now satisfy the query
588
rhythmdb_query_model_entry_added_cb (db, entry, model);
594
rhythmdb_query_model_remove_entry (model, entry);
598
/* emit separate change signals for each property */
599
for (t = changes; t; t = t->next) {
600
RhythmDBEntryChange *change = t->data;
601
g_signal_emit (G_OBJECT (model),
602
rhythmdb_query_model_signals[ENTRY_PROP_CHANGED], 0,
603
entry, change->prop, &change->old, &change->new);
605
if (change->prop == RHYTHMDB_PROP_DURATION) {
606
model->priv->total_duration -= g_value_get_ulong (&change->old);
607
model->priv->total_duration += g_value_get_ulong (&change->new);
608
} else if (change->prop == RHYTHMDB_PROP_FILE_SIZE) {
609
model->priv->total_size -= g_value_get_uint64 (&change->old);
610
model->priv->total_size += g_value_get_uint64 (&change->new);
614
if (model->priv->query &&
615
!rhythmdb_evaluate_query (db, model->priv->query, entry)) {
616
rhythmdb_query_model_filter_out_entry (model, entry);
620
/* it may have moved, so we can't just emit a changed entry */
621
rhythmdb_query_model_do_reorder (model, entry);
672
625
rhythmdb_query_model_entry_deleted_cb (RhythmDB *db, RhythmDBEntry *entry,
673
626
RhythmDBQueryModel *model)
675
rhythmdb_query_model_remove_entry (model, entry);
678
/* Threading: Called from the database context, holding a db write lock
629
if (g_hash_table_lookup (model->priv->reverse_map, entry) ||
630
g_hash_table_lookup (model->priv->limited_reverse_map, entry))
631
rhythmdb_query_model_remove_entry (model, entry);
635
rhythmdb_query_model_process_update (struct RhythmDBQueryModelUpdate *update)
637
g_atomic_int_inc (&update->model->priv->pending_update_count);
638
if (rb_is_main_thread ())
639
idle_process_update (update);
641
g_idle_add ((GSourceFunc) idle_process_update, update);
645
idle_process_update (struct RhythmDBQueryModelUpdate *update)
647
switch (update->type) {
648
case RHYTHMDB_QUERY_MODEL_UPDATE_ROWS_INSERTED:
651
rb_debug ("inserting %d rows", update->entries->len);
652
for (i = 0; i < update->entries->len; i++ ) {
653
RhythmDBEntry *entry = g_ptr_array_index (update->entries, i);
655
if (!rhythmdb_entry_get_boolean (entry, RHYTHMDB_PROP_HIDDEN))
656
rhythmdb_query_model_do_insert (update->model, entry);
658
rhythmdb_entry_unref (update->model->priv->db, entry);
660
g_ptr_array_free (update->entries, TRUE);
663
case RHYTHMDB_QUERY_MODEL_UPDATE_QUERY_COMPLETE:
664
g_signal_emit (G_OBJECT (update->model), rhythmdb_query_model_signals[COMPLETE], 0);
668
g_atomic_int_add (&update->model->priv->pending_update_count, -1);
669
g_object_unref (G_OBJECT (update->model));
674
/* Threading: Called from the database query thread for async queries,
675
* from the main thread for synchronous queries.
681
678
rhythmdb_query_model_add_entries (RhythmDBQueryModel *model, GPtrArray *entries)
741
715
return model->priv->total_duration;
745
compare_times (GTimeVal *a, GTimeVal *b)
747
if (a->tv_sec == b->tv_sec)
748
/* It's quite unlikely that microseconds are equal,
749
* so just ignore that case, we don't need a lot
752
return a->tv_usec > b->tv_usec ? 1 : -1;
753
else if (a->tv_sec > b->tv_sec)
760
rhythmdb_query_model_do_insert (RhythmDBQueryModel *model,
761
RhythmDBEntry *entry)
719
rhythmdb_query_model_insert_into_main_list (RhythmDBQueryModel *model, RhythmDBEntry *entry)
763
721
GSequencePtr ptr;
769
/* we check again if the entry already exists in the hash table */
770
if (g_hash_table_lookup (model->priv->reverse_map, entry) != NULL)
773
if (model->priv->max_count > 0
774
&& g_hash_table_size (model->priv->reverse_map) >= model->priv->max_count)
777
rhythmdb_read_lock (model->priv->db);
778
size = rhythmdb_entry_get_uint64 (model->priv->db, entry,
779
RHYTHMDB_PROP_FILE_SIZE);
780
duration = rhythmdb_entry_get_long (model->priv->db,
781
entry, RHYTHMDB_PROP_DURATION);
782
rhythmdb_read_unlock (model->priv->db);
784
if (model->priv->max_size > 0
785
&& (model->priv->total_size + size >= model->priv->max_size))
788
723
rhythmdb_entry_ref (model->priv->db, entry);
790
725
if (model->priv->sort_func) {
791
rhythmdb_read_lock (model->priv->db);
792
726
ptr = g_sequence_insert_sorted (model->priv->entries, entry,
793
727
model->priv->sort_func,
794
728
model->priv->sort_user_data);
795
rhythmdb_read_unlock (model->priv->db);
797
730
ptr = g_sequence_get_end_ptr (model->priv->entries);
798
731
g_sequence_insert (ptr, entry);
802
735
g_hash_table_insert (model->priv->reverse_map, entry, ptr);
804
model->priv->total_duration += duration;
805
model->priv->total_size += size;
807
iter.stamp = model->priv->stamp;
808
iter.user_data = ptr;
809
path = rhythmdb_query_model_get_path (GTK_TREE_MODEL (model),
811
gtk_tree_model_row_inserted (GTK_TREE_MODEL (model),
813
gtk_tree_path_free (path);
737
model->priv->total_duration += rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION);
738
model->priv->total_size += rhythmdb_entry_get_uint64 (entry, RHYTHMDB_PROP_FILE_SIZE);
817
rhythmdb_query_model_do_delete (RhythmDBQueryModel *model,
818
RhythmDBEntry *entry)
742
rhythmdb_query_model_insert_into_limited_list (RhythmDBQueryModel *model, RhythmDBEntry *entry)
821
744
GSequencePtr ptr;
746
rhythmdb_entry_ref (model->priv->db, entry);
748
if (model->priv->sort_func) {
749
ptr = g_sequence_insert_sorted (model->priv->limited_entries, entry,
750
model->priv->sort_func,
751
model->priv->sort_user_data);
753
ptr = g_sequence_get_end_ptr (model->priv->limited_entries);
754
g_sequence_insert (ptr, entry);
755
ptr = g_sequence_ptr_prev (ptr);
758
g_hash_table_insert (model->priv->limited_reverse_map, entry, ptr);
762
rhythmdb_query_model_remove_from_main_list (RhythmDBQueryModel *model, RhythmDBEntry *entry)
764
GSequencePtr ptr = g_hash_table_lookup (model->priv->reverse_map, entry);
824
ptr = g_hash_table_lookup (model->priv->reverse_map, entry);
829
768
index = g_sequence_ptr_get_position (ptr);
831
770
path = gtk_tree_path_new ();
832
771
gtk_tree_path_append_index (path, index);
833
rb_debug ("emitting row deleted");
834
773
gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
835
774
gtk_tree_path_free (path);
837
rhythmdb_read_lock (model->priv->db);
838
model->priv->total_duration -= rhythmdb_entry_get_long (model->priv->db, entry,
839
RHYTHMDB_PROP_DURATION);
840
model->priv->total_size -= rhythmdb_entry_get_uint64 (model->priv->db, entry,
841
RHYTHMDB_PROP_FILE_SIZE);
842
rhythmdb_read_unlock (model->priv->db);
776
model->priv->total_duration -= entry->duration;
777
model->priv->total_size -= entry->file_size;
844
779
g_sequence_remove (ptr);
845
780
g_hash_table_remove (model->priv->reverse_map, entry);
847
782
rhythmdb_entry_unref (model->priv->db, entry);
851
idle_poll_model (RhythmDBQueryModel *model)
786
rhythmdb_query_model_remove_from_limited_list (RhythmDBQueryModel *model, RhythmDBEntry *entry)
856
g_get_current_time (&timeout);
857
g_time_val_add (&timeout, G_USEC_PER_SEC*0.75);
859
GDK_THREADS_ENTER ();
861
did_sync = rhythmdb_query_model_poll (model, &timeout);
864
model->priv->model_poll_id =
865
g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) idle_poll_model, model, NULL);
867
model->priv->model_poll_id =
868
g_timeout_add (300, (GSourceFunc) idle_poll_model, model);
870
GDK_THREADS_LEAVE ();
788
GSequencePtr ptr = g_hash_table_lookup (model->priv->limited_reverse_map, entry);
790
g_sequence_remove (ptr);
791
g_hash_table_remove (model->priv->limited_reverse_map, entry);
792
rhythmdb_entry_unref (model->priv->db, entry);
875
/* Threading: main thread only, should hold GDK lock
878
rhythmdb_query_model_poll (RhythmDBQueryModel *model, GTimeVal *timeout)
796
rhythmdb_query_model_update_limited_entries (RhythmDBQueryModel *model)
880
GList *processed = NULL, *tem;
882
struct RhythmDBQueryModelUpdate *update;
885
if (G_UNLIKELY (model->priv->cancelled))
888
while ((update = g_async_queue_try_pop (model->priv->pending_updates)) != NULL) {
798
RhythmDBEntry *entry;
801
/* make it fit inside the limits */
802
while ((model->priv->max_count > 0 && g_hash_table_size (model->priv->reverse_map) > model->priv->max_count) ||
803
(model->priv->max_size > 0 && model->priv->total_size > model->priv->max_size) ||
804
(model->priv->max_time > 0 && model->priv->total_duration > model->priv->max_time)) {
806
ptr = g_sequence_ptr_prev (g_sequence_get_end_ptr (model->priv->entries));
807
entry = (RhythmDBEntry*) g_sequence_ptr_get_data (ptr);
809
rb_debug ("query: moving entry to limited list");
810
rhythmdb_query_model_remove_from_main_list (model, entry);
811
rhythmdb_query_model_insert_into_limited_list (model, entry);
814
/* move entries that were previously limited, back to the main list */
889
818
GtkTreePath *path;
890
819
GtkTreeIter iter;
821
ptr = g_sequence_get_begin_ptr (model->priv->limited_entries);
822
if (!ptr || ptr == g_sequence_get_end_ptr (model->priv->limited_entries))
824
entry = (RhythmDBEntry*) g_sequence_ptr_get_data (ptr);
828
size = entry->file_size;
829
duration = entry->duration;
831
if ((model->priv->max_count > 0 && (g_hash_table_size (model->priv->reverse_map) + 1) > model->priv->max_count) ||
832
(model->priv->max_size > 0 && model->priv->total_size + size > model->priv->max_size) ||
833
(model->priv->max_time > 0 && model->priv->total_duration + duration > model->priv->max_time))
836
rb_debug ("query: moving entry from limited list");
837
rhythmdb_query_model_remove_from_limited_list (model, entry);
838
rhythmdb_query_model_insert_into_main_list (model, entry);
840
ptr = g_hash_table_lookup (model->priv->reverse_map, entry);
896
841
iter.stamp = model->priv->stamp;
898
switch (update->type) {
899
case RHYTHMDB_QUERY_MODEL_UPDATE_ROWS_INSERTED:
902
rb_debug ("inserting %d rows", update->entries->len);
903
for (i = 0; i < update->entries->len; i++)
904
rhythmdb_query_model_do_insert (model, g_ptr_array_index (update->entries, i));
907
case RHYTHMDB_QUERY_MODEL_UPDATE_ROW_CHANGED:
909
ptr = g_hash_table_lookup (model->priv->reverse_map,
915
g_signal_emit (G_OBJECT (model),
916
rhythmdb_query_model_signals[ENTRY_PROP_CHANGED], 0,
917
update->entry, update->prop, &update->old, &update->new);
919
iter.user_data = ptr;
920
path = rhythmdb_query_model_get_path (GTK_TREE_MODEL (model),
922
rb_debug ("emitting row changed");
923
gtk_tree_model_row_changed (GTK_TREE_MODEL (model),
925
gtk_tree_path_free (path);
928
case RHYTHMDB_QUERY_MODEL_UPDATE_ROW_DELETED:
930
rhythmdb_query_model_do_delete (model, update->entry);
933
case RHYTHMDB_QUERY_MODEL_UPDATE_QUERY_COMPLETE:
935
g_signal_emit (G_OBJECT (model), rhythmdb_query_model_signals[COMPLETE], 0);
936
g_async_queue_push (model->priv->query_complete, GINT_TO_POINTER (1));
941
processed = g_list_prepend (processed, update);
944
if (timeout && count / 8 > 0) {
945
/* Do this here at the bottom, so we do at least one update. */
946
g_get_current_time (&now);
947
if (compare_times (timeout,&now) < 0)
952
for (tem = processed; tem; tem = tem->next)
953
rhythmdb_query_model_free_pending_update (model, tem->data);
955
g_list_free (processed);
956
return processed != NULL;
842
iter.user_data = ptr;
843
path = rhythmdb_query_model_get_path (GTK_TREE_MODEL (model),
845
gtk_tree_model_row_inserted (GTK_TREE_MODEL (model),
847
gtk_tree_path_free (path);
853
rhythmdb_query_model_do_reorder (RhythmDBQueryModel *model, RhythmDBEntry *entry)
856
int old_pos, new_pos;
862
if (model->priv->sort_func == NULL)
865
ptr = g_sequence_get_begin_ptr (model->priv->limited_entries);
867
if (ptr != NULL && !g_sequence_ptr_is_end (ptr)) {
868
RhythmDBEntry *first_limited = g_sequence_ptr_get_data (ptr);
869
int cmp = (model->priv->sort_func) (entry, first_limited, model->priv->sort_user_data);
872
/* the entry belongs in the limited list, so we don't need a re-order */
873
rhythmdb_query_model_remove_entry (model, entry);
874
rhythmdb_query_model_do_insert (model, entry);
879
ptr = g_hash_table_lookup (model->priv->reverse_map, entry);
880
iter.stamp = model->priv->stamp;
881
iter.user_data = ptr;
882
path = rhythmdb_query_model_get_path (GTK_TREE_MODEL (model),
884
gtk_tree_model_row_changed (GTK_TREE_MODEL (model),
886
gtk_tree_path_free (path);
888
/* it may have moved, check for a re-order */
889
length = g_sequence_get_length (model->priv->entries);
891
g_hash_table_remove (model->priv->reverse_map, entry);
892
old_pos = g_sequence_ptr_get_position (ptr);
893
g_sequence_remove (ptr);
895
ptr = g_sequence_insert_sorted (model->priv->entries, entry,
896
model->priv->sort_func,
897
model->priv->sort_user_data);
898
new_pos = g_sequence_ptr_get_position (ptr);
899
g_hash_table_insert (model->priv->reverse_map, entry, ptr);
901
if (new_pos == old_pos) {
902
/* it hasn't moved, don't emit a re-order */
906
reorder_map = malloc (length * sizeof(gint));
908
if (new_pos > old_pos) {
909
/* it has mover further down the list */
910
for (i = 0; i < old_pos; i++)
912
for (i = old_pos; i < new_pos; i++)
913
reorder_map[i] = i + 1;
914
reorder_map[new_pos] = old_pos;
915
for (i = new_pos + 1; i < length; i++)
918
/* it has moved up the list */
919
for (i = 0; i < new_pos; i++)
921
reorder_map[new_pos] = old_pos;
922
for (i = new_pos + 1; i < old_pos + 1; i++)
923
reorder_map[i] = i - 1;
924
for (i = old_pos + 1; i < length; i++)
928
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (model), &iter);
929
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
931
gtk_tree_model_rows_reordered (GTK_TREE_MODEL (model),
934
gtk_tree_path_free (path);
939
rhythmdb_query_model_do_insert (RhythmDBQueryModel *model,
940
RhythmDBEntry *entry)
946
g_assert (!rhythmdb_entry_get_boolean (entry, RHYTHMDB_PROP_HIDDEN));
948
/* we check again if the entry already exists in the hash table */
949
if (g_hash_table_lookup (model->priv->reverse_map, entry) != NULL)
951
ptr = g_hash_table_lookup (model->priv->limited_reverse_map, entry);
953
rhythmdb_query_model_remove_from_limited_list (model, entry);
955
rhythmdb_query_model_insert_into_main_list (model, entry);
957
/* it was added to the main list, send out the inserted signal */
958
ptr = g_hash_table_lookup (model->priv->reverse_map, entry);
959
iter.stamp = model->priv->stamp;
960
iter.user_data = ptr;
961
path = rhythmdb_query_model_get_path (GTK_TREE_MODEL (model),
963
gtk_tree_model_row_inserted (GTK_TREE_MODEL (model),
965
gtk_tree_path_free (path);
967
rhythmdb_query_model_update_limited_entries (model);
971
rhythmdb_query_model_filter_out_entry (RhythmDBQueryModel *model,
972
RhythmDBEntry *entry)
976
ptr = g_hash_table_lookup (model->priv->reverse_map, entry);
978
rhythmdb_query_model_remove_from_main_list (model, entry);
979
rhythmdb_query_model_update_limited_entries (model);
983
ptr = g_hash_table_lookup (model->priv->limited_reverse_map, entry);
985
rhythmdb_query_model_remove_from_limited_list (model, entry);
986
rhythmdb_query_model_update_limited_entries (model);
993
rhythmdb_query_model_remove_entry (RhythmDBQueryModel *model,
994
RhythmDBEntry *entry)
996
gboolean present = (g_hash_table_lookup (model->priv->reverse_map, entry) == NULL) ||
997
(g_hash_table_lookup (model->priv->limited_reverse_map, entry) == NULL);
998
g_return_val_if_fail (present, FALSE);
1000
/* emit entry-removed, so listeners know the
1001
* entry has actually been removed, rather than filtered
1004
g_signal_emit (G_OBJECT (model),
1005
rhythmdb_query_model_signals[ENTRY_REMOVED], 0,
1007
rhythmdb_query_model_filter_out_entry (model, entry);