udapted vi.po
[rhythmbox.git] / widgets / rb-property-view.c
blob3836c19939ddba3d38da34953a5d77fdc5432c03
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_dispose (GObject *object);
45 static void rb_property_view_finalize (GObject *object);
46 static void rb_property_view_set_property (GObject *object,
47 guint prop_id,
48 const GValue *value,
49 GParamSpec *pspec);
50 static void rb_property_view_get_property (GObject *object,
51 guint prop_id,
52 GValue *value,
53 GParamSpec *pspec);
54 static GObject * rb_property_view_constructor (GType type, guint n_construct_properties,
55 GObjectConstructParam *construct_properties);
56 static void rb_property_view_row_activated_cb (GtkTreeView *treeview,
57 GtkTreePath *path,
58 GtkTreeViewColumn *column,
59 RBPropertyView *view);
60 static void rb_property_view_selection_changed_cb (GtkTreeSelection *selection,
61 RBPropertyView *view);
62 static void rb_property_view_pre_row_deleted_cb (RhythmDBPropertyModel *model,
63 RBPropertyView *view);
64 static void rb_property_view_post_row_deleted_cb (GtkTreeModel *model,
65 GtkTreePath *path,
66 RBPropertyView *view);
67 static gboolean rb_property_view_popup_menu_cb (GtkTreeView *treeview,
68 RBPropertyView *view);
69 static gboolean rb_property_view_button_press_cb (GtkTreeView *tree,
70 GdkEventButton *event,
71 RBPropertyView *view);
73 struct RBPropertyViewPrivate
75 RhythmDB *db;
77 RhythmDBPropType propid;
79 RhythmDBPropertyModel *prop_model;
81 char *title;
83 GtkWidget *treeview;
84 GtkTreeSelection *selection;
86 gboolean draggable;
87 gboolean handling_row_deletion;
90 #define RB_PROPERTY_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PROPERTY_VIEW, RBPropertyViewPrivate))
92 enum
94 PROPERTY_SELECTED,
95 PROPERTIES_SELECTED,
96 PROPERTY_ACTIVATED,
97 SELECTION_RESET,
98 SHOW_POPUP,
99 LAST_SIGNAL
102 enum
104 PROP_0,
105 PROP_DB,
106 PROP_PROP,
107 PROP_TITLE,
108 PROP_MODEL,
109 PROP_DRAGGABLE,
112 static guint rb_property_view_signals[LAST_SIGNAL] = { 0 };
114 G_DEFINE_TYPE (RBPropertyView, rb_property_view, GTK_TYPE_SCROLLED_WINDOW)
116 static void
117 rb_property_view_class_init (RBPropertyViewClass *klass)
119 GObjectClass *object_class = G_OBJECT_CLASS (klass);
121 object_class->dispose = rb_property_view_dispose;
122 object_class->finalize = rb_property_view_finalize;
123 object_class->constructor = rb_property_view_constructor;
125 object_class->set_property = rb_property_view_set_property;
126 object_class->get_property = rb_property_view_get_property;
128 g_object_class_install_property (object_class,
129 PROP_DB,
130 g_param_spec_object ("db",
131 "RhythmDB",
132 "RhythmDB database",
133 RHYTHMDB_TYPE,
134 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
136 g_object_class_install_property (object_class,
137 PROP_PROP,
138 g_param_spec_enum ("prop",
139 "PropertyId",
140 "RhythmDBPropType",
141 RHYTHMDB_TYPE_PROP_TYPE,
142 RHYTHMDB_PROP_TYPE,
143 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
145 g_object_class_install_property (object_class,
146 PROP_TITLE,
147 g_param_spec_string ("title",
148 "title",
149 "title",
151 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
152 g_object_class_install_property (object_class,
153 PROP_MODEL,
154 g_param_spec_object ("property-model",
155 "property model",
156 "RhythmDBPropertyModel",
157 RHYTHMDB_TYPE_PROPERTY_MODEL,
158 G_PARAM_READWRITE));
159 g_object_class_install_property (object_class,
160 PROP_DRAGGABLE,
161 g_param_spec_boolean ("draggable",
162 "draggable",
163 "is a drag source",
164 TRUE,
165 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
167 rb_property_view_signals[PROPERTY_ACTIVATED] =
168 g_signal_new ("property-activated",
169 G_OBJECT_CLASS_TYPE (object_class),
170 G_SIGNAL_RUN_LAST,
171 G_STRUCT_OFFSET (RBPropertyViewClass, property_activated),
172 NULL, NULL,
173 g_cclosure_marshal_VOID__STRING,
174 G_TYPE_NONE,
176 G_TYPE_STRING);
178 rb_property_view_signals[PROPERTY_SELECTED] =
179 g_signal_new ("property-selected",
180 G_OBJECT_CLASS_TYPE (object_class),
181 G_SIGNAL_RUN_LAST,
182 G_STRUCT_OFFSET (RBPropertyViewClass, property_selected),
183 NULL, NULL,
184 g_cclosure_marshal_VOID__STRING,
185 G_TYPE_NONE,
187 G_TYPE_STRING);
189 rb_property_view_signals[PROPERTIES_SELECTED] =
190 g_signal_new ("properties-selected",
191 G_OBJECT_CLASS_TYPE (object_class),
192 G_SIGNAL_RUN_LAST,
193 G_STRUCT_OFFSET (RBPropertyViewClass, properties_selected),
194 NULL, NULL,
195 g_cclosure_marshal_VOID__POINTER,
196 G_TYPE_NONE,
198 G_TYPE_POINTER);
200 rb_property_view_signals[SELECTION_RESET] =
201 g_signal_new ("property-selection-reset",
202 G_OBJECT_CLASS_TYPE (object_class),
203 G_SIGNAL_RUN_LAST,
204 G_STRUCT_OFFSET (RBPropertyViewClass, selection_reset),
205 NULL, NULL,
206 g_cclosure_marshal_VOID__VOID,
207 G_TYPE_NONE,
209 rb_property_view_signals[SHOW_POPUP] =
210 g_signal_new ("show_popup",
211 G_OBJECT_CLASS_TYPE (object_class),
212 G_SIGNAL_RUN_LAST,
213 G_STRUCT_OFFSET (RBPropertyViewClass, show_popup),
214 NULL, NULL,
215 g_cclosure_marshal_VOID__VOID,
216 G_TYPE_NONE,
219 g_type_class_add_private (klass, sizeof (RBPropertyViewPrivate));
222 static void
223 rb_property_view_init (RBPropertyView *view)
225 view->priv = RB_PROPERTY_VIEW_GET_PRIVATE (view);
228 static void
229 rb_property_view_set_model_internal (RBPropertyView *view,
230 RhythmDBPropertyModel *model)
232 if (view->priv->prop_model != NULL) {
233 g_signal_handlers_disconnect_by_func (view->priv->prop_model,
234 G_CALLBACK (rb_property_view_pre_row_deleted_cb),
235 view);
236 g_signal_handlers_disconnect_by_func (view->priv->prop_model,
237 G_CALLBACK (rb_property_view_post_row_deleted_cb),
238 view);
239 g_object_unref (view->priv->prop_model);
242 view->priv->prop_model = model;
244 if (view->priv->prop_model != NULL) {
245 GtkTreeIter iter;
247 g_object_ref (view->priv->prop_model);
249 gtk_tree_view_set_model (GTK_TREE_VIEW (view->priv->treeview),
250 GTK_TREE_MODEL (view->priv->prop_model));
252 g_signal_connect_object (view->priv->prop_model,
253 "pre-row-deletion",
254 G_CALLBACK (rb_property_view_pre_row_deleted_cb),
255 view,
257 g_signal_connect_object (view->priv->prop_model,
258 "row_deleted",
259 G_CALLBACK (rb_property_view_post_row_deleted_cb),
260 view,
261 G_CONNECT_AFTER);
263 g_signal_handlers_block_by_func (view->priv->selection,
264 G_CALLBACK (rb_property_view_selection_changed_cb),
265 view);
267 gtk_tree_selection_unselect_all (view->priv->selection);
269 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (view->priv->prop_model), &iter))
270 gtk_tree_selection_select_iter (view->priv->selection, &iter);
272 g_signal_handlers_unblock_by_func (view->priv->selection,
273 G_CALLBACK (rb_property_view_selection_changed_cb),
274 view);
278 static void
279 rb_property_view_dispose (GObject *object)
281 RBPropertyView *view;
283 g_return_if_fail (object != NULL);
284 g_return_if_fail (RB_IS_PROPERTY_VIEW (object));
286 view = RB_PROPERTY_VIEW (object);
288 rb_property_view_set_model_internal (view, NULL);
290 G_OBJECT_CLASS (rb_property_view_parent_class)->dispose (object);
293 static void
294 rb_property_view_finalize (GObject *object)
296 RBPropertyView *view;
298 g_return_if_fail (object != NULL);
299 g_return_if_fail (RB_IS_PROPERTY_VIEW (object));
301 view = RB_PROPERTY_VIEW (object);
303 g_free (view->priv->title);
305 G_OBJECT_CLASS (rb_property_view_parent_class)->finalize (object);
308 static void
309 rb_property_view_set_property (GObject *object,
310 guint prop_id,
311 const GValue *value,
312 GParamSpec *pspec)
314 RBPropertyView *view = RB_PROPERTY_VIEW (object);
316 switch (prop_id) {
317 case PROP_DB:
318 view->priv->db = g_value_get_object (value);
319 break;
320 case PROP_PROP:
321 view->priv->propid = g_value_get_enum (value);
322 break;
323 case PROP_TITLE:
324 view->priv->title = g_value_dup_string (value);
325 break;
326 case PROP_MODEL:
327 rb_property_view_set_model_internal (view, g_value_get_object (value));
328 break;
329 case PROP_DRAGGABLE:
330 view->priv->draggable = g_value_get_boolean (value);
331 break;
332 default:
333 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
334 break;
338 static void
339 rb_property_view_get_property (GObject *object,
340 guint prop_id,
341 GValue *value,
342 GParamSpec *pspec)
344 RBPropertyView *view = RB_PROPERTY_VIEW (object);
346 switch (prop_id) {
347 case PROP_DB:
348 g_value_set_object (value, view->priv->db);
349 break;
350 case PROP_PROP:
351 g_value_set_enum (value, view->priv->propid);
352 break;
353 case PROP_TITLE:
354 g_value_set_string (value, view->priv->title);
355 break;
356 case PROP_MODEL:
357 g_value_set_object (value, view->priv->prop_model);
358 break;
359 case PROP_DRAGGABLE:
360 g_value_set_boolean (value, view->priv->draggable);
361 break;
362 default:
363 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
364 break;
368 RBPropertyView *
369 rb_property_view_new (RhythmDB *db,
370 guint propid,
371 const char *title)
373 RBPropertyView *view;
375 view = RB_PROPERTY_VIEW (g_object_new (RB_TYPE_PROPERTY_VIEW,
376 "hadjustment", NULL,
377 "vadjustment", NULL,
378 "hscrollbar_policy", GTK_POLICY_AUTOMATIC,
379 "vscrollbar_policy", GTK_POLICY_ALWAYS,
380 "shadow_type", GTK_SHADOW_IN,
381 "db", db,
382 "prop", propid,
383 "title", title,
384 "draggable", TRUE,
385 NULL));
387 g_return_val_if_fail (view->priv != NULL, NULL);
389 return view;
392 void
393 rb_property_view_set_selection_mode (RBPropertyView *view,
394 GtkSelectionMode mode)
396 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
397 g_return_if_fail (mode == GTK_SELECTION_SINGLE || mode == GTK_SELECTION_MULTIPLE);
399 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview)),
400 mode);
403 void
404 rb_property_view_reset (RBPropertyView *view)
406 RhythmDBPropertyModel *model;
408 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
410 model = rhythmdb_property_model_new (view->priv->db, view->priv->propid);
412 rb_property_view_set_model_internal (view, model);
413 g_object_unref (model);
416 RhythmDBPropertyModel *
417 rb_property_view_get_model (RBPropertyView *view)
419 RhythmDBPropertyModel *model;
421 g_return_val_if_fail (RB_IS_PROPERTY_VIEW (view), NULL);
423 model = view->priv->prop_model;
425 return model;
428 void
429 rb_property_view_set_model (RBPropertyView *view,
430 RhythmDBPropertyModel *model)
432 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
434 rb_property_view_set_model_internal (view, model);
437 static void
438 rb_property_view_pre_row_deleted_cb (RhythmDBPropertyModel *model,
439 RBPropertyView *view)
441 view->priv->handling_row_deletion = TRUE;
442 rb_debug ("pre row deleted");
445 static void
446 rb_property_view_post_row_deleted_cb (GtkTreeModel *model,
447 GtkTreePath *path,
448 RBPropertyView *view)
450 view->priv->handling_row_deletion = FALSE;
451 rb_debug ("post row deleted");
452 if (gtk_tree_selection_count_selected_rows (view->priv->selection) == 0) {
453 GtkTreeIter first_iter;
454 rb_debug ("no rows selected, signalling reset");
455 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (view->priv->prop_model), &first_iter)) {
456 g_signal_handlers_block_by_func (G_OBJECT (view->priv->selection),
457 G_CALLBACK (rb_property_view_selection_changed_cb),
458 view);
459 gtk_tree_selection_select_iter (view->priv->selection, &first_iter);
460 g_signal_emit (G_OBJECT (view), rb_property_view_signals[SELECTION_RESET], 0);
461 g_signal_handlers_unblock_by_func (G_OBJECT (view->priv->selection),
462 G_CALLBACK (rb_property_view_selection_changed_cb),
463 view);
468 guint
469 rb_property_view_get_num_properties (RBPropertyView *view)
471 g_return_val_if_fail (RB_IS_PROPERTY_VIEW (view), 0);
473 return gtk_tree_model_iter_n_children (GTK_TREE_MODEL (view->priv->prop_model),
474 NULL)-1;
477 static void
478 rb_property_view_cell_data_func (GtkTreeViewColumn *column,
479 GtkCellRenderer *renderer,
480 GtkTreeModel *tree_model,
481 GtkTreeIter *iter,
482 RBPropertyView *view)
484 char *title;
485 char *str;
486 guint number;
487 gboolean is_all;
489 gtk_tree_model_get (GTK_TREE_MODEL (tree_model), iter,
490 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &title,
491 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all,
492 RHYTHMDB_PROPERTY_MODEL_COLUMN_NUMBER, &number, -1);
494 if (is_all) {
495 int nodes;
496 const char *fmt;
498 nodes = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (tree_model), NULL);
499 /* Subtract one for the All node */
500 nodes--;
502 switch (view->priv->propid) {
503 case RHYTHMDB_PROP_ARTIST:
504 fmt = ngettext ("All %d artist (%d)", "All %d artists (%d)", nodes);
505 break;
506 case RHYTHMDB_PROP_ALBUM:
507 fmt = ngettext ("All %d album (%d)", "All %d albums (%d)", nodes);
508 break;
509 case RHYTHMDB_PROP_GENRE:
510 fmt = ngettext ("All %d genre (%d)", "All %d genres (%d)", nodes);
511 break;
512 default:
513 fmt = _("All %d (%d)");
514 break;
517 str = g_strdup_printf (fmt, nodes, number);
518 } else {
519 str = g_strdup_printf (_("%s (%d)"), title, number);
522 g_object_set (G_OBJECT (renderer), "text", str,
523 "weight", G_UNLIKELY (is_all) ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
524 NULL);
525 g_free (str);
526 g_free (title);
529 static GObject *
530 rb_property_view_constructor (GType type,
531 guint n_construct_properties,
532 GObjectConstructParam *construct_properties)
534 GtkTreeViewColumn *column;
535 GtkCellRenderer *renderer;
537 RBPropertyView *view;
538 RBPropertyViewClass *klass;
540 klass = RB_PROPERTY_VIEW_CLASS (g_type_class_peek (RB_TYPE_PROPERTY_VIEW));
542 view = RB_PROPERTY_VIEW (G_OBJECT_CLASS (rb_property_view_parent_class)->
543 constructor (type, n_construct_properties, construct_properties));
545 view->priv->prop_model = rhythmdb_property_model_new (view->priv->db, view->priv->propid);
546 view->priv->treeview = GTK_WIDGET (gtk_tree_view_new_with_model (GTK_TREE_MODEL (view->priv->prop_model)));
548 if (view->priv->draggable)
549 rhythmdb_property_model_enable_drag (view->priv->prop_model,
550 GTK_TREE_VIEW (view->priv->treeview));
552 g_signal_connect_object (G_OBJECT (view->priv->treeview),
553 "row_activated",
554 G_CALLBACK (rb_property_view_row_activated_cb),
555 view,
558 view->priv->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
559 g_signal_connect_object (G_OBJECT (view->priv->selection),
560 "changed",
561 G_CALLBACK (rb_property_view_selection_changed_cb),
562 view,
564 g_signal_connect_object (G_OBJECT (view->priv->treeview),
565 "popup_menu",
566 G_CALLBACK (rb_property_view_popup_menu_cb),
567 view,
570 g_signal_connect_object (G_OBJECT (view->priv->treeview),
571 "button_press_event",
572 G_CALLBACK (rb_property_view_button_press_cb),
573 view,
576 gtk_container_add (GTK_CONTAINER (view), view->priv->treeview);
578 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (view->priv->treeview), TRUE);
579 gtk_tree_selection_set_mode (view->priv->selection, GTK_SELECTION_SINGLE);
581 column = gtk_tree_view_column_new ();
582 renderer = gtk_cell_renderer_text_new ();
583 gtk_tree_view_column_pack_start (column, renderer, TRUE);
584 gtk_tree_view_column_set_cell_data_func (column, renderer,
585 (GtkTreeCellDataFunc) rb_property_view_cell_data_func,
586 view, NULL);
587 gtk_tree_view_column_set_title (column, view->priv->title);
588 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
589 gtk_tree_view_append_column (GTK_TREE_VIEW (view->priv->treeview),
590 column);
592 return G_OBJECT (view);
595 static void
596 rb_property_view_row_activated_cb (GtkTreeView *treeview,
597 GtkTreePath *path,
598 GtkTreeViewColumn *column,
599 RBPropertyView *view)
601 GtkTreeIter iter;
602 char *val;
603 gboolean is_all;
605 rb_debug ("row activated");
606 g_return_if_fail (gtk_tree_model_get_iter (GTK_TREE_MODEL (view->priv->prop_model),
607 &iter, path));
609 gtk_tree_model_get (GTK_TREE_MODEL (view->priv->prop_model), &iter,
610 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &val,
611 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all, -1);
613 rb_debug ("emitting property activated");
614 g_signal_emit (G_OBJECT (view), rb_property_view_signals[PROPERTY_ACTIVATED], 0,
615 is_all ? NULL : val);
617 g_free (val);
620 void
621 rb_property_view_set_selection (RBPropertyView *view,
622 const GList *vals)
624 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
626 view->priv->handling_row_deletion = TRUE;
628 gtk_tree_selection_unselect_all (view->priv->selection);
630 for (; vals ; vals = vals->next) {
631 GtkTreeIter iter;
633 if (rhythmdb_property_model_iter_from_string (view->priv->prop_model, vals->data, &iter)) {
634 GtkTreePath *path;
636 gtk_tree_selection_select_iter (view->priv->selection, &iter);
637 path = gtk_tree_model_get_path (GTK_TREE_MODEL (view->priv->prop_model), &iter);
638 if (path != NULL) {
639 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view->priv->treeview),
640 path, NULL, TRUE,
641 0.5, 0.0);
642 gtk_tree_path_free (path);
648 view->priv->handling_row_deletion = FALSE;
649 rb_property_view_selection_changed_cb (view->priv->selection, view);
652 static void
653 rb_property_view_selection_changed_cb (GtkTreeSelection *selection,
654 RBPropertyView *view)
656 char *selected_prop = NULL;
657 gboolean is_all = TRUE;
658 GtkTreeModel *model;
659 GtkTreeIter iter;
661 if (view->priv->handling_row_deletion)
662 return;
664 rb_debug ("selection changed");
665 if (gtk_tree_selection_get_mode (selection) == GTK_SELECTION_MULTIPLE) {
666 GList *selected_rows, *tem;
667 GList *selected_properties = NULL;
669 selected_rows = gtk_tree_selection_get_selected_rows (view->priv->selection, &model);
670 for (tem = selected_rows; tem; tem = tem->next) {
671 g_assert (gtk_tree_model_get_iter (model, &iter, tem->data));
672 gtk_tree_model_get (model, &iter,
673 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &selected_prop,
674 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all, -1);
675 if (is_all) {
676 g_list_free (selected_properties);
677 selected_properties = NULL;
678 break;
680 selected_properties = g_list_prepend (selected_properties,
681 g_strdup (selected_prop));
684 g_list_foreach (selected_rows, (GFunc) gtk_tree_path_free, NULL);
685 g_list_free (selected_rows);
687 if (is_all) {
688 g_signal_handlers_block_by_func (G_OBJECT (view->priv->selection),
689 G_CALLBACK (rb_property_view_selection_changed_cb),
690 view);
691 gtk_tree_selection_unselect_all (selection);
692 if (gtk_tree_model_get_iter_first (model, &iter))
693 gtk_tree_selection_select_iter (selection, &iter);
694 g_signal_handlers_unblock_by_func (G_OBJECT (view->priv->selection),
695 G_CALLBACK (rb_property_view_selection_changed_cb),
696 view);
698 g_signal_emit (G_OBJECT (view), rb_property_view_signals[PROPERTIES_SELECTED], 0,
699 selected_properties);
700 rb_list_deep_free (selected_properties);
701 } else {
702 if (gtk_tree_selection_get_selected (view->priv->selection, &model, &iter)) {
703 gtk_tree_model_get (model, &iter,
704 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &selected_prop,
705 RHYTHMDB_PROPERTY_MODEL_COLUMN_PRIORITY, &is_all, -1);
706 g_signal_emit (G_OBJECT (view), rb_property_view_signals[PROPERTY_SELECTED], 0,
707 is_all ? NULL : selected_prop);
711 g_free (selected_prop);
714 static gboolean
715 rb_property_view_popup_menu_cb (GtkTreeView *treeview,
716 RBPropertyView *view)
718 g_signal_emit (G_OBJECT (view), rb_property_view_signals[SHOW_POPUP], 0);
719 return TRUE;
722 void
723 rb_property_view_append_column_custom (RBPropertyView *view,
724 GtkTreeViewColumn *column)
726 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
728 gtk_tree_view_append_column (GTK_TREE_VIEW (view->priv->treeview), column);
731 static gboolean
732 rb_property_view_button_press_cb (GtkTreeView *tree,
733 GdkEventButton *event,
734 RBPropertyView *view)
737 if (event->button == 3) {
738 GtkTreeSelection *selection;
739 GtkTreePath *path;
741 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view->priv->treeview));
743 gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (view->priv->treeview), event->x, event->y, &path, NULL, NULL, NULL);
744 if (path == NULL) {
745 gtk_tree_selection_unselect_all (selection);
746 } else {
747 GtkTreeModel *model;
748 GtkTreeIter iter;
749 char *val;
750 GList *lst = NULL;
752 model = gtk_tree_view_get_model (GTK_TREE_VIEW (view->priv->treeview));
753 if (gtk_tree_model_get_iter (model, &iter, path)) {
754 gtk_tree_model_get (model, &iter,
755 RHYTHMDB_PROPERTY_MODEL_COLUMN_TITLE, &val, -1);
756 lst = g_list_prepend (lst, (gpointer) val);
757 rb_property_view_set_selection (view, lst);
758 g_free (val);
761 g_signal_emit (G_OBJECT (view), rb_property_view_signals[SHOW_POPUP], 0);
762 return TRUE;
765 return FALSE;
768 void
769 rb_property_view_set_search_func (RBPropertyView *view,
770 GtkTreeViewSearchEqualFunc func,
771 gpointer func_data,
772 GtkDestroyNotify notify)
774 g_return_if_fail (RB_IS_PROPERTY_VIEW (view));
776 gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (view->priv->treeview),
777 func, func_data,
778 notify);