1 /*****************************************************************
2  * gmerlin - a general purpose multimedia framework and applications
3  *
4  * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5  * gmerlin-general@lists.sourceforge.net
6  * http://gmerlin.sourceforge.net
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  * *****************************************************************/
21 
22 #include <config.h>
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include <gmerlin/utils.h>
27 
28 
29 #include "gtk_dialog.h"
30 #include <gui_gtk/gtkutils.h>
31 
32 enum
33 {
34   COLUMN_DEVICE,
35   NUM_COLUMNS
36 };
37 
38 typedef struct
39   {
40   GtkWidget    * treeview;
41 
42   GtkWidget * add_button;
43   GtkWidget * delete_button;
44   GtkWidget * scrolled;
45   GtkWidget * fileselect;
46   int selected;
47   } device_t;
48 
get_value(bg_gtk_widget_t * w)49 static void get_value(bg_gtk_widget_t * w)
50   {
51   int i;
52   device_t * priv;
53   GtkTreeSelection * selection;
54   GtkTreeIter iter;
55   GtkTreeModel * model;
56   char ** tmp_items;
57 
58   priv = (device_t*)(w->priv);
59 
60   model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview));
61   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview));
62 
63   gtk_list_store_clear(GTK_LIST_STORE(model));
64 
65   if(!w->value.val_str || (*w->value.val_str == '\0'))
66     return;
67 
68   tmp_items = bg_strbreak(w->value.val_str, ' ');
69 
70 
71   i = 0;
72 
73   while(tmp_items[i])
74     {
75     gtk_list_store_append(GTK_LIST_STORE(model), &iter);
76     gtk_list_store_set(GTK_LIST_STORE(model), &iter,
77                        COLUMN_DEVICE,
78                        tmp_items[i],
79                        -1);
80     if(!i)
81       gtk_tree_selection_select_iter(selection, &iter);
82 
83     i++;
84     }
85   bg_strbreak_free(tmp_items);
86   }
87 
set_value(bg_gtk_widget_t * w)88 static void set_value(bg_gtk_widget_t * w)
89   {
90   device_t * priv;
91   GtkTreeSelection * selection;
92   GtkTreeIter iter;
93   GtkTreeModel * model;
94 
95   int num_entries;
96   int selected;
97   char ** strings;
98   int len;
99   int index;
100   int i, imax;
101 
102   priv = (device_t*)(w->priv);
103 
104   model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview));
105 
106   if(!gtk_tree_model_get_iter_first(model, &iter))
107     {
108     if(w->value.val_str)
109       {
110       free(w->value.val_str);
111       w->value.val_str = NULL;
112       }
113     return;
114     }
115   num_entries = 1;
116   while(gtk_tree_model_iter_next(model, &iter))
117     num_entries++;
118 
119   /* Copy the strings */
120 
121   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview));
122 
123   strings = malloc(num_entries * sizeof(char*));
124 
125   len = 0;
126   selected = -1;
127 
128   gtk_tree_model_get_iter_first(model, &iter);
129   for(i = 0; i < num_entries; i++)
130     {
131     gtk_tree_model_get(model, &iter,
132                        COLUMN_DEVICE,
133                        &strings[i],
134                        -1);
135     if(gtk_tree_selection_iter_is_selected(selection,
136                                            &iter))
137       {
138       selected = i;
139       }
140     gtk_tree_model_iter_next(model, &iter);
141     len += strlen(strings[i])+1;
142     }
143 
144   /* Copy to the value */
145 
146   if(w->value.val_str)
147     free(w->value.val_str);
148   w->value.val_str = malloc(len);
149   w->value.val_str[0] = '\0';
150 
151 
152   if(selected >= 0)
153     {
154     strcat(w->value.val_str, strings[selected]);
155     if(num_entries > 1)
156       strcat(w->value.val_str, " ");
157     imax = num_entries-1;
158     }
159   else
160     imax = num_entries;
161   index = 0;
162 
163   for(i = 0; i < imax; i++)
164     {
165     if(index == selected)
166       index++;
167     strcat(w->value.val_str, strings[index]);
168     if(i < imax - 1)
169       strcat(w->value.val_str, ":");
170     index++;
171     }
172   for(i = 0; i < num_entries; i++)
173     {
174     g_free(strings[i]);
175     }
176   free(strings);
177   }
178 
destroy(bg_gtk_widget_t * w)179 static void destroy(bg_gtk_widget_t * w)
180   {
181   device_t * priv = (device_t*)w->priv;
182   if(priv->fileselect)
183     gtk_widget_destroy(priv->fileselect);
184   free(priv);
185   }
186 
attach(void * priv,GtkWidget * table,int * row,int * num_columns)187 static void attach(void * priv, GtkWidget * table,
188                    int * row,
189                    int * num_columns)
190   {
191   device_t * f = (device_t*)priv;
192   if(*num_columns < 3)
193     *num_columns = 3;
194 
195   gtk_table_resize(GTK_TABLE(table), *row+3, *num_columns);
196 
197   gtk_table_attach_defaults(GTK_TABLE(table), f->scrolled,
198                             0, 2, *row, *row+3);
199 
200   gtk_table_attach(GTK_TABLE(table), f->add_button,
201                    2, 3, *row, *row+1, GTK_FILL, GTK_SHRINK, 0, 0);
202 
203   gtk_table_attach(GTK_TABLE(table), f->delete_button,
204                    2, 3, *row+1, *row+2, GTK_FILL, GTK_SHRINK, 0, 0);
205   *row += 3;
206   }
207 
208 static const gtk_widget_funcs_t funcs =
209   {
210     .get_value = get_value,
211     .set_value = set_value,
212     .destroy =   destroy,
213     .attach =    attach
214   };
215 
216 static void
fileselect_callback(GtkWidget * chooser,gint response_id,gpointer data)217 fileselect_callback(GtkWidget *chooser,
218                     gint       response_id,
219                     gpointer data)
220   {
221   device_t * priv;
222   GtkTreeIter iter;
223   gchar *uri;
224   priv = (device_t*)data;
225 
226   if(response_id == GTK_RESPONSE_OK)
227     {
228     GtkTreeModel * model;
229     uri = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER (chooser));
230 
231     model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->treeview));
232 
233     gtk_list_store_append(GTK_LIST_STORE(model), &iter);
234     gtk_list_store_set(GTK_LIST_STORE(model), &iter,
235                        COLUMN_DEVICE,
236                        uri,
237                        -1);
238     g_free (uri);
239     }
240   //  gtk_widget_destroy (chooser);
241 
242   gtk_widget_hide(priv->fileselect);
243   gtk_main_quit();
244   }
245 
246 static gboolean
fileselect_delete_callback(GtkWidget * w,GdkEventAny * event,gpointer data)247 fileselect_delete_callback(GtkWidget * w, GdkEventAny * event,
248                            gpointer data)
249   {
250   fileselect_callback(w, GTK_RESPONSE_CANCEL, data);
251   return TRUE;
252   }
253 
button_callback(GtkWidget * w,gpointer data)254 static void button_callback(GtkWidget * w, gpointer data)
255   {
256   device_t * priv;
257   GtkTreeSelection * selection;
258   GtkTreeModel * model;
259   GtkWidget * toplevel;
260   GtkTreeIter iter;
261 
262   priv = (device_t*)data;
263 
264   if(w == priv->add_button)
265     {
266     if(!priv->fileselect)
267       {
268       toplevel = bg_gtk_get_toplevel(w);
269 
270       priv->fileselect =
271         gtk_file_chooser_dialog_new (TRD("Select a device", PACKAGE),
272                                      GTK_WINDOW(toplevel),
273                                      GTK_FILE_CHOOSER_ACTION_OPEN,
274                                      GTK_STOCK_CANCEL,
275                                      GTK_RESPONSE_CANCEL,
276                                      GTK_STOCK_OK, GTK_RESPONSE_OK,
277                                      NULL);
278 
279       gtk_window_set_modal(GTK_WINDOW(priv->fileselect), TRUE);
280 
281       g_signal_connect(priv->fileselect, "response",
282                        G_CALLBACK(fileselect_callback),
283                        (gpointer)priv);
284       g_signal_connect(G_OBJECT(priv->fileselect), "delete_event",
285                        G_CALLBACK(fileselect_delete_callback),
286                        (gpointer)priv);
287       }
288     gtk_widget_show(priv->fileselect);
289     gtk_main();
290     }
291   else if(w == priv->delete_button)
292     {
293     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview));
294     if(!gtk_tree_selection_get_selected(selection, &model, &iter))
295       return;
296     gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
297     }
298   }
299 
bg_gtk_create_device(bg_gtk_widget_t * w,const char * translation_domain)300 void bg_gtk_create_device(bg_gtk_widget_t * w,
301                           const char * translation_domain)
302   {
303   GtkListStore *store;
304   GtkCellRenderer *renderer;
305   GtkTreeViewColumn *column;
306   GtkTreeSelection * selection;
307   device_t * priv = calloc(1, sizeof(*priv));
308 
309   priv->selected = -1;
310 
311   store = gtk_list_store_new (NUM_COLUMNS,
312 			      G_TYPE_STRING);
313 
314   priv->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
315 
316   if(w->info->help_string)
317     {
318     bg_gtk_tooltips_set_tip(priv->treeview,
319                             w->info->help_string, translation_domain);
320     }
321 
322 
323   /* Add the columns */
324 
325   renderer = gtk_cell_renderer_text_new ();
326   column = gtk_tree_view_column_new_with_attributes ("Devices",
327 						     renderer,
328 						     "text",
329 						     COLUMN_DEVICE,
330 						     NULL);
331   gtk_tree_view_column_set_sort_column_id (column, COLUMN_DEVICE);
332   gtk_tree_view_append_column (GTK_TREE_VIEW(priv->treeview), column);
333 
334   /* Set Selection mode */
335 
336   selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->treeview));
337   gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
338 
339   priv->add_button = gtk_button_new_with_label(TR("Add..."));
340   priv->delete_button = gtk_button_new_with_label(TR("Delete"));
341 
342   g_signal_connect(G_OBJECT(priv->add_button), "clicked",
343                    G_CALLBACK(button_callback),
344                    (gpointer)priv);
345   g_signal_connect(G_OBJECT(priv->delete_button), "clicked",
346                    G_CALLBACK(button_callback),
347                    (gpointer)priv);
348 
349   gtk_widget_show(priv->add_button);
350   gtk_widget_show(priv->delete_button);
351 
352   gtk_widget_show(priv->treeview);
353 
354   priv->scrolled =
355     gtk_scrolled_window_new(gtk_tree_view_get_hadjustment(GTK_TREE_VIEW(priv->treeview)),
356                             gtk_tree_view_get_vadjustment(GTK_TREE_VIEW(priv->treeview)));
357 
358   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(priv->scrolled),
359                                  GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
360   gtk_container_add(GTK_CONTAINER(priv->scrolled), priv->treeview);
361   gtk_widget_show(priv->scrolled);
362   w->funcs = &funcs;
363   w->priv = priv;
364   }
365