diff options
Diffstat (limited to 'app/wlib/gtklib/filesel.c')
-rw-r--r-- | app/wlib/gtklib/filesel.c | 238 |
1 files changed, 187 insertions, 51 deletions
diff --git a/app/wlib/gtklib/filesel.c b/app/wlib/gtklib/filesel.c index ca30c7f..a1fb7cc 100644 --- a/app/wlib/gtklib/filesel.c +++ b/app/wlib/gtklib/filesel.c @@ -34,24 +34,92 @@ #define GSEAL_ENABLE #include <gtk/gtk.h> +#include <glib-object.h> #include "gtkint.h" #include "i18n.h" #define MAX_ALLOWEDFILTERS 10 struct wFilSel_t { - GtkWidget * window; - wFilSelCallBack_p action; - void * data; - int pattCount; - GtkFileFilter *filter[ MAX_ALLOWEDFILTERS ]; - wFilSelMode_e mode; - int opt; - const char * title; - wWin_p parent; - char *defaultExtension; + GtkWidget * window; /**< file selector handle*/ + wFilSelCallBack_p action; /**< */ + void * data; /**< */ + int pattCount; /**< number of file patterns*/ + wBool_t loadPatternsAdded; /** Already loaded */ + GtkFileFilter *filter[ MAX_ALLOWEDFILTERS ]; /**< array of file patterns */ + wFilSelMode_e mode; /**< used for load or save */ + int opt; /**< see FS_ options */ + const char * title; /**< dialog box title */ + wWin_p parent; /**< parent window */ + char *defaultExtension; /**< to use if no extension specified */ }; +/** + * Signal handler for 'changed' signal of custom combo box. The filter + * is set accordinng to the file format active in the combo box + * + * \param comboBox the combo box + * \param fileSelector data of the file selector + * + */ + +static void FileFormatChanged( GtkWidget *comboBox, + struct wFilSel_t *fileSelector ) +{ + // get active entry + int entry = (int)gtk_combo_box_get_active (GTK_COMBO_BOX(comboBox)); + + if( entry>=0 ) { + g_object_ref(G_OBJECT( (fileSelector->filter)[ entry ])); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fileSelector->window ), + (fileSelector->filter)[ entry ]); + } +} + +/** + * Create a widget containing a combo box for selecting a file format. + * From an array of filters, the names are retrieved and used to populate + * the combo box. + * \param IN dialogBox + * \param patterns IN number of entries for combo + * \param filters IN + * \returns the newly created widget + */ + +static GtkWidget *CreateFileformatSelector(struct wFilSel_t *dialogBox, + int patterns, + GtkFileFilter **filters) +{ + GtkWidget *hbox = gtk_hbox_new(FALSE, 12); + GtkWidget *text = gtk_label_new(_("Save format:")); + GtkWidget *combo = gtk_combo_box_text_new (); + + g_signal_connect(G_OBJECT(combo), + "changed", + (GCallback)FileFormatChanged, + dialogBox ); + + + gtk_box_pack_start (GTK_BOX(hbox), + text, + FALSE, + FALSE, + 0); + gtk_box_pack_end (GTK_BOX(hbox), + combo, + TRUE, + TRUE, + 0); + for(int i=0; i < patterns; i++ ) { + const char *nameOfFilter = gtk_file_filter_get_name( filters[ i ] ); + gtk_combo_box_text_append_text( GTK_COMBO_BOX_TEXT(combo), nameOfFilter ); + } + gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0); + + gtk_widget_show_all(hbox); + + return(hbox); +} /** * Create a new file selector. Only the internal data structures are @@ -89,31 +157,75 @@ struct wFilSel_t * wFilSelCreate( fs->title = strdup( title ); fs->action = action; fs->data = data; + fs->pattCount = 0; + fs->loadPatternsAdded = FALSE; if (pattList) { - char * cp = strdup(pattList); + char * cps = strdup(pattList); + char *cp, *cp2; int count = 0; + char *patternState, *patternState2; //create filters for the passed filter list // names and patterns are separated by | - cp = strtok( cp, "|" ); - while ( cp && count < (MAX_ALLOWEDFILTERS - 1)) { + // filter elements are also separated by | + cp = cps; + while (cp && cp[0]) { + if (cp[0] == '|') { + count++; + if (count && count%2==0) { + cp[0] = ':'; //Replace every second "|" with ":" + } + } + cp++; + } + count = 0; + cp = cps; //Restart + if (opt&FS_PICTURES) { //Put first fs->filter[ count ] = gtk_file_filter_new (); - gtk_file_filter_set_name ( fs->filter[ count ], cp ); - cp = strtok( NULL, "|" ); - gtk_file_filter_add_pattern (fs->filter[ count ], cp ); - // the first pattern is considered to match the default extension - if( count == 0 ) { - fs->defaultExtension = strdup( cp ); - } - cp = strtok( NULL, "|" ); - count++; + g_object_ref_sink( G_OBJECT(fs->filter[ count ] )); + gtk_file_filter_set_name( fs->filter[ count ], _("Image files") ); + gtk_file_filter_add_pixbuf_formats( fs->filter[ count ]); + fs->pattCount = ++count; + } + cp = strtok_r( cp, ":", &patternState ); // Break up by colons + while ( cp && count < (MAX_ALLOWEDFILTERS - 1)) { + cp2 = strtok_r( cp, "|", &patternState2 ); + if (cp2) { + fs->filter[ count ] = gtk_file_filter_new (); + gtk_file_filter_set_name ( fs->filter[ count ], cp2 ); + + cp2 = strtok_r( NULL, "|", &patternState2 ); + // find multiple patterns separated by ";" + if (cp2) { + char * cp1s = strdup(cp2); + char *cp1; + char *filterState; + + cp1 = cp1s; + cp1 = strtok_r(cp1, ";", &filterState ); + while (cp1) { + gtk_file_filter_add_pattern (fs->filter[ count ], cp1 ); + cp1 = strtok_r(NULL, ";", &filterState ); + } + if (cp1s) + free(cp1s); + } + // the first pattern is considered to match the default extension + if( count == 0 && !(opt&FS_PICTURES)) { + fs->defaultExtension = strdup( cp2 ); + int i = 0; + for (i=0; i<strlen(cp2) && cp2[i] != ' ' && cp2[i] != ';';i++) ; + if (i<strlen(cp2)) fs->defaultExtension[i] = '\0'; + } + fs->pattCount = ++count; + } + cp = strtok_r( NULL, ":", &patternState ); } - // finally add the all files pattern - fs->filter[ count ] = gtk_file_filter_new (); - gtk_file_filter_set_name( fs->filter[ count ], _("All files") ); - gtk_file_filter_add_pattern( fs->filter[ count ], "*" ); - fs->pattCount = count++; + if (cps) + free(cps); + + } else { fs->filter[ 0 ] = NULL; fs->pattCount = 0; @@ -145,33 +257,41 @@ int wFilSelect( struct wFilSel_t * fs, const char * dirName ) (fs->mode == FS_LOAD ? GTK_STOCK_OPEN : GTK_STOCK_SAVE ), GTK_RESPONSE_ACCEPT, NULL ); if (fs->window==0) abort(); - // get confirmation before overwritting an existing file - gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(fs->window), TRUE ); + if ( fs->mode == FS_SAVE ) { + // get confirmation before overwritting an existing file + gtk_file_chooser_set_do_overwrite_confirmation( GTK_FILE_CHOOSER(fs->window), TRUE ); + } - // allow selecting multiple files - if( fs->opt & FS_MULTIPLEFILES ) { - gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(fs->window), TRUE); - } - // add the file filters to the dialog box - if( fs->pattCount ) { - for( i = 0; i <= fs->pattCount; i++ ) { - gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( fs->window ), fs->filter[ i ] ); - } - } /** \todo for loading a shortcut folder could be added linking to the example directory */ } strcpy( name, dirName ); - if( fs->mode == FS_SAVE ) - gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(fs->window), name ); + gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(fs->window), name ); + if( fs->mode == FS_SAVE || fs->mode == FS_UPDATE ) { + gtk_file_chooser_set_extra_widget( GTK_FILE_CHOOSER(fs->window), + CreateFileformatSelector(fs, fs->pattCount, fs->filter )); + } // Add a current folder and a shortcut to it for Load/import dialogs if( fs->mode == FS_LOAD ) { - gtk_file_chooser_set_current_folder( GTK_FILE_CHOOSER(fs->window), name ); gtk_file_chooser_add_shortcut_folder( GTK_FILE_CHOOSER(fs->window), name, NULL ); + // allow selecting multiple files + if( fs->opt & FS_MULTIPLEFILES ) { + gtk_file_chooser_set_select_multiple ( GTK_FILE_CHOOSER(fs->window), TRUE); + } + // add the file filters to the dialog box + if( fs->pattCount && !fs->loadPatternsAdded) { + + for( i = 0; i < fs->pattCount; i++ ) { + gtk_file_chooser_add_filter( GTK_FILE_CHOOSER( fs->window ), fs->filter[ i ] ); + } + fs->loadPatternsAdded = TRUE; + } } - if( gtk_dialog_run( GTK_DIALOG( fs->window )) == GTK_RESPONSE_ACCEPT ) { + int resp = gtk_dialog_run( GTK_DIALOG( fs->window )); + + if( resp == GTK_RESPONSE_ACCEPT || resp == GTK_RESPONSE_APPLY) { char **fileNames; GSList *fileNameList; @@ -184,21 +304,36 @@ int wFilSelect( struct wFilSel_t * fs, const char * dirName ) file = g_filename_from_uri( g_slist_nth_data( fileNameList, i ), &host, &err ); // check for presence of file extension - // jump behind tha last directory delimiter + // jump behind the last directory delimiter namePart = strrchr( file, '/' ) + 1; // is there a dot in the last part, yes->extension present if( !strchr( namePart, '.' ) ){ - // make room for the extension - file = g_realloc( file, strlen(file)+strlen(fs->defaultExtension)); - strcat( file, fs->defaultExtension + 1 ); + + // else try to find the current filter and parse its name + GtkFileFilter *currentFilter = gtk_file_chooser_get_filter (GTK_FILE_CHOOSER(fs->window) ); + if (currentFilter) { + const char *nameOfFilter = gtk_file_filter_get_name( currentFilter ); + char *pattern = strdup( nameOfFilter ); + char *extension = fs->defaultExtension; + char *startDelimiter = strstr( pattern, "(*." ); + + if(startDelimiter) { + char *endDelimiter = strpbrk(startDelimiter + 3, ",;) "); + if( endDelimiter ) { + *endDelimiter = '\0'; + extension = startDelimiter + 2; + } + } + file = g_realloc( file, strlen(file)+strlen(extension)); + strcat( file, extension ); + free( pattern ); + } } fileNames[ i ] = file; g_free( g_slist_nth_data ( fileNameList, i)); } - if (fs->data) - strcpy( fs->data, fileNames[ 0 ] ); - + gtk_widget_hide( GTK_WIDGET( fs->window )); if (fs->action) { fs->action( g_slist_length(fileNameList), fileNames, fs->data ); } @@ -208,8 +343,9 @@ int wFilSelect( struct wFilSel_t * fs, const char * dirName ) } free( fileNames ); g_slist_free (fileNameList); + } else { + gtk_widget_hide( GTK_WIDGET( fs->window )); } - gtk_widget_hide( GTK_WIDGET( fs->window )); return 1; } |