1 /*
2  *  Copyright (C) 2005 Marc Pavot <marc.pavot@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2, or (at your option)
7  *  any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  */
19 
20 #include "sources/ario-source-manager.h"
21 #include <gtk/gtk.h>
22 #include <string.h>
23 #include <config.h>
24 #include <glib/gi18n.h>
25 
26 #include "ario-debug.h"
27 #include "lib/ario-conf.h"
28 #include "preferences/ario-preferences.h"
29 #include "sources/ario-browser.h"
30 #include "sources/ario-search.h"
31 #include "sources/ario-storedplaylists.h"
32 #include "widgets/ario-playlist.h"
33 
34 static void ario_source_manager_sync (ArioSourceManager *sourcemanager);
35 static void ario_source_manager_showtabs_changed_cb (guint notification_id,
36                                                      ArioSourceManager *sourcemanager);
37 static gboolean ario_source_manager_button_press_cb (GtkWidget *widget,
38                                                      GdkEventButton *event,
39                                                      ArioSourceManager *sourcemanager);
40 static gboolean ario_source_manager_switch_page_cb (GtkNotebook *notebook,
41                                                     gpointer notebook_page,
42                                                     guint page,
43                                                     ArioSourceManager *sourcemanager);
44 
45 struct ArioSourceManagerPrivate
46 {
47         GSList *sources;
48 
49         ArioSource *source;
50 };
51 
52 static ArioSourceManager *instance = NULL;
53 
54 typedef struct ArioSourceData
55 {
56         ArioSource *source;
57 } ArioSourceData;
58 
59 #define ARIO_SOURCE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ARIO_TYPE_SOURCE_MANAGER, ArioSourceManagerPrivate))
G_DEFINE_TYPE(ArioSourceManager,ario_source_manager,GTK_TYPE_NOTEBOOK)60 G_DEFINE_TYPE (ArioSourceManager, ario_source_manager, GTK_TYPE_NOTEBOOK)
61 
62 static void
63 ario_source_manager_class_init (ArioSourceManagerClass *klass)
64 {
65         ARIO_LOG_FUNCTION_START;
66         /* Private attributes */
67         g_type_class_add_private (klass, sizeof (ArioSourceManagerPrivate));
68 }
69 
70 static void
ario_source_manager_init(ArioSourceManager * sourcemanager)71 ario_source_manager_init (ArioSourceManager *sourcemanager)
72 {
73         ARIO_LOG_FUNCTION_START;
74         sourcemanager->priv = ARIO_SOURCE_MANAGER_GET_PRIVATE (sourcemanager);
75 }
76 
77 GtkWidget *
ario_source_manager_get_instance(void)78 ario_source_manager_get_instance (void)
79 {
80         ARIO_LOG_FUNCTION_START;
81         GtkWidget *source;
82 
83         /* Returns singleton if already instantiated */
84         if (instance)
85                 return GTK_WIDGET (instance);
86 
87         instance = g_object_new (ARIO_TYPE_SOURCE_MANAGER,
88                                  NULL);
89         g_return_val_if_fail (instance->priv != NULL, NULL);
90 
91         /* Create browser */
92         source = ario_browser_new ();
93         ario_source_manager_append (ARIO_SOURCE (source));
94 
95 #ifdef ENABLE_SEARCH
96         /* Create search */
97         source = ario_search_new ();
98         ario_source_manager_append (ARIO_SOURCE (source));
99 #endif  /* ENABLE_SEARCH */
100 #ifdef ENABLE_STOREDPLAYLISTS
101         /* Create stored playlists source */
102         source = ario_storedplaylists_new ();
103         ario_source_manager_append (ARIO_SOURCE (source));
104 #endif  /* ENABLE_STOREDPLAYLISTS */
105 
106         /* Connect signlas for actions on notebook */
107         g_signal_connect (instance,
108                           "button_press_event",
109                           G_CALLBACK (ario_source_manager_button_press_cb),
110                           instance);
111 
112         g_signal_connect_after (instance,
113                                 "switch-page",
114                                 G_CALLBACK (ario_source_manager_switch_page_cb),
115                                 instance);
116 
117         /* Reorder sources according to preferences */
118         ario_source_manager_reorder ();
119 
120         /* Notification for preference changes */
121         ario_conf_notification_add (PREF_SHOW_TABS,
122                                     (ArioNotifyFunc) ario_source_manager_showtabs_changed_cb,
123                                     instance);
124 
125         /* Set tabs visibility according to preferences */
126         gtk_notebook_set_show_tabs (GTK_NOTEBOOK (instance),
127                                     ario_conf_get_boolean (PREF_SHOW_TABS, PREF_SHOW_TABS_DEFAULT));
128 
129         return GTK_WIDGET (instance);
130 }
131 
132 static void
ario_source_manager_shutdown_foreach(ArioSource * source,GSList ** ordered_sources)133 ario_source_manager_shutdown_foreach (ArioSource *source,
134                                       GSList **ordered_sources)
135 {
136         ARIO_LOG_FUNCTION_START;
137         /* Shutdown source */
138         ario_source_shutdown (source);
139 
140         /* Add source to ordered list */
141         *ordered_sources = g_slist_append (*ordered_sources, ario_source_get_id (source));
142 }
143 
144 void
ario_source_manager_shutdown(void)145 ario_source_manager_shutdown (void)
146 {
147         ARIO_LOG_FUNCTION_START;
148         GSList *ordered_sources = NULL;
149 
150         /* Save current active page */
151         ario_conf_set_integer (PREF_SOURCE,
152                                gtk_notebook_get_current_page (GTK_NOTEBOOK (instance)));
153 
154         /* Shutdown each source and get an ordered list of sources */
155         gtk_container_foreach (GTK_CONTAINER (instance),
156                                (GtkCallback) ario_source_manager_shutdown_foreach,
157                                &ordered_sources);
158 
159         /* Save ordered list of sources */
160         ario_conf_set_string_slist (PREF_SOURCE_LIST, ordered_sources);
161         g_slist_free (ordered_sources);
162 }
163 
164 void
ario_source_manager_goto_playling_song(void)165 ario_source_manager_goto_playling_song (void)
166 {
167         ARIO_LOG_FUNCTION_START;
168         /* Go to playing song on active source */
169         if (instance->priv->source) {
170                 ario_source_goto_playling_song (instance->priv->source);
171         }
172 }
173 
174 void
ario_source_manager_reorder(void)175 ario_source_manager_reorder (void)
176 {
177         ARIO_LOG_FUNCTION_START;
178         int i = 0;
179         ArioSourceData *data;
180         GSList *ordered_tmp;
181         GSList *sources_tmp;
182         GSList *ordered_sources = ario_conf_get_string_slist (PREF_SOURCE_LIST, PREF_SOURCE_LIST_DEFAULT);
183 
184         /* For each source in preferences */
185         for (ordered_tmp = ordered_sources; ordered_tmp; ordered_tmp = g_slist_next (ordered_tmp)) {
186                 /* For each registered source */
187                 for (sources_tmp = instance->priv->sources; sources_tmp; sources_tmp = g_slist_next (sources_tmp)) {
188                         data = sources_tmp->data;
189                         if (!strcmp (ario_source_get_id (data->source), ordered_tmp->data)) {
190                                 /* Move source tab according to preferences */
191                                 gtk_notebook_reorder_child (GTK_NOTEBOOK (instance),
192                                                             GTK_WIDGET (data->source), i);
193                                 break;
194                         }
195                 }
196                 ++i;
197         }
198 
199         g_slist_foreach (ordered_sources, (GFunc) g_free, NULL);
200         g_slist_free (ordered_sources);
201 
202         ario_source_manager_sync (instance);
203 }
204 
205 static void
ario_source_manager_sync(ArioSourceManager * sourcemanager)206 ario_source_manager_sync (ArioSourceManager *sourcemanager)
207 {
208         ARIO_LOG_FUNCTION_START;
209         gint page;
210 
211         /* Select active page according to preferences */
212         page = ario_conf_get_integer (PREF_SOURCE, PREF_SOURCE_DEFAULT);
213         gtk_notebook_set_current_page (GTK_NOTEBOOK (sourcemanager), page);
214 }
215 
216 static void
ario_source_manager_showtabs_changed_cb(guint notification_id,ArioSourceManager * sourcemanager)217 ario_source_manager_showtabs_changed_cb (guint notification_id,
218                                          ArioSourceManager *sourcemanager)
219 {
220         ARIO_LOG_FUNCTION_START;
221         /* Set tabs visibility */
222         gtk_notebook_set_show_tabs (GTK_NOTEBOOK (sourcemanager),
223                                     ario_conf_get_boolean (PREF_SHOW_TABS, PREF_SHOW_TABS_DEFAULT));
224 }
225 
226 static void
ario_source_manager_set_source_active(ArioSource * source,gboolean active)227 ario_source_manager_set_source_active (ArioSource *source,
228                                        gboolean active)
229 {
230         ARIO_LOG_FUNCTION_START;
231         gchar *conf_name;
232 
233         /* Set source activity in preferences */
234         conf_name = g_strconcat (ario_source_get_id (source), "-active", NULL);
235         ario_conf_set_boolean (conf_name, active);
236         g_free (conf_name);
237 
238         if (active) {
239                 /* Show source */
240                 gtk_widget_set_no_show_all (GTK_WIDGET (source), FALSE);
241                 gtk_widget_show_all (GTK_WIDGET (source));
242                 gtk_widget_set_no_show_all (GTK_WIDGET (source), TRUE);
243         } else {
244                 /* Hide source */
245                 gtk_widget_hide (GTK_WIDGET (source));
246         }
247 }
248 
249 static void
ario_source_manager_menu_cb(GtkCheckMenuItem * checkmenuitem,ArioSource * source)250 ario_source_manager_menu_cb (GtkCheckMenuItem *checkmenuitem,
251                              ArioSource *source)
252 {
253         ARIO_LOG_FUNCTION_START;
254         /* Select source as in menu */
255         ario_source_manager_set_source_active (source, gtk_check_menu_item_get_active (checkmenuitem));
256 }
257 
258 void
ario_source_manager_append(ArioSource * source)259 ario_source_manager_append (ArioSource *source)
260 {
261         ARIO_LOG_FUNCTION_START;
262         GtkWidget *hbox;
263         gchar *conf_name;
264         ArioSourceData *data;
265 
266         /* Create hbox for tab header */
267         hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
268 
269         /* Add source icon to hbox */
270         gtk_box_pack_start (GTK_BOX (hbox),
271                             gtk_image_new_from_icon_name (ario_source_get_icon (source), GTK_ICON_SIZE_MENU),
272                             TRUE, TRUE, 0);
273 
274         /* Add source name to hbox */
275         gtk_box_pack_start (GTK_BOX (hbox),
276                             gtk_label_new (ario_source_get_name (source)),
277                             TRUE, TRUE, 0);
278 
279         /* Append source to source-manager */
280         gtk_widget_show_all (hbox);
281         gtk_notebook_append_page (GTK_NOTEBOOK (instance),
282                                   GTK_WIDGET (source),
283                                   hbox);
284 
285         gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (instance),
286                                           GTK_WIDGET (source),
287                                           TRUE);
288 
289         /* Show/hide source depending on preferences */
290         conf_name = g_strconcat (ario_source_get_id (source), "-active", NULL);
291         if (ario_conf_get_boolean (conf_name, TRUE))
292                 gtk_widget_show_all (GTK_WIDGET (source));
293         else
294                 gtk_widget_hide (GTK_WIDGET (source));
295         gtk_widget_set_no_show_all (GTK_WIDGET (source), TRUE);
296         g_free (conf_name);
297 
298         /* Add source data to list */
299         data = (ArioSourceData *) g_malloc (sizeof (ArioSourceData));
300         data->source = source;
301 
302         instance->priv->sources = g_slist_append (instance->priv->sources, data);
303 }
304 
305 void
ario_source_manager_remove(ArioSource * source)306 ario_source_manager_remove (ArioSource *source)
307 {
308         ARIO_LOG_FUNCTION_START;
309         GSList *tmp;
310         ArioSourceData *data;
311 
312         /* Shutdown source */
313         ario_source_shutdown (source);
314 
315         if (instance->priv->source == source)
316                 instance->priv->source = NULL;
317 
318         /* For each source */
319         for (tmp = instance->priv->sources; tmp; tmp = g_slist_next (tmp)) {
320                 data = tmp->data;
321                 /* Get source to remove */
322                 if (data->source == source) {
323                         /* Remove the source from the list */
324                         instance->priv->sources = g_slist_remove (instance->priv->sources, data);
325                         g_free (data);
326                         break;
327                 }
328         }
329         /* Remove source from notebook */
330         gtk_container_remove (GTK_CONTAINER (instance), GTK_WIDGET (source));
331 }
332 
333 static gboolean
ario_source_manager_button_press_cb(GtkWidget * widget,GdkEventButton * event,ArioSourceManager * sourcemanager)334 ario_source_manager_button_press_cb (GtkWidget *widget,
335                                      GdkEventButton *event,
336                                      ArioSourceManager *sourcemanager)
337 {
338         ARIO_LOG_FUNCTION_START;
339         GtkWidget *menu;
340         GtkWidget *item;
341         GSList *tmp;
342         ArioSourceData *data;
343         gchar *conf_name;
344 
345         if (event->button == 3) {
346                 /* Third button: Show popup menu */
347                 menu = gtk_menu_new ();
348 
349                 for (tmp = sourcemanager->priv->sources; tmp; tmp = g_slist_next (tmp)) {
350                         /* Build menu with each source */
351                         data = tmp->data;
352 
353                         item = gtk_check_menu_item_new_with_label (ario_source_get_name (data->source));
354                         conf_name = g_strconcat (ario_source_get_id (data->source), "-active", NULL);
355                         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
356                                                         ario_conf_get_boolean (conf_name, TRUE));
357                         g_free (conf_name);
358 
359                         /* Connect signal for activation/deactivation of sources in popup menu */
360                         g_signal_connect (item, "toggled",
361                                           G_CALLBACK (ario_source_manager_menu_cb), data->source);
362                         gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
363                 }
364 
365                 /* Show popup menu */
366                 gtk_widget_show_all (menu);
367                 gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
368         }
369 
370         return FALSE;
371 }
372 
373 static gboolean
ario_source_manager_switch_page_cb(GtkNotebook * notebook,gpointer notebook_page,guint page,ArioSourceManager * sourcemanager)374 ario_source_manager_switch_page_cb (GtkNotebook *notebook,
375                                     gpointer notebook_page,
376                                     guint page,
377                                     ArioSourceManager *sourcemanager)
378 {
379         ARIO_LOG_FUNCTION_START;
380         ArioSource *new_source;
381 
382         /* Call unselect on previous source */
383         if (sourcemanager->priv->source) {
384                 ario_source_unselect (sourcemanager->priv->source);
385         }
386 
387         /* Call select on new source */
388         new_source = ARIO_SOURCE (gtk_notebook_get_nth_page (notebook, page));
389         if (new_source)
390                 ario_source_select (new_source);
391 
392         sourcemanager->priv->source = new_source;
393 
394         return FALSE;
395 }
396