1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * arch-tag: Implementation of GtkTreeModel iface containing RBSource objects
5 * Copyright (C) 2003 Colin Walters <walters@verbum.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301 USA.
28 #include <glib/gi18n.h>
32 #include "rb-sourcelist-model.h"
33 #include "rb-tree-dnd.h"
35 #include "rb-marshal.h"
36 #include "rb-playlist-source.h"
38 struct RBSourceListModelPrivate
40 GtkTreeRowReference
*groups
[RB_SOURCELIST_GROUP_LAST
];
43 #define RB_SOURCELIST_MODEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_SOURCELIST_MODEL, RBSourceListModelPrivate))
51 static void rb_sourcelist_model_class_init (RBSourceListModelClass
*klass
);
52 static void rb_sourcelist_model_init (RBSourceListModel
*model
);
53 static void rb_sourcelist_model_drag_dest_init (RbTreeDragDestIface
*iface
);
54 static void rb_sourcelist_model_drag_source_init (RbTreeDragSourceIface
*iface
);
55 static void rb_sourcelist_model_finalize (GObject
*object
);
56 static gboolean
rb_sourcelist_model_is_row_visible (GtkTreeModel
*model
,
58 RBSourceListModel
*sourcelist
);
59 static gboolean
rb_sourcelist_model_drag_data_received (RbTreeDragDest
*drag_dest
,
61 GtkTreeViewDropPosition pos
,
62 GtkSelectionData
*selection_data
);
63 static gboolean
rb_sourcelist_model_row_drop_possible (RbTreeDragDest
*drag_dest
,
65 GtkTreeViewDropPosition pos
,
66 GtkSelectionData
*selection_data
);
67 static gboolean
rb_sourcelist_model_row_drop_position (RbTreeDragDest
*drag_dest
,
68 GtkTreePath
*dest_path
,
70 GtkTreeViewDropPosition
*pos
);
71 static GdkAtom
rb_sourcelist_model_get_drag_target (RbTreeDragDest
*drag_dest
,
73 GdkDragContext
*context
,
75 GtkTargetList
*target_list
);
76 static gboolean
rb_sourcelist_model_drag_data_delete (RbTreeDragSource
*drag_source
,
78 static gboolean
rb_sourcelist_model_drag_data_get (RbTreeDragSource
*drag_source
,
80 GtkSelectionData
*selection_data
);
81 static gboolean
rb_sourcelist_model_row_draggable (RbTreeDragSource
*drag_source
,
83 static void rb_sourcelist_model_row_inserted_cb (GtkTreeModel
*model
,
86 RBSourceListModel
*sourcelist
);
87 static void rb_sourcelist_model_row_deleted_cb (GtkTreeModel
*model
,
89 RBSourceListModel
*sourcelist
);
91 static guint rb_sourcelist_model_signals
[LAST_SIGNAL
] = { 0 };
100 static const GtkTargetEntry sourcelist_targets
[] = { { "text/x-rhythmbox-album", 0, TARGET_PROPERTY
},
101 { "text/x-rhythmbox-artist", 0, TARGET_PROPERTY
},
102 { "text/x-rhythmbox-genre", 0, TARGET_PROPERTY
},
103 { "application/x-rhythmbox-source", 0, TARGET_SOURCE
},
104 { "text/uri-list", 0, TARGET_URIS
},
105 { "application/x-delete-me", 0, TARGET_DELETE
}};
107 static GtkTargetList
*sourcelist_drag_target_list
= NULL
;
109 G_DEFINE_TYPE_EXTENDED (RBSourceListModel
,
111 GTK_TYPE_TREE_MODEL_FILTER
,
113 G_IMPLEMENT_INTERFACE (RB_TYPE_TREE_DRAG_SOURCE
,
114 rb_sourcelist_model_drag_source_init
)
115 G_IMPLEMENT_INTERFACE (RB_TYPE_TREE_DRAG_DEST
,
116 rb_sourcelist_model_drag_dest_init
));
119 rb_sourcelist_model_class_init (RBSourceListModelClass
*class)
121 GObjectClass
*o_class
;
122 GtkObjectClass
*object_class
;
124 o_class
= (GObjectClass
*) class;
125 object_class
= (GtkObjectClass
*) class;
127 o_class
->finalize
= rb_sourcelist_model_finalize
;
129 rb_sourcelist_model_signals
[DROP_RECEIVED
] =
130 g_signal_new ("drop_received",
131 G_OBJECT_CLASS_TYPE (object_class
),
133 G_STRUCT_OFFSET (RBSourceListModelClass
, drop_received
),
135 rb_marshal_VOID__OBJECT_INT_POINTER
,
138 RB_TYPE_SOURCE
, G_TYPE_INT
, G_TYPE_POINTER
);
140 if (!sourcelist_drag_target_list
)
141 sourcelist_drag_target_list
=
142 gtk_target_list_new (sourcelist_targets
,
143 G_N_ELEMENTS (sourcelist_targets
));
145 g_type_class_add_private (class, sizeof (RBSourceListModelPrivate
));
149 rb_sourcelist_model_drag_dest_init (RbTreeDragDestIface
*iface
)
151 iface
->drag_data_received
= rb_sourcelist_model_drag_data_received
;
152 iface
->row_drop_possible
= rb_sourcelist_model_row_drop_possible
;
153 iface
->row_drop_position
= rb_sourcelist_model_row_drop_position
;
154 iface
->get_drag_target
= rb_sourcelist_model_get_drag_target
;
158 rb_sourcelist_model_drag_source_init (RbTreeDragSourceIface
*iface
)
160 iface
->row_draggable
= rb_sourcelist_model_row_draggable
;
161 iface
->drag_data_get
= rb_sourcelist_model_drag_data_get
;
162 iface
->drag_data_delete
= rb_sourcelist_model_drag_data_delete
;
166 rb_sourcelist_model_set_dnd_targets (RBSourceListModel
*sourcelist
,
167 GtkTreeView
*treeview
)
169 int n_targets
= G_N_ELEMENTS (sourcelist_targets
);
170 g_return_if_fail (RB_IS_SOURCELIST_MODEL (sourcelist
));
172 rb_tree_dnd_add_drag_dest_support (treeview
,
173 (RB_TREE_DEST_EMPTY_VIEW_DROP
| RB_TREE_DEST_SELECT_ON_DRAG_TIMEOUT
),
174 sourcelist_targets
, n_targets
,
177 rb_tree_dnd_add_drag_source_support (treeview
,
179 sourcelist_targets
, n_targets
,
184 rb_sourcelist_model_init (RBSourceListModel
*model
)
186 model
->priv
= RB_SOURCELIST_MODEL_GET_PRIVATE (model
);
190 rb_sourcelist_model_finalize (GObject
*object
)
192 RBSourceListModel
*model
;
195 g_return_if_fail (RB_IS_SOURCELIST_MODEL (object
));
196 model
= RB_SOURCELIST_MODEL (object
);
198 for (i
= 0; i
< RB_SOURCELIST_GROUP_LAST
; i
++) {
199 gtk_tree_row_reference_free (model
->priv
->groups
[i
]);
202 G_OBJECT_CLASS (rb_sourcelist_model_parent_class
)->finalize (object
);
206 rb_sourcelist_model_new (void)
208 RBSourceListModel
*model
;
211 GType
*column_types
= g_new (GType
, RB_SOURCELIST_MODEL_N_COLUMNS
);
213 column_types
[RB_SOURCELIST_MODEL_COLUMN_PLAYING
] = G_TYPE_BOOLEAN
;
214 column_types
[RB_SOURCELIST_MODEL_COLUMN_PIXBUF
] = GDK_TYPE_PIXBUF
;
215 column_types
[RB_SOURCELIST_MODEL_COLUMN_NAME
] = G_TYPE_STRING
;
216 column_types
[RB_SOURCELIST_MODEL_COLUMN_SOURCE
] = G_TYPE_OBJECT
;
217 column_types
[RB_SOURCELIST_MODEL_COLUMN_ATTRIBUTES
] = PANGO_TYPE_ATTR_LIST
;
218 column_types
[RB_SOURCELIST_MODEL_COLUMN_VISIBILITY
] = G_TYPE_BOOLEAN
;
219 store
= gtk_tree_store_newv (RB_SOURCELIST_MODEL_N_COLUMNS
,
222 model
= RB_SOURCELIST_MODEL (g_object_new (RB_TYPE_SOURCELIST_MODEL
,
223 "child-model", store
,
224 "virtual-root", NULL
,
226 g_object_unref (store
);
228 /* create marker rows used to separate source groups */
229 for (i
= 0; i
< RB_SOURCELIST_GROUP_LAST
; i
++) {
233 gtk_tree_store_append (store
, &iter
, NULL
);
234 gtk_tree_store_set (store
, &iter
,
235 RB_SOURCELIST_MODEL_COLUMN_NAME
, "",
236 RB_SOURCELIST_MODEL_COLUMN_SOURCE
, NULL
,
237 RB_SOURCELIST_MODEL_COLUMN_VISIBILITY
, FALSE
,
240 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (store
), &iter
);
241 model
->priv
->groups
[i
] = gtk_tree_row_reference_new (GTK_TREE_MODEL (store
), path
);
242 gtk_tree_path_free (path
);
245 /* ensure the group markers get updated as sources are added and removed */
246 g_signal_connect_object (G_OBJECT (store
), "row-inserted",
247 G_CALLBACK (rb_sourcelist_model_row_inserted_cb
),
249 g_signal_connect_object (G_OBJECT (store
), "row-deleted",
250 G_CALLBACK (rb_sourcelist_model_row_deleted_cb
),
253 gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model
),
254 (GtkTreeModelFilterVisibleFunc
) rb_sourcelist_model_is_row_visible
,
257 g_free (column_types
);
259 return GTK_TREE_MODEL (model
);
263 real_row_is_separator (RBSourceListModel
*model
, GtkTreeIter
*iter
)
267 GtkTreeModel
*real_model
;
268 GtkTreePath
*group_path
;
270 real_model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model
));
271 path
= gtk_tree_model_get_path (real_model
, iter
);
273 /* -1 here because the last group marker is always the last row in
274 * the model, and therefore can never be shown.
276 for (i
= 0; i
< RB_SOURCELIST_GROUP_LAST
-1; i
++) {
277 group_path
= rb_sourcelist_model_get_group_path (model
, i
);
279 if (gtk_tree_path_compare (path
, group_path
) == 0) {
280 /* okay, we know this is a group marker.
281 * if the next row is not a group marker,
282 * then we should show this row as a separator.
284 gboolean separator
= FALSE
;
286 gtk_tree_path_next (path
);
288 gtk_tree_path_free (group_path
);
289 group_path
= rb_sourcelist_model_get_group_path (model
, i
+1);
290 separator
= (gtk_tree_path_compare (path
, group_path
) != 0);
292 gtk_tree_path_free (group_path
);
293 gtk_tree_path_free (path
);
296 gtk_tree_path_free (group_path
);
299 gtk_tree_path_free (path
);
305 rb_sourcelist_model_is_row_visible (GtkTreeModel
*model
,
307 RBSourceListModel
*sourcelist
)
311 gtk_tree_model_get (GTK_TREE_MODEL (model
), iter
,
312 RB_SOURCELIST_MODEL_COLUMN_SOURCE
, &source
, -1);
314 if (source
!= NULL
) {
316 g_object_get (source
, "visibility", &visible
, NULL
);
318 g_object_unref (source
);
322 return real_row_is_separator (sourcelist
, iter
);
327 rb_sourcelist_model_row_is_separator (GtkTreeModel
*model
,
329 RBSourceListModel
*sourcelist
)
331 GtkTreeIter real_iter
;
334 /* rows with actual sources are never separators */
335 gtk_tree_model_get (GTK_TREE_MODEL (model
), iter
,
336 RB_SOURCELIST_MODEL_COLUMN_SOURCE
, &source
, -1);
337 if (source
!= NULL
) {
338 g_object_unref (source
);
342 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (sourcelist
),
345 return real_row_is_separator (sourcelist
, &real_iter
);
349 get_group_for_path (RBSourceListModel
*model
, GtkTreePath
*path
)
351 GtkTreePath
*group_path
;
352 gboolean found
= FALSE
;
355 for (i
=0; i
< RB_SOURCELIST_GROUP_LAST
; i
++) {
356 group_path
= rb_sourcelist_model_get_group_path (model
, i
);
357 g_assert (group_path
);
359 found
= (gtk_tree_path_compare (group_path
, path
) == 1);
360 gtk_tree_path_free (group_path
);
366 g_assert_not_reached ();
370 rb_sourcelist_model_drag_data_received (RbTreeDragDest
*drag_dest
,
372 GtkTreeViewDropPosition pos
,
373 GtkSelectionData
*selection_data
)
375 RBSourceListModel
*model
;
377 g_return_val_if_fail (RB_IS_SOURCELIST_MODEL (drag_dest
), FALSE
);
378 model
= RB_SOURCELIST_MODEL (drag_dest
);
380 if (selection_data
->type
== gdk_atom_intern ("text/uri-list", TRUE
)) {
382 RBSource
*target
= NULL
;
384 rb_debug ("text/uri-list drag data received");
386 if (dest
!= NULL
&& gtk_tree_model_get_iter (GTK_TREE_MODEL (model
), &iter
, dest
)) {
387 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
388 RB_SOURCELIST_MODEL_COLUMN_SOURCE
, &target
, -1);
391 if (target
!= NULL
) {
392 g_signal_emit (G_OBJECT (model
), rb_sourcelist_model_signals
[DROP_RECEIVED
],
393 0, target
, pos
, selection_data
);
394 g_object_unref (target
);
400 /* if artist, album or genre, only allow new playlists */
401 if (selection_data
->type
== gdk_atom_intern ("text/x-rhythmbox-album", TRUE
) ||
402 selection_data
->type
== gdk_atom_intern ("text/x-rhythmbox-artist", TRUE
) ||
403 selection_data
->type
== gdk_atom_intern ("text/x-rhythmbox-genre", TRUE
)) {
404 rb_debug ("text/x-rhythmbox-(album|artist|genre) drag data received");
405 g_signal_emit (G_OBJECT (model
), rb_sourcelist_model_signals
[DROP_RECEIVED
],
406 0, NULL
, pos
, selection_data
);
410 if (selection_data
->type
== gdk_atom_intern ("application/x-rhythmbox-source", TRUE
)) {
412 GtkTreePath
*real_dest
;
414 GtkTreeIter iter
, real_iter
;
415 GtkTreeIter real_dest_iter
;
416 GtkTreeModel
*real_model
;
418 RBSourceListGroup group
;
424 real_model
= gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (model
));
426 path_str
= g_strndup ((char *) selection_data
->data
, selection_data
->length
);
428 path
= gtk_tree_path_new_from_string (path_str
);
429 gtk_tree_model_get_iter (GTK_TREE_MODEL (model
),
431 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model
),
435 gtk_tree_model_filter_convert_path_to_child_path (GTK_TREE_MODEL_FILTER (model
),
438 gtk_tree_model_get (GTK_TREE_MODEL (real_model
), &real_iter
,
439 RB_SOURCELIST_MODEL_COLUMN_SOURCE
, &source
,
441 g_object_get (source
, "sourcelist-group", &group
, NULL
);
442 g_object_unref (source
);
444 /* restrict sources to within their group */
445 dest_group
= get_group_for_path (model
, real_dest
);
446 if (dest_group
< group
) {
447 gtk_tree_path_free (real_dest
);
448 real_dest
= rb_sourcelist_model_get_group_path (model
, group
-1);
449 pos
= GTK_TREE_VIEW_DROP_AFTER
;
450 } else if (dest_group
> group
) {
451 gtk_tree_path_free (real_dest
);
452 real_dest
= rb_sourcelist_model_get_group_path (model
, group
);
453 pos
= GTK_TREE_VIEW_DROP_BEFORE
;
456 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (real_model
),
457 &real_dest_iter
, real_dest
)) {
459 if (pos
== GTK_TREE_VIEW_DROP_AFTER
)
460 gtk_tree_store_move_after (GTK_TREE_STORE (real_model
),
461 &real_iter
, &real_dest_iter
);
463 gtk_tree_store_move_before (GTK_TREE_STORE (real_model
),
464 &real_iter
, &real_dest_iter
);
467 gtk_tree_store_move_before (GTK_TREE_STORE (real_model
),
471 gtk_tree_path_free (real_dest
);
472 gtk_tree_path_free (path
);
480 rb_sourcelist_model_row_drop_possible (RbTreeDragDest
*drag_dest
,
482 GtkTreeViewDropPosition pos
,
483 GtkSelectionData
*selection_data
)
485 RBSourceListModel
*model
;
487 rb_debug ("row drop possible");
488 g_return_val_if_fail (RB_IS_SOURCELIST_MODEL (drag_dest
), FALSE
);
489 model
= RB_SOURCELIST_MODEL (drag_dest
);
491 if (selection_data
->type
== gdk_atom_intern ("text/uri-list", TRUE
)
498 /* Call the superclass method */
499 return gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (GTK_TREE_STORE (model
)),
500 dest
, selection_data
);
504 path_is_droppable (RBSourceListModel
*model
,
512 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model
), &iter
, dest
)) {
515 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
516 RB_SOURCELIST_MODEL_COLUMN_SOURCE
, &source
, -1);
518 if (source
!= NULL
) {
519 res
= rb_source_can_paste (source
);
520 g_object_unref (source
);
528 path_is_reorderable (RBSourceListModel
*model
,
533 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (model
), &iter
, dest
)) {
535 RBSourceListGroup group
;
537 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
538 RB_SOURCELIST_MODEL_COLUMN_SOURCE
, &source
, -1);
543 g_object_get (source
, "sourcelist-group", &group
, NULL
);
544 g_object_unref (source
);
546 /* fixed and transient sources are not reorderable, everything else is */
547 return (group
!= RB_SOURCELIST_GROUP_FIXED
&&
548 group
!= RB_SOURCELIST_GROUP_TRANSIENT
);
555 rb_sourcelist_model_row_drop_position (RbTreeDragDest
*drag_dest
,
556 GtkTreePath
*dest_path
,
558 GtkTreeViewDropPosition
*pos
)
560 GtkTreeModel
*model
= GTK_TREE_MODEL (drag_dest
);
562 if (g_list_find (targets
, gdk_atom_intern ("application/x-rhythmbox-source", TRUE
)) && dest_path
) {
563 rb_debug ("application/x-rhythmbox-source type");
564 if (!path_is_reorderable (RB_SOURCELIST_MODEL (model
), dest_path
)) {
565 GtkTreePath
*test_path
= gtk_tree_path_copy (dest_path
);
566 gtk_tree_path_next (test_path
);
567 gboolean ret
= FALSE
;
568 if (path_is_reorderable (RB_SOURCELIST_MODEL (model
), test_path
)) {
569 *pos
= GTK_TREE_VIEW_DROP_AFTER
;
573 gtk_tree_path_free (test_path
);
577 if (*pos
== GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
)
578 *pos
= GTK_TREE_VIEW_DROP_BEFORE
;
579 else if (*pos
== GTK_TREE_VIEW_DROP_INTO_OR_AFTER
)
580 *pos
= GTK_TREE_VIEW_DROP_AFTER
;
585 if (g_list_find (targets
, gdk_atom_intern ("text/uri-list", TRUE
))) {
586 rb_debug ("text/uri-list type");
587 if (dest_path
&& !path_is_droppable (RB_SOURCELIST_MODEL (model
), dest_path
))
590 *pos
= GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
;
594 if ((g_list_find (targets
, gdk_atom_intern ("text/x-rhythmbox-artist", TRUE
))
595 || g_list_find (targets
, gdk_atom_intern ("text/x-rhythmbox-album", TRUE
))
596 || g_list_find (targets
, gdk_atom_intern ("text/x-rhythmbox-genre", TRUE
)))
597 && !g_list_find (targets
, gdk_atom_intern ("application/x-rhythmbox-source", TRUE
))) {
598 rb_debug ("genre, album, or artist type");
599 *pos
= GTK_TREE_VIEW_DROP_AFTER
;
607 rb_sourcelist_model_get_drag_target (RbTreeDragDest
*drag_dest
,
609 GdkDragContext
*context
,
611 GtkTargetList
*target_list
)
613 if (g_list_find (context
->targets
, gdk_atom_intern ("application/x-rhythmbox-source", TRUE
))) {
614 /* always accept rb source path if offered */
615 return gdk_atom_intern ("application/x-rhythmbox-source", TRUE
);
619 /* only accept text/uri-list drops into existing sources */
620 return gdk_atom_intern ("text/uri-list", FALSE
);
623 return gtk_drag_dest_find_target (widget
, context
,
628 rb_sourcelist_model_row_draggable (RbTreeDragSource
*drag_source
,
633 GtkTreeModel
*model
= GTK_TREE_MODEL (drag_source
);
635 /* we don't support multi selection */
636 g_return_val_if_fail (g_list_length (path_list
) == 1, FALSE
);
638 path
= gtk_tree_row_reference_get_path (path_list
->data
);
640 if (path
&& gtk_tree_model_get_iter (model
, &iter
, path
)) {
642 RBSourceListGroup group
;
644 gtk_tree_model_get (GTK_TREE_MODEL (model
), &iter
,
645 RB_SOURCELIST_MODEL_COLUMN_SOURCE
, &source
, -1);
647 g_object_get (source
, "sourcelist-group", &group
, NULL
);
648 g_object_unref (source
);
650 return (group
!= RB_SOURCELIST_GROUP_FIXED
&&
651 group
!= RB_SOURCELIST_GROUP_TRANSIENT
);
658 rb_sourcelist_model_drag_data_get (RbTreeDragSource
*drag_source
,
660 GtkSelectionData
*selection_data
)
666 path
= gtk_tree_row_reference_get_path (path_list
->data
);
670 if (!gtk_target_list_find (sourcelist_drag_target_list
,
671 selection_data
->target
,
676 if (target
== TARGET_SOURCE
) {
677 rb_debug ("getting drag data as rb source path");
678 path_str
= gtk_tree_path_to_string (path
);
679 gtk_selection_data_set (selection_data
,
680 selection_data
->target
,
681 8, (guchar
*) path_str
,
684 gtk_tree_path_free (path
);
686 } else if (target
== TARGET_URIS
) {
688 RhythmDBQueryModel
*query_model
;
691 gboolean first
= TRUE
;
693 rb_debug ("getting drag data as uri list");
694 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_source
), &iter
, path
))
697 data
= g_string_new ("");
698 gtk_tree_model_get (GTK_TREE_MODEL (drag_source
), &iter
,
699 RB_SOURCELIST_MODEL_COLUMN_SOURCE
, &source
, -1);
700 g_object_get (source
, "query-model", &query_model
, NULL
);
701 g_object_unref (source
);
703 if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (query_model
), &iter
)) {
704 g_object_unref (query_model
);
709 RhythmDBEntry
*entry
;
712 g_string_append(data
, "\r\n");
716 entry
= rhythmdb_query_model_iter_to_entry (query_model
, &iter
);
717 g_string_append (data
, rhythmdb_entry_get_string (entry
, RHYTHMDB_PROP_LOCATION
));
719 rhythmdb_entry_unref (entry
);
721 } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (query_model
), &iter
));
723 g_object_unref (query_model
);
725 gtk_selection_data_set (selection_data
,
726 selection_data
->target
,
727 8, (guchar
*) data
->str
,
730 g_string_free (data
, TRUE
);
734 /* unsupported target */
740 rb_sourcelist_model_drag_data_delete (RbTreeDragSource
*drag_source
,
747 rb_sourcelist_model_row_inserted_cb (GtkTreeModel
*model
,
750 RBSourceListModel
*sourcelist
)
752 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (sourcelist
));
756 rb_sourcelist_model_row_deleted_cb (GtkTreeModel
*model
,
758 RBSourceListModel
*sourcelist
)
760 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (sourcelist
));
764 rb_sourcelist_model_get_group_path (RBSourceListModel
*sourcelist
,
765 RBSourceListGroup group
)
767 return gtk_tree_row_reference_get_path (sourcelist
->priv
->groups
[group
]);