No issues found
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2010 Jonathan Matthew <jonathan@d14n.org>
4 * Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * The Rhythmbox authors hereby grant permission for non-GPL compatible
12 * GStreamer plugins to be used and distributed together with GStreamer
13 * and Rhythmbox. This permission is above and beyond the permissions granted
14 * by the GPL license by which Rhythmbox is covered. If you modify this code
15 * you may extend this exception to your version of the code, but you are not
16 * obligated to do so. If you do not wish to do so, delete this exception
17 * statement from your version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 *
28 */
29
30 #include "config.h"
31
32 #include <string.h>
33 #include <glib.h>
34 #include <glib/gi18n.h>
35
36 #include "rb-util.h"
37
38 #include "rb-display-page-group.h"
39 #include "rb-display-page-tree.h"
40
41 /**
42 * SECTION:rb-display-page-group
43 * @short_description: Display page grouping
44 *
45 * Page groups define sections of the display page tree. A page group
46 * consists of an internal name, a display name, and a category.
47 * The internal name can be used to locate a registered page group.
48 * The category is used to sort the page groups.
49 *
50 * While #RBDisplayPageGroup is a subclass of #RBDisplayPage, by default page
51 * groups are never selectable so they have no content.
52 */
53
54 G_LOCK_DEFINE_STATIC (display_page_groups);
55
56 enum {
57 PROP_0,
58 PROP_ID,
59 PROP_CATEGORY,
60 PROP_LOADED
61 };
62
63 struct _RBDisplayPageGroupPrivate
64 {
65 char *id;
66 RBDisplayPageGroupCategory category;
67 gboolean loaded;
68 };
69
70 G_DEFINE_TYPE (RBDisplayPageGroup, rb_display_page_group, RB_TYPE_DISPLAY_PAGE)
71
72 static GHashTable *display_page_groups_map;
73
74 /**
75 * rb_display_page_group_add_core_groups:
76 * @shell: the #RBShell
77 * @page_model: the #RBDisplayPageModel
78 *
79 * Registers core page groups.
80 */
81 void
82 rb_display_page_group_add_core_groups (GObject *shell, RBDisplayPageModel *page_model)
83 {
84 RBDisplayPageGroup *group;
85
86 group = rb_display_page_group_new (shell, "library", _("Library"), RB_DISPLAY_PAGE_GROUP_CATEGORY_FIXED);
87 rb_display_page_model_add_page (page_model, RB_DISPLAY_PAGE (group), NULL);
88
89 group = rb_display_page_group_new (shell, "stores", _("Stores"), RB_DISPLAY_PAGE_GROUP_CATEGORY_FIXED);
90 rb_display_page_model_add_page (page_model, RB_DISPLAY_PAGE (group), NULL);
91
92 group = rb_display_page_group_new (shell, "playlists", _("Playlists"), RB_DISPLAY_PAGE_GROUP_CATEGORY_PERSISTENT);
93 rb_display_page_model_add_page (page_model, RB_DISPLAY_PAGE (group), NULL);
94
95 group = rb_display_page_group_new (shell, "devices", _("Devices"), RB_DISPLAY_PAGE_GROUP_CATEGORY_REMOVABLE);
96 rb_display_page_model_add_page (page_model, RB_DISPLAY_PAGE (group), NULL);
97 rb_display_page_group_loaded (group);
98
99 group = rb_display_page_group_new (shell, "shared", _("Shared"), RB_DISPLAY_PAGE_GROUP_CATEGORY_TRANSIENT);
100 rb_display_page_model_add_page (page_model, RB_DISPLAY_PAGE (group), NULL);
101 rb_display_page_group_loaded (group);
102 }
103
104 /**
105 * rb_display_page_group_get_by_id:
106 * @id: name of page group to find
107 *
108 * Locates a page group by name. If the page group has not been registered yet,
109 * returns NULL instead.
110 *
111 * Return value: (transfer none): existing page group, or NULL.
112 */
113 RBDisplayPageGroup *
114 rb_display_page_group_get_by_id (const char *id)
115 {
116 RBDisplayPageGroup *group;
117
118 group = NULL;
119
120 G_LOCK (display_page_groups);
121 if (display_page_groups_map) {
122 group = g_hash_table_lookup (display_page_groups_map, id);
123 }
124 G_UNLOCK (display_page_groups);
125
126 return group;
127 }
128
129 /**
130 * rb_display_page_group_loaded:
131 * @group: a #RBDisplayPageGroup
132 *
133 * Called when the page group is fully loaded, that is, all initial pages have
134 * been added.
135 */
136 void
137 rb_display_page_group_loaded (RBDisplayPageGroup *group)
138 {
139 group->priv->loaded = TRUE;
140 g_object_notify (G_OBJECT (group), "loaded");
141 }
142
143 /**
144 * rb_display_page_group_new:
145 * @shell: the #RBShell
146 * @id: name of the page group (untranslated, used in code)
147 * @name: display name of the page group (translated)
148 * @category: category for the page group
149 *
150 * Creates a new page group object. The group will be registered
151 * before it is returned.
152 *
153 * Return value: new page group
154 */
155 RBDisplayPageGroup *
156 rb_display_page_group_new (GObject *shell,
157 const char *id,
158 const char *name,
159 RBDisplayPageGroupCategory category)
160 {
161 return g_object_new (RB_TYPE_DISPLAY_PAGE_GROUP,
162 "shell", shell,
163 "id", id,
164 "name", name,
165 "category", category,
166 NULL);
167 }
168
169 static gboolean
170 impl_selectable (RBDisplayPage *page)
171 {
172 return FALSE;
173 }
174
175 static void
176 impl_activate (RBDisplayPage *page)
177 {
178 RBDisplayPageTree *display_page_tree;
179 RBShell *shell;
180
181 g_object_get (page, "shell", &shell, NULL);
182 g_object_get (shell, "display-page-tree", &display_page_tree, NULL);
183 rb_display_page_tree_toggle_expanded (display_page_tree, page);
184 g_object_unref (display_page_tree);
185 g_object_unref (shell);
186 }
187
188 /**
189 * RBDisplayPageGroupType:
190 * @RB_DISPLAY_PAGE_GROUP_CATEGORY_FIXED: Fixed single instance sources (e.g., library)
191 * @RB_DISPLAY_PAGE_GROUP_CATEGORY_PERSISTENT: Persistent multiple-instance sources (e.g. playlists)
192 * @RB_DISPLAY_PAGE_GROUP_CATEGORY_REMOVABLE: Sources representing removable devices
193 * @RB_DISPLAY_PAGE_GROUP_CATEGORY_TRANSIENT: Transient sources (e.g. network shares)
194 * @RB_DISPLAY_PAGE_GROUP_CATEGORY_TOOLS: Utility (ie non-source) pages
195 *
196 * Predefined categories of page group. The order they're defined here is the order they
197 * appear in the page tree.
198 */
199
200 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
201 GType
202 rb_display_page_group_category_get_type (void)
203 {
204 static GType etype = 0;
205
206 if (etype == 0) {
207 static const GEnumValue values[] = {
208 ENUM_ENTRY (RB_DISPLAY_PAGE_GROUP_CATEGORY_FIXED, "fixed"),
209 ENUM_ENTRY (RB_DISPLAY_PAGE_GROUP_CATEGORY_PERSISTENT, "persistent"),
210 ENUM_ENTRY (RB_DISPLAY_PAGE_GROUP_CATEGORY_REMOVABLE, "removable"),
211 ENUM_ENTRY (RB_DISPLAY_PAGE_GROUP_CATEGORY_TRANSIENT, "transient"),
212 ENUM_ENTRY (RB_DISPLAY_PAGE_GROUP_CATEGORY_TOOLS, "tools"),
213 { 0, 0, 0 }
214 };
215
216 etype = g_enum_register_static ("RBDisplayPageGroupType", values);
217 }
218
219 return etype;
220 }
221
222 static void
223 impl_finalize (GObject *object)
224 {
225 RBDisplayPageGroup *group = RB_DISPLAY_PAGE_GROUP (object);
226
227 g_free (group->priv->id);
228 /* remove from group map? can this ever happen? */
229
230 G_OBJECT_CLASS (rb_display_page_group_parent_class)->finalize (object);
231 }
232
233 static void
234 impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
235 {
236 RBDisplayPageGroup *group = RB_DISPLAY_PAGE_GROUP (object);
237 switch (prop_id) {
238 case PROP_ID:
239 g_value_set_string (value, group->priv->id);
240 break;
241 case PROP_CATEGORY:
242 g_value_set_enum (value, group->priv->category);
243 break;
244 case PROP_LOADED:
245 g_value_set_boolean (value, group->priv->loaded);
246 break;
247 default:
248 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
249 break;
250 }
251 }
252
253 static void
254 impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
255 {
256 RBDisplayPageGroup *group = RB_DISPLAY_PAGE_GROUP (object);
257 switch (prop_id) {
258 case PROP_ID:
259 group->priv->id = g_value_dup_string (value);
260 break;
261 case PROP_CATEGORY:
262 group->priv->category = g_value_get_enum (value);
263 break;
264 default:
265 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
266 break;
267 }
268 }
269
270 static void
271 impl_constructed (GObject *object)
272 {
273 RBDisplayPageGroup *group;
274
275 RB_CHAIN_GOBJECT_METHOD (rb_display_page_group_parent_class, constructed, object);
276
277 group = RB_DISPLAY_PAGE_GROUP (object);
278
279 /* register the new group */
280 G_LOCK (display_page_groups);
281 g_assert (g_hash_table_lookup (display_page_groups_map, group->priv->id) == NULL);
282 g_hash_table_insert (display_page_groups_map, g_strdup (group->priv->id), group);
283 G_UNLOCK (display_page_groups);
284 }
285
286 static void
287 rb_display_page_group_init (RBDisplayPageGroup *group)
288 {
289 group->priv = G_TYPE_INSTANCE_GET_PRIVATE (group,
290 RB_TYPE_DISPLAY_PAGE_GROUP,
291 RBDisplayPageGroupPrivate);
292 }
293
294 static void
295 rb_display_page_group_class_init (RBDisplayPageGroupClass *klass)
296 {
297 GObjectClass *object_class = G_OBJECT_CLASS (klass);
298 RBDisplayPageClass *page_class = RB_DISPLAY_PAGE_CLASS (klass);
299
300 G_LOCK (display_page_groups);
301 if (display_page_groups_map == NULL) {
302 display_page_groups_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
303 }
304 G_UNLOCK (display_page_groups);
305
306 object_class->constructed = impl_constructed;
307 object_class->finalize = impl_finalize;
308 object_class->set_property = impl_set_property;
309 object_class->get_property = impl_get_property;
310
311 page_class->selectable = impl_selectable;
312 page_class->activate = impl_activate;
313
314 /**
315 * RBDisplayPageGroup:id:
316 *
317 * Internal (untranslated) name for the page group
318 */
319 g_object_class_install_property (object_class,
320 PROP_ID,
321 g_param_spec_string ("id",
322 "identifier",
323 "identifier",
324 NULL,
325 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
326 /**
327 * RBDisplayPageGroup:category:
328 *
329 * Page group category that the group falls into
330 */
331 g_object_class_install_property (object_class,
332 PROP_CATEGORY,
333 g_param_spec_enum ("category",
334 "category",
335 "page group category",
336 RB_TYPE_DISPLAY_PAGE_GROUP_CATEGORY,
337 RB_DISPLAY_PAGE_GROUP_CATEGORY_FIXED,
338 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
339 /**
340 * RBDisplayPageProperty:loaded:
341 *
342 * Set to %TRUE once the initial set of pages have been added to the group
343 */
344 g_object_class_install_property (object_class,
345 PROP_LOADED,
346 g_param_spec_boolean ("loaded",
347 "loaded",
348 "Whether the group is loaded",
349 FALSE,
350 G_PARAM_READABLE));
351
352 g_type_class_add_private (klass, sizeof (RBDisplayPageGroupPrivate));
353 }