Updated Finnish translation
[rhythmbox.git] / widgets / rb-property-view.c
blob49c6e50920a221092eee8ca9e22d1ebc5c5f2693
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)
135 static void
136 rb_property_view_class_init (RBPropertyViewClass *klass)
138 GObjectClass *object_class = G_OBJECT_CLASS (klass);
140 object_class->finalize = rb_property_view_finalize;
141 object_class->constructor = rb_property_view_constructor;
143 object_class->set_property = rb_property_view_set_property;
144 object_class->get_property = rb_property_view_get_property;
146 g_object_class_install_property (object_class,
147 PROP_DB,
148 g_param_spec_object ("db",
149 "RhythmDB",
150 "RhythmDB database",
151 RHYTHMDB_TYPE,
152 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
154 g_object_class_install_property (object_class,
155 PROP_PROP,
156 g_param_spec_enum ("prop",
157 "PropertyId",
158 "RhythmDBPropType",
159 RHYTHMDB_TYPE_PROP_TYPE,
160 RHYTHMDB_PROP_TYPE,
161 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
163 g_object_class_install_property (object_class,
164 PROP_TITLE,
165 g_param_spec_string ("title",
166 "title",
167 "title",
169 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
170 g_object_class_install_property (object_class,
171 PROP_MODEL,
172 g_param_spec_object ("property-model",
173 "property model",
174 "RhythmDBPropertyModel",
175 RHYTHMDB_TYPE_PROPERTY_MODEL,
176 G_PARAM_READWRITE));
177 g_object_class_install_property (object_class,
178 PROP_DRAGGABLE,
179 g_param_spec_boolean ("draggable",
180 "draggable",
181 "is a drag source",
182 TRUE,
183 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
185 rb_property_view_signals[PROPERTY_ACTIVATED] =
186 g_signal_new ("property-activated",
187 G_OBJECT_CLASS_TYPE (object_class),
188 G_SIGNAL_RUN_LAST,
189 G_STRUCT_OFFSET (RBPropertyViewClass, property_activated),
190 NULL, NULL,
191 g_cclosure_marshal_VOID__STRING,
192 G_TYPE_NONE,
194 G_TYPE_STRING);
196 rb_property_view_signals[PROPERTY_SELECTED] =
197 g_signal_new ("property-selected",
198 G_OBJECT_CLASS_TYPE (object_class),
199 G_SIGNAL_RUN_LAST,
200 G_STRUCT_OFFSET (RBPropertyViewClass, property_selected),
201 NULL, NULL,
202 g_cclosure_marshal_VOID__STRING,
203 G_TYPE_NONE,
205 G_TYPE_STRING);
207 rb_property_view_signals[PROPERTIES_SELECTED] =
208 g_signal_new ("properties-selected",
209 G_OBJECT_CLASS_TYPE (object_class),
210 G_SIGNAL_RUN_LAST,
211 G_STRUCT_OFFSET (RBPropertyViewClass, properties_selected),
212 NULL, NULL,
213 g_cclosure_marshal_VOID__POINTER,
214 G_TYPE_NONE,
216 G_TYPE_POINTER);
218 rb_property_view_signals[SELECTION_RESET] =
219 g_signal_new ("property-selection-reset",
220 G_OBJECT_CLASS_TYPE (object_class),
221 G_SIGNAL_RUN_LAST,
222 G_STRUCT_OFFSET (RBPropertyViewClass, selection_reset),
223 NULL, NULL,
224 g_cclosure_marshal_VOID__VOID,
225 G_TYPE_NONE,
227 rb_property_view_signals[SHOW_POPUP] =
228 g_signal_new ("show_popup",
229 G_OBJECT_CLASS_TYPE (object_class),
230 G_SIGNAL_RUN_LAST,
231 G_STRUCT_OFFSET (RBPropertyViewClass, show_popup),
232 NULL, NULL,
233 g_cclosure_marshal_VOID__VOID,
234 G_TYPE_NONE,
237 g_type_class_add_private (klass, sizeof (RBPropertyViewPrivate));
240 static void
241 rb_property_view_init (RBPropertyView *view)
243 view->priv = RB_PROPERTY_VIEW_GET_PRIVATE (view);
246 static void
247 rb_property_view_set_model_internal (RBPropertyView *view,
248 RhythmDBPropertyModel *model)
250 if (view->priv->prop_model != NULL) {
251 g_signal_handlers_disconnect_by_func (view->priv->prop_model,
252 G_CALLBACK (rb_property_view_pre_row_deleted_cb),
253 view);
254 g_signal_handlers_disconnect_by_func (view->priv->prop_model,
255 G_CALLBACK (rb_property_view_post_row_deleted_cb),
256 view);
257 g_object_unref (view->priv->prop_model);
260 view->priv->prop_model = model;
262 if (view->priv->prop_model != NULL) {
263 GtkTreeIter iter;
265 g_object_ref (view->priv->prop_model);
267 gtk_tree_view_set_model (GTK_TREE_VIEW (view->priv->treeview),
268 GTK_TREE_MODEL (view->priv->prop_model));
270 g_signal_connect_object (view->priv->prop_model,
271 "pre-row-deletion",
272 G_CALLBACK (rb_property_view_pre_row_deleted_cb),
273 view,
275 g_signal_connect_object (view->priv->prop_model,
276 "row_deleted",
277 G_CALLBACK (rb_property_view_post_row_deleted_cb),
278 view,
279 G_CONNECT_AFTER);
281 g_signal_handlers_block_by_func (view->priv->selection,
282 G_CALLBACK (rb_property_view_selection_changed_cb),
283 view);
285 gtk_tree_selection_unselect_all (view->priv->selection);
287 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (view->priv->prop_model), &iter))
288 gtk_tree_selection_select_iter (view->priv->selection, &iter);
290 g_signal_handlers_unblock_by_func (view->priv->selection,
291 G_CALLBACK (rb_property_view_selection_changed_cb),
292 view);
296 static void
297 rb_property_view_finalize (GObject *object)
299 RBPropertyView *view;
301 g_return_if_fail (object != NULL);
302 g_return_if_fail (RB_IS_PROPERTY_VIEW (object));
304 view = RB_PROPERTY_VIEW (object);
306 g_return_if_fail (view->priv != NULL);
308 rb_property_view_set_model_internal (view, NULL);
310 g_free (view->priv->title);
312 G_OBJECT_CLASS (rb_property_view_parent_class)->finalize (object);
315 static void
316 rb_property_view_set_property (GObject *object,
317 guint prop_id,
318 const GValue *value,
319 GParamSpec *pspec)
321 RBPropertyView *view = RB_PROPERTY_VIEW (object);
323 switch (prop_id) {
324 case PROP_DB:
325 view->priv->db = g_value_get_object (value);
326 break;
327 case PROP_PROP:
328 view->priv->propid = g_value_get_enum (value);
329 break;
330 case PROP_TITLE:
331 view->priv->title = g_value_dup_string (value);
332 break;
333 case PROP_MODEL:
334 rb_property_view_set_model_internal (view, g_value_get_object (value));
335 break;
336 case PROP_DRAGGABLE:
337 view->priv->draggable = g_value_get_boolean (value);
338 break;
339 default:
340 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
341 break;
345 static void
346 rb_property_view_get_property (GObject *object,
347 guint prop_id,
348 GValue *value,
349 GParamSpec *pspec)
351 RBPropertyView *view = RB_PROPERTY_VIEW (object);
353 switch (prop_id) {
354 case PROP_DB:
355 g_value_set_object (value, view->priv->db);
356 break;
357 case PROP_PROP:
358 g_value_set_enum (value, view->priv->propid);
359 break;
360 case PROP_TITLE:
361 g_value_set_string (value, view->priv->title);
362 break;
363 case PROP_MODEL:
364 g_value_set_object (value, view->priv->prop_model);
365 break;
366 case PROP_DRAGGABLE:
367 g_value_set_boolean (value, view->priv->draggable);
368 break;
369 default:
370 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
371 break;
375 RBPropertyView *
376 rb_property_view_new (RhythmDB *db,
377 guint propid,
378 const char *title)
380 RBPropertyView *view;
382 view = RB_PROPERTY_VIEW (g_object_new (RB_TYPE_PROPERTY_VIEW,
383 "hadjustment", NULL,
384 "vadjustment", NULL,
385 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
386 "vscrollbar_policy", GTK_POLICY_ALWAYS,
387 "shadow_type", GTK_SHADOW_IN,
388 "db", db,
389 "prop", propid,
390 "title", title,
391 "draggable", TRUE,
392 NULL));
394 g_return_val_if_fail (view->priv != NULL, NULL);
396 return view;
399 void
400 rb_property_view_set_selection_mode (RBPropertyView *view,
401 GtkSelectionMode mode)
403 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
404 g_return_if_fail (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_MULTIPLE);
406 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview)),
407 mode);
410 void
411 rb_property_view_reset (RBPropertyView *view)
413 RhythmDBPropertyModel *model;
415 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
417 model = rhythmdb_property_model_new (view->priv->db, view->priv->propid);
419 rb_property_view_set_model_internal (view, model);
420 g_object_unref (model);
423 RhythmDBPropertyModel *
424 rb_property_view_get_model (RBPropertyView *view)
426 RhythmDBPropertyModel *model;
428 g_return_val_if_fail (RB_IS_PROPERTY_VIEW (view), NULL);
430 model = view->priv->prop_model;
432 return model;
435 void
436 rb_property_view_set_model (RBPropertyView *view,
437 RhythmDBPropertyModel *model)
439 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
441 rb_property_view_set_model_internal (view, model);
444 static void
445 rb_property_view_pre_row_deleted_cb (RhythmDBPropertyModel *model,
446 RBPropertyView *view)
448 view->priv->handling_row_deletion = TRUE;
449 rb_debug ("pre row deleted");
452 static void
453 rb_property_view_post_row_deleted_cb (GtkTreeModel *model,
454 GtkTreePath *path,
455 RBPropertyView *view)
457 view->priv->handling_row_deletion = FALSE;
458 rb_debug ("post row deleted");
459 if (gtk_tree_selection_count_selected_rows (view->priv->selection) == 0) {
460 GtkTreeIter first_iter;
461 rb_debug ("no rows selected, signalling reset");
462 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (view->priv->prop_model), &first_iter)) {
463 g_signal_handlers_block_by_func (G_OBJECT (view->priv->selection),
464 G_CALLBACK (rb_property_view_selection_changed_cb),
465 view);
466 gtk_tree_selection_select_iter (view->priv->selection, &first_iter);
467 g_signal_emit (G_OBJECT (view), rb_property_view_signals[SELECTION_RESET], 0);
468 g_signal_handlers_unblock_by_func (G_OBJECT (view->priv->selection),
469 G_CALLBACK (rb_property_view_selection_changed_cb),
470 view);
475 guint
476 rb_property_view_get_num_properties (RBPropertyView *view)
478 g_return_val_if_fail (RB_IS_PROPERTY_VIEW (view), 0);
480 return gtk_tree_model_iter_n_children (GTK_TREE_MODEL (view->priv->prop_model),
481 NULL)-1;
484 static void
485 rb_property_view_cell_data_func (GtkTreeViewColumn *column,
486 GtkCellRenderer *renderer,
487 GtkTreeModel *tree_model,
488 GtkTreeIter *iter,
489 RBPropertyView *view)
491 char *title;
492 char *str;
493 guint number;
494 gboolean is_all;
496 gtk_tree_model_get (GTK_TREE_MODEL (tree_model), iter,
497 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &title,
498 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all,
499 RHYTHMDB_PROPERTY_MODEL_COLUMN_NUMBER, &number, -1);
501 if (is_all) {
502 int nodes;
503 const char *fmt;
505 nodes = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree_model), NULL);
506 /* Subtract one for the All node */
507 nodes--;
509 switch (view->priv->propid) {
510 case RHYTHMDB_PROP_ARTIST:
511 fmt = ngettext ("All %d artist (%d)", "All %d artists (%d)", nodes);
512 break;
513 case RHYTHMDB_PROP_ALBUM:
514 fmt = ngettext ("All %d album (%d)", "All %d albums (%d)", nodes);
515 break;
516 case RHYTHMDB_PROP_GENRE:
517 fmt = ngettext ("All %d genre (%d)", "All %d genres (%d)", nodes);
518 break;
519 default:
520 fmt = _("All %d (%d)");
521 break;
524 str = g_strdup_printf (fmt, nodes, number);
525 } else {
526 str = g_strdup_printf (_("%s (%d)"), title, number);
529 g_object_set (G_OBJECT (renderer), "text", str,
530 "weight", G_UNLIKELY (is_all) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
531 NULL);
532 g_free (str);
533 g_free (title);
536 static GObject *
537 rb_property_view_constructor (GType type,
538 guint n_construct_properties,
539 GObjectConstructParam *construct_properties)
541 GtkTreeViewColumn *column;
542 GtkCellRenderer *renderer;
544 RBPropertyView *view;
545 RBPropertyViewClass *klass;
547 klass = RB_PROPERTY_VIEW_CLASS (g_type_class_peek (RB_TYPE_PROPERTY_VIEW));
549 view = RB_PROPERTY_VIEW (G_OBJECT_CLASS (rb_property_view_parent_class)->
550 constructor (type, n_construct_properties, construct_properties));
552 view->priv->prop_model = rhythmdb_property_model_new (view->priv->db, view->priv->propid);
553 view->priv->treeview = GTK_WIDGET (gtk_tree_view_new_with_model (GTK_TREE_MODEL (view->priv->prop_model)));
555 if (view->priv->draggable)
556 rhythmdb_property_model_enable_drag (view->priv->prop_model,
557 GTK_TREE_VIEW (view->priv->treeview));
559 g_signal_connect_object (G_OBJECT (view->priv->treeview),
560 "row_activated",
561 G_CALLBACK (rb_property_view_row_activated_cb),
562 view,
565 view->priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
566 g_signal_connect_object (G_OBJECT (view->priv->selection),
567 "changed",
568 G_CALLBACK (rb_property_view_selection_changed_cb),
569 view,
571 g_signal_connect_object (G_OBJECT (view->priv->treeview),
572 "popup_menu",
573 G_CALLBACK (rb_property_view_popup_menu_cb),
574 view,
577 g_signal_connect_object (G_OBJECT (view->priv->treeview),
578 "button_press_event",
579 G_CALLBACK (rb_property_view_button_press_cb),
580 view,
583 gtk_container_add (GTK_CONTAINER (view), view->priv->treeview);
585 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view->priv->treeview), TRUE);
586 gtk_tree_selection_set_mode (view->priv->selection, GTK_SELECTION_SINGLE);
588 column = gtk_tree_view_column_new ();
589 renderer = gtk_cell_renderer_text_new ();
590 gtk_tree_view_column_pack_start (column, renderer, TRUE);
591 gtk_tree_view_column_set_cell_data_func (column, renderer,
592 (GtkTreeCellDataFunc) rb_property_view_cell_data_func,
593 view, NULL);
594 gtk_tree_view_column_set_title (column, view->priv->title);
595 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
596 gtk_tree_view_append_column (GTK_TREE_VIEW (view->priv->treeview),
597 column);
599 return G_OBJECT (view);
602 static void
603 rb_property_view_row_activated_cb (GtkTreeView *treeview,
604 GtkTreePath *path,
605 GtkTreeViewColumn *column,
606 RBPropertyView *view)
608 GtkTreeIter iter;
609 char *val;
610 gboolean is_all;
612 rb_debug ("row activated");
613 g_return_if_fail (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->priv->prop_model),
614 &iter, path));
616 gtk_tree_model_get (GTK_TREE_MODEL (view->priv->prop_model), &iter,
617 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &val,
618 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all, -1);
620 rb_debug ("emitting property activated");
621 g_signal_emit (G_OBJECT (view), rb_property_view_signals[PROPERTY_ACTIVATED], 0,
622 is_all ? NULL : val);
624 g_free (val);
627 void
628 rb_property_view_set_selection (RBPropertyView *view,
629 const GList *vals)
631 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
633 view->priv->handling_row_deletion = TRUE;
635 gtk_tree_selection_unselect_all (view->priv->selection);
637 for (; vals ; vals = vals->next) {
638 GtkTreeIter iter;
640 if (rhythmdb_property_model_iter_from_string (view->priv->prop_model, vals->data, &iter)) {
641 GtkTreePath *path;
643 gtk_tree_selection_select_iter (view->priv->selection, &iter);
644 path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->priv->prop_model), &iter);
645 if (path != NULL) {
646 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view->priv->treeview),
647 path, NULL, TRUE,
648 0.5, 0.0);
649 gtk_tree_path_free (path);
655 view->priv->handling_row_deletion = FALSE;
656 rb_property_view_selection_changed_cb (view->priv->selection, view);
659 static void
660 rb_property_view_selection_changed_cb (GtkTreeSelection *selection,
661 RBPropertyView *view)
663 char *selected_prop = NULL;
664 gboolean is_all = TRUE;
665 GtkTreeModel *model;
666 GtkTreeIter iter;
668 if (view->priv->handling_row_deletion)
669 return;
671 rb_debug ("selection changed");
672 if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_MULTIPLE) {
673 GList *selected_rows, *tem;
674 GList *selected_properties = NULL;
676 selected_rows = gtk_tree_selection_get_selected_rows (view->priv->selection, &model);
677 for (tem = selected_rows; tem; tem = tem->next) {
678 g_assert (gtk_tree_model_get_iter (model, &iter, tem->data));
679 gtk_tree_model_get (model, &iter,
680 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &selected_prop,
681 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all, -1);
682 if (is_all) {
683 g_list_free (selected_properties);
684 selected_properties = NULL;
685 break;
687 selected_properties = g_list_prepend (selected_properties,
688 g_strdup (selected_prop));
691 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
692 g_list_free (selected_rows);
694 if (is_all) {
695 g_signal_handlers_block_by_func (G_OBJECT (view->priv->selection),
696 G_CALLBACK (rb_property_view_selection_changed_cb),
697 view);
698 gtk_tree_selection_unselect_all (selection);
699 if (gtk_tree_model_get_iter_first (model, &iter))
700 gtk_tree_selection_select_iter (selection, &iter);
701 g_signal_handlers_unblock_by_func (G_OBJECT (view->priv->selection),
702 G_CALLBACK (rb_property_view_selection_changed_cb),
703 view);
705 g_signal_emit (G_OBJECT (view), rb_property_view_signals[PROPERTIES_SELECTED], 0,
706 selected_properties);
707 rb_list_deep_free (selected_properties);
708 } else {
709 if (gtk_tree_selection_get_selected (view->priv->selection, &model, &iter)) {
710 gtk_tree_model_get (model, &iter,
711 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &selected_prop,
712 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all, -1);
713 g_signal_emit (G_OBJECT (view), rb_property_view_signals[PROPERTY_SELECTED], 0,
714 is_all ? NULL : selected_prop);
718 g_free (selected_prop);
721 static gboolean
722 rb_property_view_popup_menu_cb (GtkTreeView *treeview,
723 RBPropertyView *view)
725 g_signal_emit (G_OBJECT (view), rb_property_view_signals[SHOW_POPUP], 0);
726 return TRUE;
729 void
730 rb_property_view_append_column_custom (RBPropertyView *view,
731 GtkTreeViewColumn *column)
733 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
735 gtk_tree_view_append_column (GTK_TREE_VIEW (view->priv->treeview), column);
738 static gboolean
739 rb_property_view_button_press_cb (GtkTreeView *tree,
740 GdkEventButton *event,
741 RBPropertyView *view)
744 if (event->button == 3) {
745 GtkTreeSelection *selection;
746 GtkTreePath *path;
748 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
750 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view->priv->treeview), event->x, event->y, &path, NULL, NULL, NULL);
751 if (path == NULL) {
752 gtk_tree_selection_unselect_all (selection);
753 } else {
754 GtkTreeModel *model;
755 GtkTreeIter iter;
756 char *val;
757 GList *lst = NULL;
759 model = gtk_tree_view_get_model (GTK_TREE_VIEW (view->priv->treeview));
760 if (gtk_tree_model_get_iter (model, &iter, path)) {
761 gtk_tree_model_get (model, &iter,
762 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &val, -1);
763 lst = g_list_prepend (lst, (gpointer) val);
764 rb_property_view_set_selection (view, lst);
765 g_free (val);
768 g_signal_emit (G_OBJECT (view), rb_property_view_signals[SHOW_POPUP], 0);
769 return TRUE;
772 return FALSE;
775 void
776 rb_property_view_set_search_func (RBPropertyView *view,
777 GtkTreeViewSearchEqualFunc func,
778 gpointer func_data,
779 GtkDestroyNotify notify)
781 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
783 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view->priv->treeview),
784 func, func_data,
785 notify);