1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3
* Copyright (C) 2011 Jonathan Matthew <jonathan@d14n.org>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* The Rhythmbox authors hereby grant permission for non-GPL compatible
11
* GStreamer plugins to be used and distributed together with GStreamer
12
* and Rhythmbox. This permission is above and beyond the permissions granted
13
* by the GPL license by which Rhythmbox is covered. If you modify this code
14
* you may extend this exception to your version of the code, but you are not
15
* obligated to do so. If you do not wish to do so, delete this exception
16
* statement from your version.
18
* This program is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* You should have received a copy of the GNU General Public License
24
* along with this program; if not, write to the Free Software
25
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
31
#include <widgets/rb-source-toolbar.h>
32
#include <lib/rb-util.h>
34
static void rb_source_toolbar_class_init (RBSourceToolbarClass *klass);
35
static void rb_source_toolbar_init (RBSourceToolbar *toolbar);
37
struct _RBSourceToolbarPrivate
39
GtkUIManager *ui_manager;
41
RBSearchEntry *search_entry;
42
GtkWidget *search_popup;
44
GBinding *browse_binding;
49
gulong search_change_cb_id;
50
RBSourceSearch *active_search;
52
GtkRadioAction *search_group;
55
G_DEFINE_TYPE (RBSourceToolbar, rb_source_toolbar, GTK_TYPE_GRID)
58
* SECTION:rb-source-toolbar
59
* @short_description: toolbar+search entry for sources
61
* This class combines a toolbar for custom source actions with a
62
* search entry. The toolbar content is specified using a UI path.
63
* The #RBSourceToolbar takes care of preserving search state when
64
* the selected page changes, and performs searches when the user
65
* selects a new search type or changes the search text.
76
prepare_toolbar (GtkWidget *toolbar)
78
static GtkCssProvider *provider = NULL;
80
if (provider == NULL) {
83
" -GtkToolbar-shadow-type: none;\n"
84
" border-style: none;\n"
87
provider = gtk_css_provider_new ();
88
gtk_css_provider_load_from_data (provider, style, -1, NULL);
91
gtk_style_context_add_provider (gtk_widget_get_style_context (toolbar),
92
GTK_STYLE_PROVIDER (provider),
93
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
95
gtk_widget_set_hexpand (toolbar, TRUE);
97
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_TEXT);
101
search_change_cb (GtkRadioAction *group, GtkRadioAction *current, RBSourceToolbar *toolbar)
103
toolbar->priv->active_search = rb_source_search_get_from_action (G_OBJECT (current));
105
if (toolbar->priv->search_text != NULL) {
106
rb_source_search (toolbar->priv->source, toolbar->priv->active_search, NULL, toolbar->priv->search_text);
109
rb_search_entry_set_placeholder (toolbar->priv->search_entry, gtk_action_get_label (GTK_ACTION (current)));
113
source_selected_cb (GObject *object, GParamSpec *pspec, RBSourceToolbar *toolbar)
117
g_object_get (object, "selected", &selected, NULL);
123
if (toolbar->priv->toolbar != NULL) {
124
gtk_grid_attach (GTK_GRID (toolbar), toolbar->priv->toolbar, 0, 0, 2, 1);
125
gtk_widget_show_all (GTK_WIDGET (toolbar->priv->toolbar));
128
if (toolbar->priv->search_entry != NULL) {
129
rb_search_entry_set_mnemonic (toolbar->priv->search_entry, TRUE);
131
gtk_widget_add_accelerator (GTK_WIDGET (toolbar->priv->search_entry),
133
gtk_ui_manager_get_accel_group (toolbar->priv->ui_manager),
134
gdk_unicode_to_keyval ('f'),
139
if (toolbar->priv->search_group != NULL) {
140
if (toolbar->priv->search_value != -1) {
141
gtk_radio_action_set_current_value (toolbar->priv->search_group,
142
toolbar->priv->search_value);
145
toolbar->priv->search_change_cb_id = g_signal_connect (toolbar->priv->search_group,
147
G_CALLBACK (search_change_cb),
151
g_object_get (toolbar->priv->source, "toolbar-path", &toolbar_path, NULL);
152
if (toolbar_path != NULL) {
153
GtkAction *browse_action;
155
browse_path = g_strdup_printf ("%s/Browse", toolbar_path);
156
browse_action = gtk_ui_manager_get_action (toolbar->priv->ui_manager, browse_path);
157
g_free (browse_path);
159
if (browse_action != NULL) {
160
toolbar->priv->browse_binding =
161
g_object_bind_property (toolbar->priv->source, "show-browser",
162
browse_action, "active",
163
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
165
g_free (toolbar_path);
168
if (toolbar->priv->toolbar != NULL) {
169
gtk_container_remove (GTK_CONTAINER (toolbar), toolbar->priv->toolbar);
172
if (toolbar->priv->search_entry != NULL) {
173
rb_search_entry_set_mnemonic (toolbar->priv->search_entry, FALSE);
175
gtk_widget_remove_accelerator (GTK_WIDGET (toolbar->priv->search_entry),
176
gtk_ui_manager_get_accel_group (toolbar->priv->ui_manager),
177
gdk_unicode_to_keyval ('f'),
181
if (toolbar->priv->search_group != NULL) {
182
if (toolbar->priv->search_change_cb_id != 0) {
183
g_signal_handler_disconnect (toolbar->priv->search_group,
184
toolbar->priv->search_change_cb_id);
187
toolbar->priv->search_value = gtk_radio_action_get_current_value (toolbar->priv->search_group);
190
if (toolbar->priv->browse_binding != NULL) {
191
g_object_unref (toolbar->priv->browse_binding);
192
toolbar->priv->browse_binding = NULL;
198
search_cb (RBSearchEntry *search_entry, const char *text, RBSourceToolbar *toolbar)
200
rb_source_search (toolbar->priv->source, toolbar->priv->active_search, toolbar->priv->search_text, text);
202
g_free (toolbar->priv->search_text);
203
toolbar->priv->search_text = NULL;
205
toolbar->priv->search_text = g_strdup (text);
210
show_popup_cb (RBSearchEntry *search_entry, RBSourceToolbar *toolbar)
212
gtk_menu_popup (GTK_MENU (toolbar->priv->search_popup),
213
NULL, NULL, NULL, NULL, 3,
214
gtk_get_current_event_time ());
219
impl_finalize (GObject *object)
221
RBSourceToolbar *toolbar = RB_SOURCE_TOOLBAR (object);
223
g_free (toolbar->priv->search_text);
224
g_free (toolbar->priv->popup_path);
226
G_OBJECT_CLASS (rb_source_toolbar_parent_class)->finalize (object);
230
impl_dispose (GObject *object)
232
RBSourceToolbar *toolbar = RB_SOURCE_TOOLBAR (object);
234
if (toolbar->priv->ui_manager != NULL) {
235
g_object_unref (toolbar->priv->ui_manager);
236
toolbar->priv->ui_manager = NULL;
238
if (toolbar->priv->search_popup != NULL) {
239
g_object_unref (toolbar->priv->search_popup);
240
toolbar->priv->search_popup = NULL;
242
if (toolbar->priv->toolbar != NULL) {
243
g_object_unref (toolbar->priv->toolbar);
244
toolbar->priv->toolbar = NULL;
246
if (toolbar->priv->browse_binding != NULL) {
247
g_object_unref (toolbar->priv->browse_binding);
248
toolbar->priv->browse_binding = NULL;
251
G_OBJECT_CLASS (rb_source_toolbar_parent_class)->dispose (object);
255
toolbar_add_widget_cb (GtkUIManager *ui_manager, GtkWidget *widget, RBSourceToolbar *toolbar)
260
g_object_get (toolbar->priv->source, "toolbar-path", &toolbar_path, "selected", &selected, NULL);
261
toolbar->priv->toolbar = gtk_ui_manager_get_widget (toolbar->priv->ui_manager, toolbar_path);
262
g_free (toolbar_path);
264
if (toolbar->priv->toolbar) {
265
g_object_ref (toolbar->priv->toolbar);
266
g_signal_handlers_disconnect_by_func (ui_manager, G_CALLBACK (toolbar_add_widget_cb), toolbar);
268
prepare_toolbar (toolbar->priv->toolbar);
271
gtk_grid_attach (GTK_GRID (toolbar), toolbar->priv->toolbar, 0, 0, 2, 1);
272
gtk_widget_show_all (GTK_WIDGET (toolbar->priv->toolbar));
278
impl_constructed (GObject *object)
280
RBSourceToolbar *toolbar;
284
RB_CHAIN_GOBJECT_METHOD (rb_source_toolbar_parent_class, constructed, object);
286
toolbar = RB_SOURCE_TOOLBAR (object);
288
g_object_get (toolbar->priv->source, "toolbar-path", &toolbar_path, NULL);
290
toolbar->priv->toolbar = gtk_ui_manager_get_widget (toolbar->priv->ui_manager, toolbar_path);
291
if (toolbar->priv->toolbar == NULL) {
292
g_signal_connect (toolbar->priv->ui_manager, "add-widget", G_CALLBACK (toolbar_add_widget_cb), toolbar);
294
g_object_ref (toolbar->priv->toolbar);
295
prepare_toolbar (toolbar->priv->toolbar);
298
blank = gtk_toolbar_new ();
299
prepare_toolbar (blank);
300
gtk_grid_attach (GTK_GRID (toolbar), blank, 0, 0, 2 ,1);
302
g_free (toolbar_path);
304
/* search entry gets created later if required */
306
g_signal_connect (toolbar->priv->source, "notify::selected", G_CALLBACK (source_selected_cb), toolbar);
310
impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
312
RBSourceToolbar *toolbar = RB_SOURCE_TOOLBAR (object);
316
g_value_set_object (value, toolbar->priv->source);
318
case PROP_UI_MANAGER:
319
g_value_set_object (value, toolbar->priv->ui_manager);
322
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
328
impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
330
RBSourceToolbar *toolbar = RB_SOURCE_TOOLBAR (object);
334
toolbar->priv->source = g_value_get_object (value); /* don't take a ref */
336
case PROP_UI_MANAGER:
337
toolbar->priv->ui_manager = g_value_dup_object (value);
340
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
346
rb_source_toolbar_init (RBSourceToolbar *toolbar)
348
toolbar->priv = G_TYPE_INSTANCE_GET_PRIVATE (toolbar, RB_TYPE_SOURCE_TOOLBAR, RBSourceToolbarPrivate);
350
toolbar->priv->search_value = -1;
354
rb_source_toolbar_class_init (RBSourceToolbarClass *klass)
356
GObjectClass *object_class = G_OBJECT_CLASS (klass);
358
object_class->constructed = impl_constructed;
359
object_class->dispose = impl_dispose;
360
object_class->finalize = impl_finalize;
361
object_class->set_property = impl_set_property;
362
object_class->get_property = impl_get_property;
365
* RBSourceToolbar:source:
367
* The #RBSource the toolbar is associated with
369
g_object_class_install_property (object_class,
371
g_param_spec_object ("source",
375
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
377
* RBSourceToolbar:ui-manager:
379
* The #GtkUIManager instance
381
g_object_class_install_property (object_class,
383
g_param_spec_object ("ui-manager",
385
"GtkUIManager instance",
387
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
388
g_type_class_add_private (klass, sizeof (RBSourceToolbarPrivate));
392
* rb_source_toolbar_new:
393
* @source: a #RBSource
394
* @ui_manager: the #GtkUIManager
396
* Creates a new source toolbar for @source. The toolbar does not
397
* initially include a search entry. Call #rb_source_toolbar_add_search_entry
398
* to add one. The toolbar content comes from the @RBSource:toolbar-path property.
400
* Return value: the #RBSourceToolbar
403
rb_source_toolbar_new (RBSource *source, GtkUIManager *ui_manager)
406
object = g_object_new (RB_TYPE_SOURCE_TOOLBAR,
408
"ui-manager", ui_manager,
410
"column-homogeneous", TRUE,
412
"row-homogeneous", TRUE,
414
return RB_SOURCE_TOOLBAR (object);
418
setup_search_popup (RBSourceToolbar *toolbar, GtkWidget *popup)
424
toolbar->priv->search_popup = g_object_ref (popup);
426
items = gtk_container_get_children (GTK_CONTAINER (toolbar->priv->search_popup));
427
toolbar->priv->search_group = GTK_RADIO_ACTION (gtk_activatable_get_related_action (GTK_ACTIVATABLE (items->data)));
430
active_value = gtk_radio_action_get_current_value (toolbar->priv->search_group);
431
for (l = gtk_radio_action_get_group (toolbar->priv->search_group); l != NULL; l = l->next) {
433
g_object_get (G_OBJECT (l->data), "value", &value, NULL);
434
if (value == active_value) {
435
rb_search_entry_set_placeholder (toolbar->priv->search_entry,
436
gtk_action_get_label (GTK_ACTION (l->data)));
440
g_signal_connect (toolbar->priv->search_entry, "show-popup", G_CALLBACK (show_popup_cb), toolbar);
444
popup_add_widget_cb (GtkUIManager *ui_manager, GtkWidget *widget, RBSourceToolbar *toolbar)
447
popup = gtk_ui_manager_get_widget (toolbar->priv->ui_manager, toolbar->priv->popup_path);
450
setup_search_popup (toolbar, popup);
451
g_signal_handlers_disconnect_by_func (ui_manager, G_CALLBACK (popup_add_widget_cb), toolbar);
457
* rb_source_toolbar_add_search_entry:
458
* @toolbar: a #RBSourceToolbar
459
* @popup_path: the UI path for the search popup (or NULL)
460
* @placeholder: the placeholder text for the search entry (or NULL)
462
* Adds a search entry to the toolbar. If a popup path is specified,
463
* clicking on the primary icon will show a menu allowing the user to
464
* select a search type, and the placeholder text for the entry will
465
* be the selected search description. Otherwise, the specified placeholder
466
* text will be displayed.
469
rb_source_toolbar_add_search_entry (RBSourceToolbar *toolbar, const char *popup_path, const char *placeholder)
471
g_assert (toolbar->priv->search_entry == NULL);
473
toolbar->priv->search_entry = rb_search_entry_new (popup_path != NULL);
474
gtk_widget_set_margin_right (GTK_WIDGET (toolbar->priv->search_entry), 6);
475
gtk_grid_attach (GTK_GRID (toolbar), GTK_WIDGET (toolbar->priv->search_entry), 2, 0, 1, 1);
478
rb_search_entry_set_placeholder (toolbar->priv->search_entry, placeholder);
481
g_signal_connect (toolbar->priv->search_entry, "search", G_CALLBACK (search_cb), toolbar);
484
if (popup_path != NULL) {
486
toolbar->priv->popup_path = g_strdup (popup_path);
488
popup = gtk_ui_manager_get_widget (toolbar->priv->ui_manager, popup_path);
490
setup_search_popup (toolbar, popup);
492
g_signal_connect (toolbar->priv->ui_manager, "add-widget", G_CALLBACK (popup_add_widget_cb), toolbar);
498
* rb_source_toolbar_clear_search_entry:
499
* @toolbar: a #RBSourceToolbar
501
* Clears the search entry text. Call this from RBSource:impl_reset_filters.
504
rb_source_toolbar_clear_search_entry (RBSourceToolbar *toolbar)
506
g_assert (toolbar->priv->search_entry != NULL);
507
rb_search_entry_clear (toolbar->priv->search_entry);