~ubuntu-branches/ubuntu/utopic/rhythmbox/utopic-proposed

« back to all changes in this revision

Viewing changes to shell/rb-source-header.c

Tags: upstream-0.9.2
ImportĀ upstreamĀ versionĀ 0.9.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* 
2
2
 *  arch-tag: Implementation of search entry/browse toggle container
3
3
 *
4
 
 *  Copyright (C) 2003 Colin Walters <walters@debian.org>
5
4
 *  Copyright (C) 2003 Jorn Baayen <jorn@nl.linux.org>
 
5
 *  Copyright (C) 2003,2004 Colin Walters <walters@redhat.com>
6
6
 *
7
7
 *  This program is free software; you can redistribute it and/or modify
8
8
 *  it under the terms of the GNU General Public License as published by
26
26
#include <stdlib.h>
27
27
#include <string.h>
28
28
#include <libgnome/gnome-i18n.h>
29
 
#include <bonobo/bonobo-ui-util.h>
30
29
 
31
30
#include "disclosure-widget.h"
32
31
#include "rb-source-header.h"
33
32
#include "rb-stock-icons.h"
34
 
#include "rb-thread-helpers.h"
35
 
#include "rb-bonobo-helpers.h"
36
33
#include "rb-preferences.h"
37
34
#include "rb-search-entry.h"
38
35
#include "rb-debug.h"
39
36
#include "rb-remote.h"
 
37
#include "rb-entry-view.h"
40
38
#include "eel-gconf-extensions.h"
41
39
 
42
40
static void rb_source_header_class_init (RBSourceHeaderClass *klass);
55
53
static void rb_source_header_search_cb (RBSearchEntry *search,
56
54
                                        const char *text,
57
55
                                        RBSourceHeader *header);
58
 
static void rb_source_header_disclosure_toggled_cb (GtkToggleButton *disclosure,
 
56
static void rb_source_header_disclosure_toggled_cb (GObject *object,
 
57
                                                    GParamSpec *param_spec,
59
58
                                                    gpointer data);
60
 
static void rb_source_header_gconf_search_text_changed_cb (GConfClient *client,
61
 
                                                           guint cnxn_id,
62
 
                                                           GConfEntry *entry,
63
 
                                                           RBSourceHeader *header);
 
59
static void rb_source_header_search_activate_cb (RBSearchEntry *search,
 
60
                                                 RBSourceHeader *header);
64
61
static void rb_source_header_gconf_disclosure_changed_cb (GConfClient *client,
65
62
                                                          guint cnxn_id,
66
63
                                                          GConfEntry *entry,
67
64
                                                          RBSourceHeader *header);
68
 
static void rb_source_header_view_browser_changed_cb (BonoboUIComponent *component,
69
 
                                                      const char *path,
70
 
                                                      Bonobo_UIComponent_EventType type,
71
 
                                                      const char *state,
 
65
static void rb_source_header_view_browser_changed_cb (GtkAction *action,
72
66
                                                      RBSourceHeader *header);
 
67
static void rb_source_header_source_weak_destroy_cb (RBSourceHeader *header, RBSource *source);
73
68
 
74
69
struct RBSourceHeaderPrivate
75
70
{
76
71
        RBSource *selected_source;
77
72
 
78
 
        BonoboUIComponent *component;
 
73
        GtkActionGroup *actiongroup;
79
74
 
80
75
        GtkTooltips *tooltips;
81
76
 
84
79
 
85
80
        guint browser_notify_id;
86
81
        guint search_notify_id;
 
82
        gboolean have_search;
87
83
        const char *browser_key;
88
 
        const char *search_key;
 
84
 
 
85
        GHashTable *source_search_text;
89
86
};
90
87
 
91
88
enum
92
89
{
93
90
        PROP_0,
94
 
        PROP_COMPONENT,
 
91
        PROP_ACTION_GROUP,
95
92
        PROP_SOURCE,
96
93
};
97
94
 
98
 
#define CMD_PATH_VIEW_BROWSER   "/commands/ViewBrowser"
99
 
#define CMD_PATH_VIEW_STATUSBAR  "/commands/ViewStatusbar"
100
 
 
101
 
static RBBonoboUIListener rb_source_header_listeners[] =
 
95
static GtkToggleActionEntry rb_source_header_toggle_entries [] =
102
96
{
103
 
        RB_BONOBO_UI_LISTENER ("ViewBrowser", (BonoboUIListenerFn) rb_source_header_view_browser_changed_cb),
104
 
        RB_BONOBO_UI_LISTENER_END
 
97
        { "ViewBrowser", NULL, N_("_Browser"), "<control>B",
 
98
          N_("Change the visibility of the browser"),
 
99
          G_CALLBACK (rb_source_header_view_browser_changed_cb) }
105
100
};
106
 
 
107
 
static GObjectClass *parent_class = NULL;
108
 
 
109
 
GType
110
 
rb_source_header_get_type (void)
111
 
{
112
 
        static GType rb_source_header_type = 0;
113
 
 
114
 
        if (rb_source_header_type == 0)
115
 
        {
116
 
                static const GTypeInfo our_info =
117
 
                {
118
 
                        sizeof (RBSourceHeaderClass),
119
 
                        NULL,
120
 
                        NULL,
121
 
                        (GClassInitFunc) rb_source_header_class_init,
122
 
                        NULL,
123
 
                        NULL,
124
 
                        sizeof (RBSourceHeader),
125
 
                        0,
126
 
                        (GInstanceInitFunc) rb_source_header_init
127
 
                };
128
 
 
129
 
                rb_source_header_type = g_type_register_static (GTK_TYPE_TABLE,
130
 
                                                               "RBSourceHeader",
131
 
                                                               &our_info, 0);
132
 
        }
133
 
 
134
 
        return rb_source_header_type;
135
 
}
 
101
static guint rb_source_header_n_toggle_entries = G_N_ELEMENTS (rb_source_header_toggle_entries);
 
102
 
 
103
 
 
104
G_DEFINE_TYPE (RBSourceHeader, rb_source_header, GTK_TYPE_TABLE)
136
105
 
137
106
static void
138
107
rb_source_header_class_init (RBSourceHeaderClass *klass)
139
108
{
140
109
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
141
110
 
142
 
        parent_class = g_type_class_peek_parent (klass);
143
 
 
144
111
        object_class->finalize = rb_source_header_finalize;
145
112
 
146
113
        object_class->set_property = rb_source_header_set_property;
154
121
                                                              RB_TYPE_SOURCE,
155
122
                                                              G_PARAM_READWRITE));
156
123
        g_object_class_install_property (object_class,
157
 
                                         PROP_COMPONENT,
158
 
                                         g_param_spec_object ("component",
159
 
                                                              "BonoboUIComponent",
160
 
                                                              "BonoboUIComponent object",
161
 
                                                              BONOBO_TYPE_UI_COMPONENT,
 
124
                                         PROP_ACTION_GROUP,
 
125
                                         g_param_spec_object ("action-group",
 
126
                                                              "GtkActionGroup",
 
127
                                                              "GtkActionGroup object",
 
128
                                                              GTK_TYPE_ACTION_GROUP,
162
129
                                                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
163
130
}
164
131
 
186
153
 
187
154
        g_signal_connect_object (G_OBJECT (header->priv->search), "search",
188
155
                                 G_CALLBACK (rb_source_header_search_cb), header, 0);
 
156
        g_signal_connect_object (G_OBJECT (header->priv->search), "activate",
 
157
                                 G_CALLBACK (rb_source_header_search_activate_cb), header, 0);
189
158
 
190
159
        header->priv->disclosure = cddb_disclosure_new (_("Show _Browser"),
191
160
                                                        _("Hide _Browser"));
192
161
        gtk_widget_set_sensitive (header->priv->disclosure, FALSE);
193
 
        g_signal_connect_object (G_OBJECT (header->priv->disclosure), "toggled",
 
162
        g_signal_connect_object (G_OBJECT (header->priv->disclosure), "notify::expanded",
194
163
                                 G_CALLBACK (rb_source_header_disclosure_toggled_cb), header, 0);
195
164
 
196
165
        gtk_table_attach_defaults (GTK_TABLE (header),
198
167
 
199
168
        align = gtk_alignment_new (1.0, 0.5, 1.0, 1.0);
200
169
        gtk_container_add (GTK_CONTAINER (align), GTK_WIDGET (ebox));
201
 
        gtk_table_attach_defaults (GTK_TABLE (header),
202
 
                                   align, 2, 3, 0, 1);
 
170
        gtk_table_attach (GTK_TABLE (header),
 
171
                          align, 2, 3, 0, 1, 
 
172
                          GTK_EXPAND | GTK_FILL,
 
173
                          GTK_EXPAND | GTK_FILL,
 
174
                          5, 0);
 
175
 
 
176
        header->priv->source_search_text = g_hash_table_new_full (g_direct_hash, g_direct_equal,
 
177
                                                                  NULL, (GDestroyNotify)g_free);
 
178
}
 
179
 
 
180
static void
 
181
rb_source_header_source_weak_unref (RBSource *source, char *text, RBSourceHeader *header)
 
182
{
 
183
        g_object_weak_unref (G_OBJECT (source),
 
184
                             (GWeakNotify)rb_source_header_source_weak_destroy_cb,
 
185
                             header);
203
186
}
204
187
 
205
188
static void
214
197
 
215
198
        g_return_if_fail (header->priv != NULL);
216
199
 
 
200
        g_hash_table_foreach (header->priv->source_search_text,
 
201
                              (GHFunc) rb_source_header_source_weak_unref,
 
202
                              header);
 
203
        g_hash_table_destroy (header->priv->source_search_text);
 
204
 
217
205
        g_free (header->priv);
218
206
 
219
 
        G_OBJECT_CLASS (parent_class)->finalize (object);
 
207
        G_OBJECT_CLASS (rb_source_header_parent_class)->finalize (object);
220
208
}
221
209
 
222
210
static void
234
222
                {
235
223
                        if (header->priv->browser_key)
236
224
                                eel_gconf_notification_remove (header->priv->browser_notify_id);
237
 
                        if (header->priv->search_key)
238
 
                                eel_gconf_notification_remove (header->priv->search_notify_id);
239
 
 
240
225
                        g_signal_handlers_disconnect_by_func (G_OBJECT (header->priv->selected_source),
241
226
                                                              G_CALLBACK (rb_source_header_filter_changed_cb),
242
227
                                                              header);
247
232
 
248
233
                if (header->priv->selected_source != NULL)
249
234
                {
 
235
                        const char *text = g_hash_table_lookup (header->priv->source_search_text,
 
236
                                                                header->priv->selected_source);
 
237
                        
250
238
                        header->priv->browser_key = rb_source_get_browser_key (header->priv->selected_source);
251
 
                        header->priv->search_key = rb_source_get_search_key (header->priv->selected_source);
252
239
                        if (header->priv->browser_key)
253
240
                                header->priv->browser_notify_id
254
241
                                        = eel_gconf_notification_add (header->priv->browser_key,
255
242
                                                                      (GConfClientNotifyFunc) rb_source_header_gconf_disclosure_changed_cb,
256
243
                                                                      header);
257
 
                        if (header->priv->search_key) {
258
 
                                gchar *temp = eel_gconf_get_string (header->priv->search_key);
259
 
                                
260
 
                                header->priv->search_notify_id
261
 
                                        = eel_gconf_notification_add (header->priv->search_key,
262
 
                                                                      (GConfClientNotifyFunc) rb_source_header_gconf_search_text_changed_cb,
263
 
                                                                      header);
264
 
 
265
 
                                rb_search_entry_set_text (RB_SEARCH_ENTRY (header->priv->search),
266
 
                                                          temp);
267
 
                                g_free (temp);
268
 
                        }
 
244
                        rb_search_entry_set_text (RB_SEARCH_ENTRY (header->priv->search), text);
269
245
                        g_signal_connect_object (G_OBJECT (header->priv->selected_source),
270
246
                                                 "filter_changed",
271
247
                                                 G_CALLBACK (rb_source_header_filter_changed_cb),
272
248
                                                 header, 0);
273
249
                        gtk_widget_set_sensitive (GTK_WIDGET (header->priv->search),
274
250
                                                  rb_source_can_search (header->priv->selected_source));
275
 
                        if (!header->priv->browser_key &&
276
 
                            !rb_source_can_search (header->priv->selected_source))
 
251
                        header->priv->have_search = rb_source_can_search (header->priv->selected_source);
 
252
                        if (!header->priv->browser_key && !header->priv->have_search)
277
253
                                gtk_widget_hide (GTK_WIDGET (header));
278
254
                        else
279
255
                                gtk_widget_show (GTK_WIDGET (header));
281
257
                rb_source_header_sync_control_state (header);
282
258
                
283
259
                break;
284
 
        case PROP_COMPONENT:
285
 
                header->priv->component = g_value_get_object (value);
286
 
                rb_bonobo_add_listener_list_with_data (header->priv->component,
287
 
                                                       rb_source_header_listeners,
288
 
                                                       header);
 
260
        case PROP_ACTION_GROUP:
 
261
                header->priv->actiongroup = g_value_get_object (value);
 
262
                gtk_action_group_add_toggle_actions (header->priv->actiongroup,
 
263
                                                     rb_source_header_toggle_entries,
 
264
                                                     rb_source_header_n_toggle_entries,
 
265
                                                     header);
289
266
                break;
290
267
        default:
291
268
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
306
283
        case PROP_SOURCE:
307
284
                g_value_set_object (value, header->priv->selected_source);
308
285
                break;
309
 
        case PROP_COMPONENT:
310
 
                g_value_set_object (value, header->priv->component);
 
286
        case PROP_ACTION_GROUP:
 
287
                g_value_set_object (value, header->priv->actiongroup);
311
288
                break;
312
289
        default:
313
290
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
328
305
}
329
306
 
330
307
RBSourceHeader *
331
 
rb_source_header_new (BonoboUIComponent *component)
 
308
rb_source_header_new (GtkActionGroup *actiongroup)
332
309
{
333
310
        RBSourceHeader *header = g_object_new (RB_TYPE_SOURCE_HEADER,
334
 
                                               "component", component,
 
311
                                               "action-group", actiongroup,
335
312
                                               NULL);
336
313
 
337
314
        g_return_val_if_fail (header->priv != NULL, NULL);
353
330
}
354
331
 
355
332
static void
356
 
rb_source_header_gconf_search_text_changed_cb (GConfClient *client,
357
 
                                               guint cnxn_id,
358
 
                                               GConfEntry *entry,
359
 
                                               RBSourceHeader *header)
 
333
rb_source_header_source_weak_destroy_cb (RBSourceHeader *header, RBSource *source)
360
334
{
361
 
        char *searchtext;
362
 
 
363
 
        g_return_if_fail (header->priv->search_key != NULL);
364
 
        
365
 
        rb_debug ("gconf search text changed");
366
 
 
367
 
        searchtext = eel_gconf_get_string (header->priv->search_key);
368
 
 
369
 
        rb_search_entry_set_text (RB_SEARCH_ENTRY (header->priv->search),
370
 
                                  searchtext);
371
 
 
372
 
        rb_source_search (header->priv->selected_source, searchtext);
373
 
 
374
 
        g_free (searchtext);
 
335
        g_hash_table_remove (header->priv->source_search_text, source);
375
336
}
376
337
 
377
338
static void
381
342
{
382
343
        rb_debug  ("searching for \"%s\"", text);
383
344
 
384
 
        eel_gconf_set_string (header->priv->search_key, text);
 
345
        /* if we haven't seen the source before, monitor it for deletion */
 
346
        if (g_hash_table_lookup (header->priv->source_search_text, header->priv->selected_source) == NULL) {
 
347
                g_object_weak_ref (G_OBJECT (header->priv->selected_source),
 
348
                                   (GWeakNotify)rb_source_header_source_weak_destroy_cb,
 
349
                                   header);
 
350
        }
 
351
 
 
352
        g_hash_table_insert (header->priv->source_search_text,
 
353
                             header->priv->selected_source,
 
354
                             g_strdup (text));
 
355
        rb_source_search (header->priv->selected_source, text);
 
356
        rb_source_header_sync_control_state (header);
385
357
}
386
358
 
387
359
void
395
367
        if (header->priv->selected_source)
396
368
                rb_source_search (header->priv->selected_source, NULL);
397
369
        rb_search_entry_clear (RB_SEARCH_ENTRY (header->priv->search));
 
370
        rb_source_header_sync_control_state (header);
398
371
}
399
372
 
400
373
static void
401
 
rb_source_header_disclosure_toggled_cb (GtkToggleButton *disclosure,
 
374
rb_source_header_disclosure_toggled_cb (GObject *object,
 
375
                                        GParamSpec *param_spec,
402
376
                                        gpointer data)
403
377
{
404
378
        RBSourceHeader *header = RB_SOURCE_HEADER (data);
405
 
        gboolean disclosed = gtk_toggle_button_get_active (disclosure);
 
379
        GtkExpander *expander = GTK_EXPANDER (object);
 
380
        gboolean disclosed = gtk_expander_get_expanded (expander);
406
381
 
407
382
        rb_debug ("disclosed: %s", disclosed ? "TRUE" : "FALSE");
408
383
        
424
399
}
425
400
 
426
401
static void
427
 
rb_source_header_view_browser_changed_cb (BonoboUIComponent *component,
428
 
                                          const char *path,
429
 
                                          Bonobo_UIComponent_EventType type,
430
 
                                          const char *state,
 
402
rb_source_header_view_browser_changed_cb (GtkAction *action,
431
403
                                          RBSourceHeader *header)
432
404
{
433
405
        rb_debug ("got view browser toggle");
434
406
        eel_gconf_set_boolean (header->priv->browser_key,
435
 
                               rb_bonobo_get_active (component, CMD_PATH_VIEW_BROWSER));
 
407
                               gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)));
436
408
}
437
409
 
438
410
void
439
411
rb_source_header_sync_control_state (RBSourceHeader *header)
440
412
{
 
413
        GtkAction *viewbrowser_action;
 
414
        GtkAction *viewstatusbar_action;
 
415
        GtkAction *viewall_action;
441
416
        gboolean have_browser = header->priv->selected_source != NULL
442
417
                && header->priv->browser_key != NULL;
443
418
        gboolean not_small = !eel_gconf_get_boolean (CONF_UI_SMALL_DISPLAY);
444
419
 
445
420
        gtk_widget_set_sensitive (header->priv->disclosure,
446
421
                                  have_browser);
447
 
        rb_bonobo_set_sensitive (header->priv->component, CMD_PATH_VIEW_BROWSER,
448
 
                                have_browser && not_small);
449
 
        rb_bonobo_set_sensitive (header->priv->component, 
450
 
                                CMD_PATH_VIEW_STATUSBAR, not_small);
 
422
        viewbrowser_action = gtk_action_group_get_action (header->priv->actiongroup,
 
423
                                                          "ViewBrowser");
 
424
        g_object_set (G_OBJECT (viewbrowser_action), "sensitive",
 
425
                      have_browser && not_small, NULL);
 
426
        viewstatusbar_action = gtk_action_group_get_action (header->priv->actiongroup,
 
427
                                                            "ViewStatusbar");
 
428
        g_object_set (G_OBJECT (viewstatusbar_action), "sensitive",
 
429
                      not_small, NULL);
 
430
        viewall_action = gtk_action_group_get_action (header->priv->actiongroup,
 
431
                                                      "ViewAll");
 
432
        g_object_set (G_OBJECT (viewall_action), "sensitive",
 
433
                      have_browser && not_small, NULL);
451
434
        if (have_browser) {
452
435
                gboolean shown = eel_gconf_get_boolean (header->priv->browser_key);
453
 
                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (header->priv->disclosure),
454
 
                                              shown);
455
 
                rb_bonobo_set_active (header->priv->component,
456
 
                                      CMD_PATH_VIEW_BROWSER,
457
 
                                      shown);
 
436
                gtk_expander_set_expanded    (GTK_EXPANDER (header->priv->disclosure),
 
437
                                              shown);
 
438
                gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (viewbrowser_action),
 
439
                                              shown);
458
440
        }
459
441
}
 
442
 
 
443
static void
 
444
rb_source_header_search_activate_cb (RBSearchEntry *search,
 
445
                                     RBSourceHeader *header)
 
446
{
 
447
        RBEntryView *entry_view;
 
448
 
 
449
        entry_view = rb_source_get_entry_view (header->priv->selected_source);
 
450
        gtk_widget_grab_focus (GTK_WIDGET (entry_view));
 
451
}