Updated Macedonian Translation <arangela@cvs.gnome.org>
[rhythmbox.git] / widgets / rb-property-view.c
blobd6fefa88230ea0212b9337513dee79affa1e3e73
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of widget to display RhythmDB properties
5 * Copyright (C) 2003 Colin Walters <walters@verbum.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (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
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <config.h>
25 #include <string.h>
26 #include <stdlib.h>
28 #include <glib/gi18n.h>
29 #include <gdk/gdkkeysyms.h>
30 #include <gtk/gtk.h>
31 #include <libgnomevfs/gnome-vfs-utils.h>
33 #include "rb-property-view.h"
34 #include "rb-dialog.h"
35 #include "rb-debug.h"
36 #include "rhythmdb.h"
37 #include "rhythmdb-property-model.h"
38 #include "rb-stock-icons.h"
39 #include "eel-gconf-extensions.h"
40 #include "rb-util.h"
42 static void rb_property_view_class_init (RBPropertyViewClass *klass);
43 static void rb_property_view_init (RBPropertyView *view);
44 static void rb_property_view_finalize (GObject *object);
45 static void rb_property_view_set_property (GObject *object,
46 guint prop_id,
47 const GValue *value,
48 GParamSpec *pspec);
49 static void rb_property_view_get_property (GObject *object,
50 guint prop_id,
51 GValue *value,
52 GParamSpec *pspec);
53 static GObject * rb_property_view_constructor (GType type, guint n_construct_properties,
54 GObjectConstructParam *construct_properties);
55 static void rb_property_view_row_activated_cb (GtkTreeView *treeview,
56 GtkTreePath *path,
57 GtkTreeViewColumn *column,
58 RBPropertyView *view);
59 static void rb_property_view_selection_changed_cb (GtkTreeSelection *selection,
60 RBPropertyView *view);
61 static void rb_property_view_pre_row_deleted_cb (RhythmDBPropertyModel *model,
62 RBPropertyView *view);
63 static void rb_property_view_post_row_deleted_cb (GtkTreeModel *model,
64 GtkTreePath *path,
65 RBPropertyView *view);
66 static gboolean rb_property_view_popup_menu_cb (GtkTreeView *treeview,
67 RBPropertyView *view);
68 static gboolean rb_property_view_button_press_cb (GtkTreeView *tree,
69 GdkEventButton *event,
70 RBPropertyView *view);
72 struct RBPropertyViewPrivate
74 RhythmDB *db;
76 RhythmDBPropType propid;
78 RhythmDBPropertyModel *prop_model;
80 char *title;
82 GtkWidget *treeview;
83 GtkTreeSelection *selection;
85 gboolean draggable;
86 gboolean handling_row_deletion;
89 #define RB_PROPERTY_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PROPERTY_VIEW, RBPropertyViewPrivate))
91 enum
93 PROPERTY_SELECTED,
94 PROPERTIES_SELECTED,
95 PROPERTY_ACTIVATED,
96 SELECTION_RESET,
97 SHOW_POPUP,
98 LAST_SIGNAL
101 enum
103 PROP_0,
104 PROP_DB,
105 PROP_PROP,
106 PROP_TITLE,
107 PROP_MODEL,
108 PROP_DRAGGABLE,
111 static guint rb_property_view_signals[LAST_SIGNAL] = { 0 };
113 enum {
114 TARGET_ALBUMS,
115 TARGET_GENRE,
116 TARGET_ARTISTS,
117 TARGET_URIS,
120 static const GtkTargetEntry targets_album [] = {
121 { "text/x-rhythmbox-album", 0, TARGET_ALBUMS },
122 { "text/uri-list", 0, TARGET_URIS },
124 static const GtkTargetEntry targets_genre [] = {
125 { "text/x-rhythmbox-genre", 0, TARGET_GENRE },
126 { "text/uri-list", 0, TARGET_URIS },
128 static const GtkTargetEntry targets_artist [] = {
129 { "text/x-rhythmbox-artist", 0, TARGET_ARTISTS },
130 { "text/uri-list", 0, TARGET_URIS },
133 G_DEFINE_TYPE (RBPropertyView, rb_property_view, GTK_TYPE_SCROLLED_WINDOW)
136 static void
137 rb_property_view_class_init (RBPropertyViewClass *klass)
139 GObjectClass *object_class = G_OBJECT_CLASS (klass);
141 object_class->finalize = rb_property_view_finalize;
142 object_class->constructor = rb_property_view_constructor;
144 object_class->set_property = rb_property_view_set_property;
145 object_class->get_property = rb_property_view_get_property;
147 g_object_class_install_property (object_class,
148 PROP_DB,
149 g_param_spec_object ("db",
150 "RhythmDB",
151 "RhythmDB database",
152 RHYTHMDB_TYPE,
153 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
155 g_object_class_install_property (object_class,
156 PROP_PROP,
157 g_param_spec_enum ("prop",
158 "PropertyId",
159 "RhythmDBPropType",
160 RHYTHMDB_TYPE_PROP_TYPE,
161 RHYTHMDB_PROP_TYPE,
162 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
164 g_object_class_install_property (object_class,
165 PROP_TITLE,
166 g_param_spec_string ("title",
167 "title",
168 "title",
170 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
171 g_object_class_install_property (object_class,
172 PROP_MODEL,
173 g_param_spec_object ("property-model",
174 "property model",
175 "RhythmDBPropertyModel",
176 RHYTHMDB_TYPE_PROPERTY_MODEL,
177 G_PARAM_READWRITE));
178 g_object_class_install_property (object_class,
179 PROP_DRAGGABLE,
180 g_param_spec_boolean ("draggable",
181 "draggable",
182 "is a drag source",
183 TRUE,
184 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
186 rb_property_view_signals[PROPERTY_ACTIVATED] =
187 g_signal_new ("property-activated",
188 G_OBJECT_CLASS_TYPE (object_class),
189 G_SIGNAL_RUN_LAST,
190 G_STRUCT_OFFSET (RBPropertyViewClass, property_activated),
191 NULL, NULL,
192 g_cclosure_marshal_VOID__STRING,
193 G_TYPE_NONE,
195 G_TYPE_STRING);
197 rb_property_view_signals[PROPERTY_SELECTED] =
198 g_signal_new ("property-selected",
199 G_OBJECT_CLASS_TYPE (object_class),
200 G_SIGNAL_RUN_LAST,
201 G_STRUCT_OFFSET (RBPropertyViewClass, property_selected),
202 NULL, NULL,
203 g_cclosure_marshal_VOID__STRING,
204 G_TYPE_NONE,
206 G_TYPE_STRING);
208 rb_property_view_signals[PROPERTIES_SELECTED] =
209 g_signal_new ("properties-selected",
210 G_OBJECT_CLASS_TYPE (object_class),
211 G_SIGNAL_RUN_LAST,
212 G_STRUCT_OFFSET (RBPropertyViewClass, properties_selected),
213 NULL, NULL,
214 g_cclosure_marshal_VOID__POINTER,
215 G_TYPE_NONE,
217 G_TYPE_POINTER);
219 rb_property_view_signals[SELECTION_RESET] =
220 g_signal_new ("property-selection-reset",
221 G_OBJECT_CLASS_TYPE (object_class),
222 G_SIGNAL_RUN_LAST,
223 G_STRUCT_OFFSET (RBPropertyViewClass, selection_reset),
224 NULL, NULL,
225 g_cclosure_marshal_VOID__VOID,
226 G_TYPE_NONE,
228 rb_property_view_signals[SHOW_POPUP] =
229 g_signal_new ("show_popup",
230 G_OBJECT_CLASS_TYPE (object_class),
231 G_SIGNAL_RUN_LAST,
232 G_STRUCT_OFFSET (RBPropertyViewClass, show_popup),
233 NULL, NULL,
234 g_cclosure_marshal_VOID__VOID,
235 G_TYPE_NONE,
239 g_type_class_add_private (klass, sizeof (RBPropertyViewPrivate));
242 static void
243 rb_property_view_init (RBPropertyView *view)
245 view->priv = RB_PROPERTY_VIEW_GET_PRIVATE (view);
248 static void
249 rb_property_view_finalize (GObject *object)
251 RBPropertyView *view;
253 g_return_if_fail (object != NULL);
254 g_return_if_fail (RB_IS_PROPERTY_VIEW (object));
256 view = RB_PROPERTY_VIEW (object);
258 g_return_if_fail (view->priv != NULL);
260 g_free (view->priv->title);
262 G_OBJECT_CLASS (rb_property_view_parent_class)->finalize (object);
266 static void
267 rb_property_view_set_property (GObject *object,
268 guint prop_id,
269 const GValue *value,
270 GParamSpec *pspec)
272 RBPropertyView *view = RB_PROPERTY_VIEW (object);
274 switch (prop_id)
276 case PROP_DB:
277 view->priv->db = g_value_get_object (value);
278 break;
279 case PROP_PROP:
280 view->priv->propid = g_value_get_enum (value);
281 break;
282 case PROP_TITLE:
283 view->priv->title = g_value_dup_string (value);
284 break;
285 case PROP_MODEL:
287 GtkTreeIter iter;
289 if (view->priv->prop_model) {
290 g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->prop_model),
291 G_CALLBACK (rb_property_view_pre_row_deleted_cb),
292 view);
293 g_signal_handlers_disconnect_by_func (G_OBJECT (view->priv->prop_model),
294 G_CALLBACK (rb_property_view_post_row_deleted_cb),
295 view);
296 g_object_unref (G_OBJECT (view->priv->prop_model));
299 view->priv->prop_model = g_value_get_object (value);
301 if (!view->priv->prop_model)
302 break;
304 gtk_tree_view_set_model (GTK_TREE_VIEW (view->priv->treeview),
305 GTK_TREE_MODEL (view->priv->prop_model));
307 g_object_ref (G_OBJECT (view->priv->prop_model));
308 g_signal_connect_object (G_OBJECT (view->priv->prop_model),
309 "pre-row-deletion",
310 G_CALLBACK (rb_property_view_pre_row_deleted_cb),
311 view,
313 g_signal_connect_object (G_OBJECT (view->priv->prop_model),
314 "row_deleted",
315 G_CALLBACK (rb_property_view_post_row_deleted_cb),
316 view,
317 G_CONNECT_AFTER);
319 g_signal_handlers_block_by_func (G_OBJECT (view->priv->selection),
320 G_CALLBACK (rb_property_view_selection_changed_cb),
321 view);
323 gtk_tree_selection_unselect_all (view->priv->selection);
324 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (view->priv->prop_model), &iter))
325 gtk_tree_selection_select_iter (view->priv->selection, &iter);
326 g_signal_handlers_unblock_by_func (G_OBJECT (view->priv->selection),
327 G_CALLBACK (rb_property_view_selection_changed_cb),
328 view);
331 break;
332 case PROP_DRAGGABLE:
333 view->priv->draggable = g_value_get_boolean (value);
334 break;
335 default:
336 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
337 break;
341 static void
342 rb_property_view_get_property (GObject *object,
343 guint prop_id,
344 GValue *value,
345 GParamSpec *pspec)
347 RBPropertyView *view = RB_PROPERTY_VIEW (object);
349 switch (prop_id)
351 case PROP_DB:
352 g_value_set_object (value, view->priv->db);
353 break;
354 case PROP_PROP:
355 g_value_set_enum (value, view->priv->propid);
356 break;
357 case PROP_TITLE:
358 g_value_set_string (value, view->priv->title);
359 break;
360 case PROP_MODEL:
361 g_value_set_object (value, view->priv->prop_model);
362 break;
363 case PROP_DRAGGABLE:
364 g_value_set_boolean (value, view->priv->draggable);
365 break;
366 default:
367 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
368 break;
372 RBPropertyView *
373 rb_property_view_new (RhythmDB *db,
374 guint propid,
375 const char *title)
377 RBPropertyView *view;
379 view = RB_PROPERTY_VIEW (g_object_new (RB_TYPE_PROPERTY_VIEW,
380 "hadjustment", NULL,
381 "vadjustment", NULL,
382 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
383 "vscrollbar_policy", GTK_POLICY_ALWAYS,
384 "shadow_type", GTK_SHADOW_IN,
385 "db", db,
386 "prop", propid,
387 "title", title,
388 "draggable", TRUE,
389 NULL));
391 g_return_val_if_fail (view->priv != NULL, NULL);
393 return view;
396 void
397 rb_property_view_set_selection_mode (RBPropertyView *view,
398 GtkSelectionMode mode)
400 g_return_if_fail (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_MULTIPLE);
401 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview)),
402 mode);
405 void
406 rb_property_view_reset (RBPropertyView *view)
408 RhythmDBPropertyModel *model;
410 model = rhythmdb_property_model_new (view->priv->db, view->priv->propid);
412 g_object_set (G_OBJECT (view), "property-model", model, NULL);
413 g_object_unref (G_OBJECT (model));
416 RhythmDBPropertyModel *
417 rb_property_view_get_model (RBPropertyView *view)
419 RhythmDBPropertyModel *model;
421 g_object_get (G_OBJECT (view), "property-model", &model, NULL);
422 return model;
425 void
426 rb_property_view_set_model (RBPropertyView *view, RhythmDBPropertyModel *model)
428 g_object_set (G_OBJECT (view), "property-model", model, NULL);
431 static void
432 rb_property_view_pre_row_deleted_cb (RhythmDBPropertyModel *model,
433 RBPropertyView *view)
435 view->priv->handling_row_deletion = TRUE;
436 rb_debug ("pre row deleted");
439 static void
440 rb_property_view_post_row_deleted_cb (GtkTreeModel *model,
441 GtkTreePath *path,
442 RBPropertyView *view)
444 view->priv->handling_row_deletion = FALSE;
445 rb_debug ("post row deleted");
446 if (gtk_tree_selection_count_selected_rows (view->priv->selection) == 0) {
447 GtkTreeIter first_iter;
448 rb_debug ("no rows selected, signalling reset");
449 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (view->priv->prop_model), &first_iter)) {
450 g_signal_handlers_block_by_func (G_OBJECT (view->priv->selection),
451 G_CALLBACK (rb_property_view_selection_changed_cb),
452 view);
453 gtk_tree_selection_select_iter (view->priv->selection, &first_iter);
454 g_signal_emit (G_OBJECT (view), rb_property_view_signals[SELECTION_RESET], 0);
455 g_signal_handlers_unblock_by_func (G_OBJECT (view->priv->selection),
456 G_CALLBACK (rb_property_view_selection_changed_cb),
457 view);
462 guint
463 rb_property_view_get_num_properties (RBPropertyView *view)
465 return gtk_tree_model_iter_n_children (GTK_TREE_MODEL (view->priv->prop_model),
466 NULL)-1;
469 static void
470 rb_property_view_cell_data_func (GtkTreeViewColumn *column,
471 GtkCellRenderer *renderer,
472 GtkTreeModel *tree_model,
473 GtkTreeIter *iter,
474 RBPropertyView *view)
476 char *title;
477 char *str;
478 guint number;
479 gboolean is_all;
481 gtk_tree_model_get (GTK_TREE_MODEL (tree_model), iter,
482 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &title,
483 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all,
484 RHYTHMDB_PROPERTY_MODEL_COLUMN_NUMBER, &number, -1);
486 if (is_all) {
487 int nodes;
488 const char *fmt;
490 nodes = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree_model), NULL);
491 /* Subtract one for the All node */
492 nodes--;
494 switch (view->priv->propid) {
495 case RHYTHMDB_PROP_ARTIST:
496 fmt = ngettext ("All %d artist (%d)", "All %d artists (%d)", nodes);
497 break;
498 case RHYTHMDB_PROP_ALBUM:
499 fmt = ngettext ("All %d album (%d)", "All %d albums (%d)", nodes);
500 break;
501 case RHYTHMDB_PROP_GENRE:
502 fmt = ngettext ("All %d genre (%d)", "All %d genres (%d)", nodes);
503 break;
504 default:
505 fmt = _("All %d (%d)");
506 break;
509 str = g_strdup_printf (fmt, nodes, number);
510 } else {
511 str = g_strdup_printf (_("%s (%d)"), title, number);
514 g_object_set (G_OBJECT (renderer), "text", str,
515 "weight", G_UNLIKELY (is_all) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
516 NULL);
517 g_free (str);
518 g_free (title);
521 static GObject *
522 rb_property_view_constructor (GType type,
523 guint n_construct_properties,
524 GObjectConstructParam *construct_properties)
526 GtkTreeViewColumn *column;
527 GtkCellRenderer *renderer;
529 RBPropertyView *view;
530 RBPropertyViewClass *klass;
532 klass = RB_PROPERTY_VIEW_CLASS (g_type_class_peek (RB_TYPE_PROPERTY_VIEW));
534 view = RB_PROPERTY_VIEW (G_OBJECT_CLASS (rb_property_view_parent_class)->
535 constructor (type, n_construct_properties, construct_properties));
537 view->priv->prop_model = rhythmdb_property_model_new (view->priv->db, view->priv->propid);
538 view->priv->treeview = GTK_WIDGET (gtk_tree_view_new_with_model (GTK_TREE_MODEL (view->priv->prop_model)));
540 if (view->priv->draggable)
541 rhythmdb_property_model_enable_drag (view->priv->prop_model,
542 GTK_TREE_VIEW (view->priv->treeview));
544 g_signal_connect_object (G_OBJECT (view->priv->treeview),
545 "row_activated",
546 G_CALLBACK (rb_property_view_row_activated_cb),
547 view,
550 view->priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
551 g_signal_connect_object (G_OBJECT (view->priv->selection),
552 "changed",
553 G_CALLBACK (rb_property_view_selection_changed_cb),
554 view,
556 g_signal_connect_object (G_OBJECT (view->priv->treeview),
557 "popup_menu",
558 G_CALLBACK (rb_property_view_popup_menu_cb),
559 view,
562 g_signal_connect_object (G_OBJECT (view->priv->treeview),
563 "button_press_event",
564 G_CALLBACK (rb_property_view_button_press_cb),
565 view,
569 gtk_container_add (GTK_CONTAINER (view), view->priv->treeview);
571 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view->priv->treeview), TRUE);
572 gtk_tree_selection_set_mode (view->priv->selection, GTK_SELECTION_SINGLE);
574 column = gtk_tree_view_column_new ();
575 renderer = gtk_cell_renderer_text_new ();
576 gtk_tree_view_column_pack_start (column, renderer, TRUE);
577 gtk_tree_view_column_set_cell_data_func (column, renderer,
578 (GtkTreeCellDataFunc) rb_property_view_cell_data_func,
579 view, NULL);
580 gtk_tree_view_column_set_title (column, view->priv->title);
581 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
582 gtk_tree_view_append_column (GTK_TREE_VIEW (view->priv->treeview),
583 column);
585 return G_OBJECT (view);
588 static void
589 rb_property_view_row_activated_cb (GtkTreeView *treeview,
590 GtkTreePath *path,
591 GtkTreeViewColumn *column,
592 RBPropertyView *view)
594 GtkTreeIter iter;
595 const char *val;
596 gboolean is_all;
598 rb_debug ("row activated");
599 g_return_if_fail (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->priv->prop_model),
600 &iter, path));
602 gtk_tree_model_get (GTK_TREE_MODEL (view->priv->prop_model), &iter,
603 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &val,
604 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all, -1);
606 rb_debug ("emitting property activated");
607 g_signal_emit (G_OBJECT (view), rb_property_view_signals[PROPERTY_ACTIVATED], 0,
608 is_all ? NULL : val);
611 void
612 rb_property_view_set_selection (RBPropertyView *view, const GList *vals)
614 view->priv->handling_row_deletion = TRUE;
616 gtk_tree_selection_unselect_all (view->priv->selection);
618 for (; vals ; vals = vals->next) {
619 GtkTreeIter iter;
621 if (rhythmdb_property_model_iter_from_string (view->priv->prop_model, vals->data, &iter)) {
622 GtkTreePath *path;
624 gtk_tree_selection_select_iter (view->priv->selection, &iter);
625 path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->priv->prop_model), &iter);
626 if (path != NULL) {
627 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view->priv->treeview),
628 path, NULL, TRUE,
629 0.5, 0.0);
630 gtk_tree_path_free (path);
636 view->priv->handling_row_deletion = FALSE;
637 rb_property_view_selection_changed_cb (view->priv->selection, view);
640 static void
641 rb_property_view_selection_changed_cb (GtkTreeSelection *selection,
642 RBPropertyView *view)
644 char *selected_prop = NULL;
645 gboolean is_all = TRUE;
646 GtkTreeModel *model;
647 GtkTreeIter iter;
649 if (view->priv->handling_row_deletion)
650 return;
652 rb_debug ("selection changed");
653 if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_MULTIPLE) {
654 GList *selected_rows, *tem;
655 GList *selected_properties = NULL;
657 selected_rows = gtk_tree_selection_get_selected_rows (view->priv->selection, &model);
658 for (tem = selected_rows; tem; tem = tem->next) {
659 g_assert (gtk_tree_model_get_iter (model, &iter, tem->data));
660 gtk_tree_model_get (model, &iter,
661 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &selected_prop,
662 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all, -1);
663 if (is_all) {
664 g_list_free (selected_properties);
665 selected_properties = NULL;
666 break;
668 selected_properties = g_list_prepend (selected_properties,
669 g_strdup (selected_prop));
672 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
673 g_list_free (selected_rows);
675 if (is_all) {
676 g_signal_handlers_block_by_func (G_OBJECT (view->priv->selection),
677 G_CALLBACK (rb_property_view_selection_changed_cb),
678 view);
679 gtk_tree_selection_unselect_all (selection);
680 if (gtk_tree_model_get_iter_first (model, &iter))
681 gtk_tree_selection_select_iter (selection, &iter);
682 g_signal_handlers_unblock_by_func (G_OBJECT (view->priv->selection),
683 G_CALLBACK (rb_property_view_selection_changed_cb),
684 view);
686 g_signal_emit (G_OBJECT (view), rb_property_view_signals[PROPERTIES_SELECTED], 0,
687 selected_properties);
688 rb_list_deep_free (selected_properties);
689 } else {
690 if (gtk_tree_selection_get_selected (view->priv->selection, &model, &iter)) {
691 gtk_tree_model_get (model, &iter,
692 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &selected_prop,
693 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all, -1);
694 g_signal_emit (G_OBJECT (view), rb_property_view_signals[PROPERTY_SELECTED], 0,
695 is_all ? NULL : selected_prop);
699 g_free (selected_prop);
702 static gboolean
703 rb_property_view_popup_menu_cb (GtkTreeView *treeview,
704 RBPropertyView *view)
706 g_signal_emit (G_OBJECT (view), rb_property_view_signals[SHOW_POPUP], 0);
707 return TRUE;
710 void
711 rb_property_view_append_column_custom (RBPropertyView *view,
712 GtkTreeViewColumn *column)
714 gtk_tree_view_append_column (GTK_TREE_VIEW (view->priv->treeview), column);
717 static gboolean
718 rb_property_view_button_press_cb (GtkTreeView *tree,
719 GdkEventButton *event,
720 RBPropertyView *view)
723 if (event->button == 3) {
724 GtkTreeSelection *selection;
725 GtkTreePath *path;
727 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
729 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view->priv->treeview), event->x, event->y, &path, NULL, NULL, NULL);
730 if (path == NULL) {
731 gtk_tree_selection_unselect_all (selection);
732 } else {
733 GtkTreeModel *model;
734 GtkTreeIter iter;
735 const char *val;
736 GList *lst = NULL;
738 model = gtk_tree_view_get_model (GTK_TREE_VIEW (view->priv->treeview));
739 if (gtk_tree_model_get_iter (model, &iter, path)) {
740 gtk_tree_model_get (model, &iter, 0, &val, -1);
741 lst = g_list_prepend (lst, (gpointer) val);
742 rb_property_view_set_selection (view, lst);
745 g_signal_emit (G_OBJECT (view), rb_property_view_signals[SHOW_POPUP], 0);
746 return TRUE;
749 return FALSE;
752 void
753 rb_property_view_set_search_func (RBPropertyView *view,
754 GtkTreeViewSearchEqualFunc func,
755 gpointer func_data,
756 GtkDestroyNotify notify)
758 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view->priv->treeview),
759 func, func_data,
760 notify);