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
23 #include <config.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28
29 #include <string.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <gtk/gtk.h>
33 #include <gmerlin/pluginregistry.h>
34 #include <gui_gtk/fileselect.h>
35 #include <gui_gtk/question.h>
36 #include <gui_gtk/gtkutils.h>
37 #include <gui_gtk/plugin.h>
38
39 #include <gmerlin/utils.h>
40
41 struct bg_gtk_filesel_s
42 {
43 GtkWidget * filesel;
44 GtkWidget * plugin_menu;
45 bg_gtk_plugin_menu_t * plugins;
46 void (*add_files)(char ** files, const char * plugin,
47 int prefer_edl, void * data);
48
49 void (*add_dir)(char * dir, int recursive, int subdirs_as_subalbums,
50 int watch, const char * plugin, int prefer_edl,
51 void * data);
52
53 void (*close_notify)(bg_gtk_filesel_t * f, void * data);
54
55 void * callback_data;
56
57 char * cwd;
58 int is_modal;
59
60 int unsensitive;
61
62 GtkWidget * recursive;
63 GtkWidget * subdirs_as_subalbums;
64 GtkWidget * watch;
65 GtkWidget * prefer_edl;
66 };
67
add_files(bg_gtk_filesel_t * f)68 static void add_files(bg_gtk_filesel_t * f)
69 {
70 char ** filenames;
71 GSList * file_list;
72 GSList * tmp;
73
74 const char * plugin = NULL;
75 int num, i;
76
77 if(f->plugins)
78 plugin = bg_gtk_plugin_menu_get_plugin(f->plugins);
79
80 file_list =
81 gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(f->filesel));
82
83 num = g_slist_length(file_list);
84
85 filenames = calloc(num+1, sizeof(*filenames));
86
87 tmp = file_list;
88
89 for(i = 0; i < num; i++)
90 {
91 filenames[i] = (char*)tmp->data;
92 tmp = tmp->next;
93 }
94
95 f->unsensitive = 1;
96 gtk_widget_set_sensitive(f->filesel, 0);
97 f->add_files(filenames, plugin,
98 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(f->prefer_edl)),
99 f->callback_data);
100 gtk_widget_set_sensitive(f->filesel, 1);
101 f->unsensitive = 0;
102
103 g_slist_foreach(file_list, (GFunc)g_free, NULL);
104 g_slist_free(file_list);
105
106 free(filenames);
107 }
108
add_dir(bg_gtk_filesel_t * f)109 static void add_dir(bg_gtk_filesel_t * f)
110 {
111 const char * plugin = NULL;
112 char * tmp =
113 gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(f->filesel));
114
115 if(f->plugins)
116 plugin = bg_gtk_plugin_menu_get_plugin(f->plugins);
117
118 f->unsensitive = 1;
119 gtk_widget_set_sensitive(f->filesel, 0);
120 f->add_dir(tmp,
121 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(f->recursive)),
122 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(f->subdirs_as_subalbums)),
123 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(f->watch)),
124 plugin,
125 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(f->prefer_edl)),
126 f->callback_data);
127 gtk_widget_set_sensitive(f->filesel, 1);
128 f->unsensitive = 0;
129 g_free(tmp);
130 }
131
132 static void
fileselect_callback(GtkWidget * chooser,gint response_id,gpointer data)133 fileselect_callback(GtkWidget *chooser,
134 gint response_id,
135 gpointer data)
136 {
137 bg_gtk_filesel_t * f;
138 f = (bg_gtk_filesel_t *)data;
139 if(f->unsensitive)
140 return;
141
142 if(response_id == GTK_RESPONSE_OK)
143 {
144 if(f->add_files)
145 add_files(f);
146 else if(f->add_dir)
147 add_dir(f);
148 }
149 else
150 {
151 gtk_widget_hide(f->filesel);
152 if(f->is_modal)
153 gtk_main_quit();
154
155 if(f->close_notify)
156 f->close_notify(f, f->callback_data);
157 bg_gtk_filesel_destroy(f);
158 }
159 }
160
161 #if 0
162 static gboolean delete_callback(GtkWidget * w, GdkEventAny * event,
163 gpointer data)
164 {
165 fileselect_callback(w, GTK_RESPONSE_CANCEL, data);
166 return TRUE;
167 }
168
169 static gboolean destroy_callback(GtkWidget * w, GdkEvent * event,
170 gpointer data)
171 {
172 fileselect_callback(w, GTK_RESPONSE_CANCEL, data);
173 return TRUE;
174 }
175 #endif
176
177 static bg_gtk_filesel_t *
filesel_create(const char * title,void (* add_files)(char ** files,const char * plugin,int prefer_edl,void * data),void (* add_dir)(char * dir,int recursive,int subdirs_as_subalbums,int watch,const char * plugin,int prefer_edl,void * data),void (* close_notify)(bg_gtk_filesel_t *,void * data),void * user_data,GtkWidget * parent_window,bg_plugin_registry_t * plugin_reg,int type_mask,int flag_mask)178 filesel_create(const char * title,
179 void (*add_files)(char ** files, const char * plugin,
180 int prefer_edl,
181 void * data),
182 void (*add_dir)(char * dir, int recursive,
183 int subdirs_as_subalbums,
184 int watch,
185 const char * plugin,
186 int prefer_edl,
187 void * data),
188 void (*close_notify)(bg_gtk_filesel_t *,
189 void * data),
190 void * user_data,
191 GtkWidget * parent_window, bg_plugin_registry_t * plugin_reg,
192 int type_mask, int flag_mask)
193 {
194 bg_gtk_filesel_t * ret;
195
196 GtkWidget * extra = NULL;
197
198 ret = calloc(1, sizeof(*ret));
199
200 parent_window = bg_gtk_get_toplevel(parent_window);
201
202 /* Create fileselection */
203
204 if(add_files)
205 {
206 ret->filesel =
207 gtk_file_chooser_dialog_new(title,
208 GTK_WINDOW(parent_window),
209 GTK_FILE_CHOOSER_ACTION_OPEN,
210 GTK_STOCK_CLOSE,
211 GTK_RESPONSE_CANCEL,
212 GTK_STOCK_ADD, GTK_RESPONSE_OK,
213 NULL);
214 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(ret->filesel),
215 TRUE);
216 }
217 else if(add_dir)
218 {
219 ret->filesel =
220 gtk_file_chooser_dialog_new(title,
221 GTK_WINDOW(parent_window),
222 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
223 GTK_STOCK_CLOSE,
224 GTK_RESPONSE_CANCEL,
225 GTK_STOCK_ADD, GTK_RESPONSE_OK,
226 NULL);
227
228
229 extra = gtk_vbox_new(FALSE, 5);
230
231 ret->recursive =
232 gtk_check_button_new_with_label(TR("Recursive"));
233 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ret->recursive), 1);
234
235 gtk_widget_show(ret->recursive);
236 bg_gtk_box_pack_start_defaults(GTK_BOX(extra),
237 ret->recursive);
238
239 ret->subdirs_as_subalbums =
240 gtk_check_button_new_with_label(TR("Add subdirectories as subalbums"));
241 gtk_widget_show(ret->subdirs_as_subalbums);
242 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ret->subdirs_as_subalbums), 1);
243
244 ret->watch =
245 gtk_check_button_new_with_label(TR("Watch directories"));
246 gtk_widget_show(ret->watch);
247
248 bg_gtk_box_pack_start_defaults(GTK_BOX(extra),
249 ret->subdirs_as_subalbums);
250 bg_gtk_box_pack_start_defaults(GTK_BOX(extra),
251 ret->watch);
252 }
253
254 gtk_window_set_default_size(GTK_WINDOW(ret->filesel), 400, 400);
255
256 /* Create plugin menu */
257
258 if(plugin_reg)
259 {
260 if(!extra)
261 extra = gtk_vbox_new(FALSE, 5);
262
263 ret->plugins = bg_gtk_plugin_menu_create(1, plugin_reg, type_mask,
264 flag_mask);
265
266 bg_gtk_box_pack_start_defaults(GTK_BOX(extra),
267 bg_gtk_plugin_menu_get_widget(ret->plugins));
268 ret->prefer_edl =
269 gtk_check_button_new_with_label(TR("Prefer EDL"));
270 gtk_widget_show(ret->prefer_edl);
271
272 bg_gtk_box_pack_start_defaults(GTK_BOX(extra),
273 ret->prefer_edl);
274
275 }
276
277 if(extra)
278 {
279 gtk_widget_show(extra);
280 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(ret->filesel), extra);
281 }
282
283 /* Set callbacks */
284 #if 0
285 g_signal_connect(G_OBJECT(ret->filesel), "delete_event",
286 G_CALLBACK(delete_callback), ret);
287 #endif
288 g_signal_connect(ret->filesel, "response",
289 G_CALLBACK(fileselect_callback),
290 (gpointer)ret);
291
292 ret->add_files = add_files;
293 ret->add_dir = add_dir;
294 ret->close_notify = close_notify;
295 ret->callback_data = user_data;
296
297 return ret;
298 }
299
300 bg_gtk_filesel_t *
bg_gtk_filesel_create(const char * title,void (* add_file)(char ** files,const char * plugin,int prefer_edl,void * data),void (* close_notify)(bg_gtk_filesel_t *,void * data),void * user_data,GtkWidget * parent_window,bg_plugin_registry_t * plugin_reg,int type_mask,int flag_mask)301 bg_gtk_filesel_create(const char * title,
302 void (*add_file)(char ** files, const char * plugin,
303 int prefer_edl,
304 void * data),
305 void (*close_notify)(bg_gtk_filesel_t *,
306 void * data),
307 void * user_data,
308 GtkWidget * parent_window,
309 bg_plugin_registry_t * plugin_reg,
310 int type_mask, int flag_mask)
311 {
312 return filesel_create(title,
313 add_file,
314 NULL,
315 close_notify,
316 user_data,
317 parent_window, plugin_reg, type_mask, flag_mask);
318 }
319
320 bg_gtk_filesel_t *
bg_gtk_dirsel_create(const char * title,void (* add_dir)(char * dir,int recursive,int subdirs_as_subalbums,int watch,const char * plugin,int prefer_edl,void * data),void (* close_notify)(bg_gtk_filesel_t *,void * data),void * user_data,GtkWidget * parent_window,bg_plugin_registry_t * plugin_reg,int type_mask,int flag_mask)321 bg_gtk_dirsel_create(const char * title,
322 void (*add_dir)(char * dir, int recursive,
323 int subdirs_as_subalbums,
324 int watch,
325 const char * plugin,
326 int prefer_edl,
327 void * data),
328 void (*close_notify)(bg_gtk_filesel_t *,
329 void * data),
330 void * user_data,
331 GtkWidget * parent_window,
332 bg_plugin_registry_t * plugin_reg,
333 int type_mask, int flag_mask)
334 {
335 return filesel_create(title,
336 NULL,
337 add_dir,
338 close_notify,
339 user_data,
340 parent_window, plugin_reg,
341 type_mask, flag_mask);
342 }
343
344 /* Destroy fileselector */
345
bg_gtk_filesel_destroy(bg_gtk_filesel_t * filesel)346 void bg_gtk_filesel_destroy(bg_gtk_filesel_t * filesel)
347 {
348 if(filesel->cwd)
349 g_free(filesel->cwd);
350 // g_object_unref(G_OBJECT(filesel));
351 free(filesel);
352 }
353
354 /* Show the window */
355
bg_gtk_filesel_run(bg_gtk_filesel_t * filesel,int modal)356 void bg_gtk_filesel_run(bg_gtk_filesel_t * filesel, int modal)
357 {
358 gtk_window_set_modal(GTK_WINDOW(filesel->filesel), modal);
359
360 gtk_widget_show(filesel->filesel);
361 filesel->is_modal = modal;
362 if(modal)
363 gtk_main();
364
365 }
366
367 /* Get the current working directory */
368
bg_gtk_filesel_set_directory(bg_gtk_filesel_t * filesel,const char * dir)369 void bg_gtk_filesel_set_directory(bg_gtk_filesel_t * filesel,
370 const char * dir)
371 {
372 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filesel->filesel), dir);
373 }
374
bg_gtk_filesel_get_directory(bg_gtk_filesel_t * filesel)375 const char * bg_gtk_filesel_get_directory(bg_gtk_filesel_t * filesel)
376 {
377 if(filesel->cwd)
378 g_free(filesel->cwd);
379 filesel->cwd =
380 gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(filesel->filesel));
381 return filesel->cwd;
382 }
383
384 /*
385 * Create a temporary fileselector and ask
386 * for a file to save something
387 *
388 * Return value should be freed with free();
389 */
390
391 typedef struct
392 {
393 GtkWidget * w;
394 int answer;
395 } filesel_write_struct;
396
397 static void
write_callback(GtkWidget * chooser,gint response_id,gpointer data)398 write_callback(GtkWidget *chooser,
399 gint response_id,
400 gpointer data)
401 {
402 filesel_write_struct * ws;
403
404 ws = (filesel_write_struct*)data;
405
406 if(response_id == GTK_RESPONSE_OK)
407 ws->answer = 1;
408
409 gtk_widget_hide(ws->w);
410 gtk_main_quit();
411 }
412
write_delete_callback(GtkWidget * w,GdkEventAny * evt,gpointer data)413 static gboolean write_delete_callback(GtkWidget * w,
414 GdkEventAny * evt,
415 gpointer data)
416 {
417 write_callback(w, GTK_RESPONSE_CANCEL, data);
418 return TRUE;
419 }
420
bg_gtk_get_filename_write(const char * title,char ** directory,int ask_overwrite,GtkWidget * parent)421 char * bg_gtk_get_filename_write(const char * title,
422 char ** directory,
423 int ask_overwrite, GtkWidget * parent)
424 {
425 char * ret;
426 char * tmp_string;
427 filesel_write_struct f;
428
429 ret = NULL;
430
431 parent = bg_gtk_get_toplevel(parent);
432
433 f.w =
434 gtk_file_chooser_dialog_new(title,
435 GTK_WINDOW(parent),
436 GTK_FILE_CHOOSER_ACTION_SAVE,
437 GTK_STOCK_CANCEL,
438 GTK_RESPONSE_CANCEL,
439 GTK_STOCK_OK, GTK_RESPONSE_OK,
440 NULL);
441 if(ask_overwrite)
442 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(f.w),
443 TRUE);
444 /* Set attributes */
445
446 gtk_window_set_modal(GTK_WINDOW(f.w), 1);
447 f.answer = 0;
448
449 /* Set callbacks */
450
451 g_signal_connect(G_OBJECT(f.w), "delete_event",
452 G_CALLBACK(write_delete_callback),
453 (gpointer)(&f));
454 g_signal_connect(G_OBJECT(f.w), "response",
455 G_CALLBACK(write_callback),
456 (gpointer)(&f));
457
458
459 /* Set the current directory */
460
461 if(directory && *directory)
462 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(f.w),
463 *directory);
464
465 /* Run the widget */
466
467 gtk_widget_show(f.w);
468 gtk_main();
469
470 /* Fetch the answer */
471
472 if(!f.answer)
473 {
474 gtk_widget_destroy(f.w);
475 return NULL;
476 }
477
478 tmp_string = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(f.w));
479 ret = bg_strdup(NULL, tmp_string);
480 g_free(tmp_string);
481
482 /* Update current directory */
483
484 if(directory)
485 {
486 tmp_string = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(f.w));
487 *directory = bg_strdup(*directory, tmp_string);
488 g_free(tmp_string);
489 }
490
491 return ret;
492 }
493
bg_gtk_get_filename_read(const char * title,char ** directory,GtkWidget * parent)494 char * bg_gtk_get_filename_read(const char * title,
495 char ** directory, GtkWidget * parent)
496 {
497 char * ret;
498 char * tmp_string;
499 filesel_write_struct f;
500
501 ret = NULL;
502
503 parent = bg_gtk_get_toplevel(parent);
504
505 f.w =
506 gtk_file_chooser_dialog_new(title,
507 GTK_WINDOW(parent),
508 GTK_FILE_CHOOSER_ACTION_OPEN,
509 GTK_STOCK_CANCEL,
510 GTK_RESPONSE_CANCEL,
511 GTK_STOCK_OK, GTK_RESPONSE_OK,
512 NULL);
513
514 /* Set attributes */
515
516 gtk_window_set_modal(GTK_WINDOW(f.w), 1);
517 f.answer = 0;
518
519 /* Set callbacks */
520
521 g_signal_connect(G_OBJECT(f.w), "delete_event",
522 G_CALLBACK(write_delete_callback),
523 (gpointer)(&f));
524 g_signal_connect(G_OBJECT(f.w), "response",
525 G_CALLBACK(write_callback),
526 (gpointer)(&f));
527
528 /* Set the current directory */
529
530 if(directory && *directory)
531 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(f.w),
532 *directory);
533
534 /* Run the widget */
535
536 gtk_widget_show(f.w);
537 gtk_main();
538
539 /* Fetch the answer */
540
541 if(!f.answer)
542 {
543 gtk_widget_destroy(f.w);
544 return NULL;
545 }
546
547 tmp_string = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(f.w));
548 ret = bg_strdup(NULL, tmp_string);
549 g_free(tmp_string);
550
551 /* Update current directory */
552
553 if(directory)
554 {
555 tmp_string = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(f.w));
556 *directory = bg_strdup(*directory, tmp_string);
557 g_free(tmp_string);
558 }
559
560 return ret;
561 }
562