hythmbox-2.98/sources/rb-display-page-group.c

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 }