DO NOT REPLY TO THIS MESSAGE. INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.
[STR New]
Link: http://www.fltk.org/str.php?L2904
Version: 1.3-feature
Attached file "Fl_Native_File_Chooser_GTK_test.cxx"...
Link: http://www.fltk.org/str.php?L2904
Version: 1.3-feature
// "$Id: $"
//
// FLTK native file chooser widget wrapper for GTK's GtkFileChooserDialog
//
// Copyright 1998-2013 by Bill Spitzak and others.
// Copyright 2012 IMM
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file. If this
// file is missing or damaged, see the license at:
//
// http://www.fltk.org/COPYING.php
//
// Please report all bugs and problems to:
//
// http://www.fltk.org/str.php
//
#include <FL/Fl_Native_File_Chooser.H>
#include <FL/Fl_File_Icon.H>
#define FLTK_CHOOSER_SINGLE Fl_File_Chooser::SINGLE
#define FLTK_CHOOSER_DIRECTORY Fl_File_Chooser::DIRECTORY
#define FLTK_CHOOSER_MULTI Fl_File_Chooser::MULTI
#define FLTK_CHOOSER_CREATE Fl_File_Chooser::CREATE
#include "Fl_Native_File_Chooser_common.cxx"
#include <sys/stat.h>
#include <string.h>
static int did_find_GTK_libs = 0;
#ifdef _TEST_GTK_FILE_CHOOSER
# warning Test code for GTK file chooser
# include <dlfcn.h> // for dlopen et al
# include <gtk/gtk.h> // for GTK funtions
# include <locale.h>
static int have_looked_for_GTK_libs = 0;
/* These are the GTK/GLib methods we want to load, but not call by name...! */
// void g_free (gpointer mem);
typedef void (*XX_g_free)(gpointer);
static XX_g_free fl_g_free = NULL;
// gpointer g_slist_nth_data (GSList *list, guint n);
typedef gpointer (*XX_g_slist_nth_data) (GSList *, guint);
static XX_g_slist_nth_data fl_g_slist_nth_data = NULL;
// guint g_slist_length (GSList *list);
typedef guint (*XX_g_slist_length) (GSList *);
static XX_g_slist_length fl_g_slist_length = NULL;
// void g_slist_free (GSList *list);
typedef void (*XX_g_slist_free) (GSList *);
static XX_g_slist_free fl_g_slist_free = NULL;
// gboolean gtk_init_check (int *argc, char ***argv);
typedef gboolean (*XX_gtk_init_check)(int *, char ***);
static XX_gtk_init_check fl_gtk_init_check = NULL;
// void gtk_widget_destroy (GtkWidget *widget);
typedef void (*XX_gtk_widget_destroy) (GtkWidget *);
static XX_gtk_widget_destroy fl_gtk_widget_destroy = NULL;
// void gtk_file_chooser_set_select_multiple(GtkFileChooser *chooser, gboolean
select_multiple);
typedef void (*XX_gtk_file_chooser_set_select_multiple)(GtkFileChooser *,
gboolean);
static XX_gtk_file_chooser_set_select_multiple
fl_gtk_file_chooser_set_select_multiple = NULL;
// void gtk_file_chooser_set_do_overwrite_confirmation(GtkFileChooser *chooser,
gboolean do_overwrite_confirmation);
typedef void
(*XX_gtk_file_chooser_set_do_overwrite_confirmation)(GtkFileChooser *,
gboolean);
static XX_gtk_file_chooser_set_do_overwrite_confirmation
fl_gtk_file_chooser_set_do_overwrite_confirmation = NULL;
// void gtk_file_chooser_set_current_name (GtkFileChooser *chooser, const gchar
*name);
typedef void (*XX_gtk_file_chooser_set_current_name)(GtkFileChooser *, const
gchar *);
static XX_gtk_file_chooser_set_current_name
fl_gtk_file_chooser_set_current_name = NULL;
// void gtk_file_chooser_set_current_folder (GtkFileChooser *chooser, const
gchar *name);
typedef void (*XX_gtk_file_chooser_set_current_folder)(GtkFileChooser *, const
gchar *);
static XX_gtk_file_chooser_set_current_folder
fl_gtk_file_chooser_set_current_folder = NULL;
// void gtk_file_chooser_set_create_folders (GtkFileChooser *chooser, gboolean
create_folders);
typedef void (*XX_gtk_file_chooser_set_create_folders) (GtkFileChooser *,
gboolean);
static XX_gtk_file_chooser_set_create_folders
fl_gtk_file_chooser_set_create_folders = NULL;
// gboolean gtk_file_chooser_get_select_multiple(GtkFileChooser *chooser);
typedef gboolean (*XX_gtk_file_chooser_get_select_multiple)(GtkFileChooser *);
static XX_gtk_file_chooser_get_select_multiple
fl_gtk_file_chooser_get_select_multiple = NULL;
// void gtk_widget_hide(GtkWidget *widget);
typedef void (*XX_gtk_widget_hide)(GtkWidget *);
static XX_gtk_widget_hide fl_gtk_widget_hide = NULL;
// gint gtk_dialog_run(GtkDialog *dialog);
typedef gint (*XX_gtk_dialog_run)(GtkDialog *dialog);
static XX_gtk_dialog_run fl_gtk_dialog_run = NULL;
// gchar * gtk_file_chooser_get_filename(GtkFileChooser *chooser);
typedef gchar* (*XX_gtk_file_chooser_get_filename)(GtkFileChooser *);
static XX_gtk_file_chooser_get_filename fl_gtk_file_chooser_get_filename = NULL;
// GSList * gtk_file_chooser_get_filenames(GtkFileChooser *chooser);
typedef GSList* (*XX_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser);
static XX_gtk_file_chooser_get_filenames fl_gtk_file_chooser_get_filenames =
NULL;
// gboolean gtk_main_iteration(void);
typedef gboolean (*XX_gtk_main_iteration)(void);
static XX_gtk_main_iteration fl_gtk_main_iteration = NULL;
// gboolean gtk_events_pending(void);
typedef gboolean (*XX_gtk_events_pending)(void);
static XX_gtk_events_pending fl_gtk_events_pending = NULL;
// GtkWidget * gtk_file_chooser_dialog_new(const gchar *title, GtkWindow
*parent, GtkFileChooserAction action, const gchar *first_button_text, ...);
typedef GtkWidget* (*XX_gtk_file_chooser_dialog_new)(const gchar *, GtkWindow
*, GtkFileChooserAction, const gchar *, ...);
static XX_gtk_file_chooser_dialog_new fl_gtk_file_chooser_dialog_new = NULL;
// void gtk_file_chooser_add_filter(GtkFileChooser*, GtkFileFilter*);
typedef void (*XX_gtk_file_chooser_add_filter)(GtkFileChooser*, GtkFileFilter*);
static XX_gtk_file_chooser_add_filter fl_gtk_file_chooser_add_filter = NULL;
// GtkFileFilter* gtk_file_chooser_get_filter(GtkFileChooser*);
typedef GtkFileFilter* (*XX_gtk_file_chooser_get_filter)(GtkFileChooser*);
static XX_gtk_file_chooser_get_filter fl_gtk_file_chooser_get_filter = NULL;
// void gtk_file_chooser_set_filter(GtkFileChooser*, GtkFileFilter*);
typedef void (*XX_gtk_file_chooser_set_filter)(GtkFileChooser*, GtkFileFilter*);
static XX_gtk_file_chooser_set_filter fl_gtk_file_chooser_set_filter = NULL;
// GtkFileFilter * gtk_file_filter_new();
typedef GtkFileFilter* (*XX_gtk_file_filter_new)(void);
static XX_gtk_file_filter_new fl_gtk_file_filter_new = NULL;
// void gtk_file_filter_add_pattern(GtkFileFilter*, const gchar*);
typedef void (*XX_gtk_file_filter_add_pattern)(GtkFileFilter*, const gchar*);
static XX_gtk_file_filter_add_pattern fl_gtk_file_filter_add_pattern = NULL;
// void gtk_file_filter_add_custom(GtkFileFilter *filter, GtkFileFilterFlags
needed,
// GtkFileFilterFunc func, gpointer data, GDestroyNotify notify);
typedef void (*XX_gtk_file_filter_add_custom)(GtkFileFilter *filter,
GtkFileFilterFlags needed,
GtkFileFilterFunc func, gpointer
data,
GDestroyNotify notify);
static XX_gtk_file_filter_add_custom fl_gtk_file_filter_add_custom = NULL;
// void gtk_file_filter_set_name(GtkFileFilter*, const gchar*);
typedef void (*XX_gtk_file_filter_set_name)(GtkFileFilter*, const gchar*);
static XX_gtk_file_filter_set_name fl_gtk_file_filter_set_name = NULL;
// const gchar* gtk_file_filter_get_name(GtkFileFilter*);
typedef const gchar* (*XX_gtk_file_filter_get_name)(GtkFileFilter*);
static XX_gtk_file_filter_get_name fl_gtk_file_filter_get_name = NULL;
// void gtk_file_chooser_set_extra_widget(GtkFileChooser *, GtkWidget *);
typedef void (*XX_gtk_file_chooser_set_extra_widget)(GtkFileChooser *,
GtkWidget *);
static XX_gtk_file_chooser_set_extra_widget
fl_gtk_file_chooser_set_extra_widget = NULL;
// void gtk_widget_show(GtkWidget *);
typedef void (*XX_gtk_widget_show)(GtkWidget *);
static XX_gtk_widget_show fl_gtk_widget_show = NULL;
// GtkWidget *gtk_check_button_new_with_label(const gchar *);
typedef GtkWidget* (*XX_gtk_check_button_new_with_label)(const gchar *);
static XX_gtk_check_button_new_with_label fl_gtk_check_button_new_with_label =
NULL;
// gulong g_signal_connect_data(gpointer, const gchar *, GCallback, gpointer,
GClosureNotify, GConnectFlags);
typedef gulong (*XX_g_signal_connect_data)(gpointer, const gchar *, GCallback,
gpointer, GClosureNotify, GConnectFlags);
static XX_g_signal_connect_data fl_g_signal_connect_data = NULL;
// gboolean gtk_toggle_button_get_active(GtkToggleButton *);
typedef gboolean (*XX_gtk_toggle_button_get_active)(GtkToggleButton*);
static XX_gtk_toggle_button_get_active fl_gtk_toggle_button_get_active = NULL;
// void gtk_file_chooser_set_show_hidden(GtkFileChooser *, gboolean);
typedef void (*XX_gtk_file_chooser_set_show_hidden)(GtkFileChooser *, gboolean);
static XX_gtk_file_chooser_set_show_hidden fl_gtk_file_chooser_set_show_hidden
= NULL;
// gboolean gtk_file_chooser_get_show_hidden(GtkFileChooser *);
typedef gboolean (*XX_gtk_file_chooser_get_show_hidden)(GtkFileChooser *);
static XX_gtk_file_chooser_get_show_hidden fl_gtk_file_chooser_get_show_hidden
= NULL;
// void gtk_toggle_button_set_active(GtkToggleButton *, gboolean);
typedef void (*XX_gtk_toggle_button_set_active)(GtkToggleButton *, gboolean);
static XX_gtk_toggle_button_set_active fl_gtk_toggle_button_set_active = NULL;
// macro to help with the symbol loading boilerplate...
#define GET_SYM(SSS, LLL) \
dlerror(); /* Clear any existing error */ \
fl_##SSS = (XX_##SSS)dlsym(LLL, #SSS); \
if ((pc_dl_error = dlerror()) != NULL) { \
fprintf(stderr, "%s\n", pc_dl_error); \
did_find_GTK_libs = 0; \
return; }
class Fl_GTK_File_Chooser {
friend class Fl_Native_File_Chooser;
private:
GtkWidget *gtkw_ptr; // used to hold a GtkWidget* without pulling GTK into
everything...
void *gtkw_slist; // used to hold a GLib GSList...
unsigned gtkw_count; // number of files read back - if any
mutable char *gtkw_filename; // last name we read back
char *gtkw_title; // the title to be applied to the dialog
public:
Fl_GTK_File_Chooser() {
gtkw_ptr = NULL; // used to hold a GtkWidget* without pulling GTK into
everything...
gtkw_slist = NULL; // will hold the returned file names in a
multi-selection...
gtkw_count = 0; // How many items were selected?
gtkw_filename = NULL; // holds the last name we read back in a single file
selection...
gtkw_title = NULL; // dialog title
}
};
static void* fl_dlopen(const char *filename1, const char *filename2)
{
void *ptr = dlopen(filename1, RTLD_LAZY | RTLD_GLOBAL);
if (!ptr) ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
return ptr;
}
/*
* Use dlopen to see if we can load the gtk dynamic libraries that
* will allow us to create a GtkFileChooserDialog() on the fly,
* without linking to the GTK libs at compile time.
*/
static void probe_for_GTK_libs(void) {
void *ptr_glib = NULL;
void *ptr_gtk = NULL;
# ifdef __APPLE_CC__ // allows testing on Darwin + X11
ptr_glib = dlopen("/sw/lib/libglib-2.0.dylib", RTLD_LAZY | RTLD_GLOBAL);
# else
ptr_glib = fl_dlopen("libglib-2.0.so", "libglib-2.0.so.0");
# endif
// Try first with GTK3
ptr_gtk = fl_dlopen("libgtk-3.so", "libgtk-3.so.0");
if (ptr_gtk && ptr_glib) {
#ifdef DEBUG
puts("selected GTK-3\n");
#endif
}
else {// Try then with GTK2
# ifdef __APPLE_CC__ // allows testing on Darwin + X11
ptr_gtk = dlopen("/sw/lib/libgtk-x11-2.0.dylib", RTLD_LAZY |
RTLD_GLOBAL);
#else
ptr_gtk = fl_dlopen("libgtk-x11-2.0.so", "libgtk-x11-2.0.so.0");
#endif
#ifdef DEBUG
if (ptr_gtk && ptr_glib) {
puts("selected GTK-2\n");
}
#endif
}
if((!ptr_glib) || (!ptr_gtk)) {
#ifdef DEBUG
puts("Failure to load");
#endif
did_find_GTK_libs = 0;
return;
}
char *pc_dl_error; // used to report errors by the GET_SYM macro...
// items we need from GLib
GET_SYM(g_free, ptr_glib);
GET_SYM(g_slist_nth_data, ptr_glib);
GET_SYM(g_slist_length, ptr_glib);
GET_SYM(g_slist_free, ptr_glib);
// items we need from GTK
GET_SYM(gtk_init_check, ptr_gtk);
GET_SYM(gtk_widget_destroy, ptr_gtk);
GET_SYM(gtk_file_chooser_set_select_multiple, ptr_gtk);
GET_SYM(gtk_file_chooser_set_do_overwrite_confirmation, ptr_gtk);
GET_SYM(gtk_file_chooser_set_current_name, ptr_gtk);
GET_SYM(gtk_file_chooser_set_current_folder, ptr_gtk);
GET_SYM(gtk_file_chooser_set_create_folders, ptr_gtk);
GET_SYM(gtk_file_chooser_get_select_multiple, ptr_gtk);
GET_SYM(gtk_widget_hide, ptr_gtk);
GET_SYM(gtk_dialog_run, ptr_gtk);
GET_SYM(gtk_file_chooser_get_filename, ptr_gtk);
GET_SYM(gtk_file_chooser_get_filenames, ptr_gtk);
GET_SYM(gtk_main_iteration, ptr_gtk);
GET_SYM(gtk_events_pending, ptr_gtk);
GET_SYM(gtk_file_chooser_dialog_new, ptr_gtk);
GET_SYM(gtk_file_chooser_add_filter, ptr_gtk);
GET_SYM(gtk_file_chooser_get_filter, ptr_gtk);
GET_SYM(gtk_file_chooser_set_filter, ptr_gtk);
GET_SYM(gtk_file_filter_new, ptr_gtk);
GET_SYM(gtk_file_filter_add_pattern, ptr_gtk);
GET_SYM(gtk_file_filter_add_custom, ptr_gtk);
GET_SYM(gtk_file_filter_set_name, ptr_gtk);
GET_SYM(gtk_file_filter_get_name, ptr_gtk);
GET_SYM(gtk_file_chooser_set_extra_widget, ptr_gtk);
GET_SYM(gtk_widget_show, ptr_gtk);
GET_SYM(gtk_check_button_new_with_label, ptr_gtk);
GET_SYM(g_signal_connect_data, ptr_gtk);
GET_SYM(gtk_toggle_button_get_active, ptr_gtk);
GET_SYM(gtk_file_chooser_set_show_hidden, ptr_gtk);
GET_SYM(gtk_file_chooser_get_show_hidden, ptr_gtk);
GET_SYM(gtk_toggle_button_set_active, ptr_gtk);
did_find_GTK_libs = _TEST_GTK_FILE_CHOOSER;
} // probe_for_GTK_libs
#endif /* _TEST_GTK_FILE_CHOOSER */
/**
The constructor. Internally allocates the native widgets.
Optional \p val presets the type of browser this will be,
which can also be changed with type().
*/
Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
_btype = val;
_options = NO_OPTIONS;
_filter = NULL;
_filtvalue = 0;
_parsedfilt = NULL;
_preset_file = NULL;
_prevvalue = NULL;
_directory = NULL;
_errmsg = NULL;
_file_chooser = NULL;
// My plan - such as it is - is to allocate _file_chooser ONLY if I can not
// make a GtkFileChooserDialog, which I'll deal with... somehow...
// Anyway, the idea is to have some global static state in this file, such
that
// the first time in, we probe for the GTK libs we need, and if found we use
them.
// Otherwise, we just create a stock FLTK file chooser, and from thereon this
file
// would behave exactly like Fl_Native_File_Chooser_FLTK.
#ifdef _TEST_GTK_FILE_CHOOSER
if(have_looked_for_GTK_libs == 0) {
// First Time here, try to find the GTK libs if they are installed
probe_for_GTK_libs();
have_looked_for_GTK_libs = -1;
}
// if we found all the GTK functions we need, we will use the
GtkFileChooserDialog
if (did_find_GTK_libs) {
_file_chooser = (Fl_File_Chooser*)new Fl_GTK_File_Chooser();
}
#endif // _TEST_GTK_FILE_CHOOSER
if (!_file_chooser) _file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
type(val); // do this after _file_chooser created
_nfilters = 0;
}
/**
Destructor.
Deallocates any resources allocated to this widget.
*/
Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
if (!did_find_GTK_libs) {
delete _file_chooser;
_file_chooser = NULL;
}
_filter = strfree(_filter);
_parsedfilt = strfree(_parsedfilt);
_preset_file = strfree(_preset_file);
_prevvalue = strfree(_prevvalue);
_directory = strfree(_directory);
_errmsg = strfree(_errmsg);
#ifdef _TEST_GTK_FILE_CHOOSER
if (did_find_GTK_libs) {
// Should free up resources taken for...
Fl_GTK_File_Chooser *gtk = (Fl_GTK_File_Chooser*)_file_chooser;
if(gtk->gtkw_ptr) {
fl_gtk_widget_destroy (gtk->gtkw_ptr);
gtk->gtkw_ptr = NULL;
}
if(gtk->gtkw_filename) {
fl_g_free(gtk->gtkw_filename);
gtk->gtkw_filename = NULL;
}
if(gtk->gtkw_slist) {
GSList *iter = (GSList *)gtk->gtkw_slist;
while(iter) {
if(iter->data) fl_g_free(iter->data);
iter = g_slist_next(iter);
}
fl_g_slist_free((GSList *)gtk->gtkw_slist);
gtk->gtkw_slist = NULL;
}
gtk->gtkw_count = 0; // assume we have no files selected now
gtk->gtkw_title = strfree(gtk->gtkw_title);
}
#endif // _TEST_GTK_FILE_CHOOSER
}
// PRIVATE: SET ERROR MESSAGE
void Fl_Native_File_Chooser::errmsg(const char *msg) {
_errmsg = strfree(_errmsg);
_errmsg = strnew(msg);
}
// PRIVATE: translate Native types to Fl_File_Chooser types
int Fl_Native_File_Chooser::type_fl_file(int val) {
switch (val) {
case BROWSE_FILE:
return(FLTK_CHOOSER_SINGLE);
case BROWSE_DIRECTORY:
return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_DIRECTORY);
case BROWSE_MULTI_FILE:
return(FLTK_CHOOSER_MULTI);
case BROWSE_MULTI_DIRECTORY:
return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI);
case BROWSE_SAVE_FILE:
return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_CREATE);
case BROWSE_SAVE_DIRECTORY:
return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI | FLTK_CHOOSER_CREATE);
default:
return(FLTK_CHOOSER_SINGLE);
}
}
/**
Sets the current Fl_Native_File_Chooser::Type of browser.
*/
void Fl_Native_File_Chooser::type(int val) {
_btype = val;
if (!did_find_GTK_libs) _file_chooser->type(type_fl_file(val));
}
/**
Gets the current Fl_Native_File_Chooser::Type of browser.
*/
int Fl_Native_File_Chooser::type() const {
return(_btype);
}
/**
Sets the platform specific chooser options to \p val.
\p val is expected to be one or more Fl_Native_File_Chooser::Option flags
ORed together.
Some platforms have OS-specific functions that can be enabled/disabled via
this method.
<P>
\code
Flag Description Win
Mac Other
-------------- ----------------------------------------------- -------
------- -------
NEW_FOLDER Shows the 'New Folder' button. Ignored
Used Used
PREVIEW Enables the 'Preview' mode by default. Ignored
Ignored Used
SAVEAS_CONFIRM Confirm dialog if BROWSE_SAVE_FILE file exists. Used
Used Used
\endcode
*/
void Fl_Native_File_Chooser::options(int val) {
_options = val;
}
/**
Gets the platform specific Fl_Native_File_Chooser::Option flags.
*/
int Fl_Native_File_Chooser::options() const {
return(_options);
}
#ifdef _TEST_GTK_FILE_CHOOSER
static gboolean fl_custom_gtk_filter_function(const GtkFileFilterInfo *info,
gpointer data)
{
return (gboolean)fl_filename_match(info->filename, (const char*)data);
}
static void hidden_files_cb(GtkToggleButton *togglebutton, gpointer user_data)
{
gboolean state = fl_gtk_toggle_button_get_active(togglebutton);
fl_gtk_file_chooser_set_show_hidden((GtkFileChooser*)user_data, state);
}
// Implements a wrapper for the GtkFileChooserDialog
int Fl_Native_File_Chooser::fl_gtk_chooser_wrapper()
{
int result = 1;
static int have_gtk_init = 0;
if(!have_gtk_init) {
have_gtk_init = -1;
int ac = 0;
fl_gtk_init_check(&ac, NULL);
}
Fl_GTK_File_Chooser *gtk = (Fl_GTK_File_Chooser*)_file_chooser;
if(gtk->gtkw_ptr) { // discard the previous dialog widget
fl_gtk_widget_destroy (gtk->gtkw_ptr);
gtk->gtkw_ptr = NULL;
}
// set the dialog action type
GtkFileChooserAction gtw_action_type;
switch (_btype) {
case BROWSE_DIRECTORY:
case BROWSE_MULTI_DIRECTORY:
gtw_action_type = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
break;
case BROWSE_SAVE_FILE:
gtw_action_type = GTK_FILE_CHOOSER_ACTION_SAVE;
break;
case BROWSE_SAVE_DIRECTORY:
gtw_action_type = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
break;
case BROWSE_MULTI_FILE:
case BROWSE_FILE:
default:
gtw_action_type = GTK_FILE_CHOOSER_ACTION_OPEN;
break;
}
// create a new dialog
gtk->gtkw_ptr = fl_gtk_file_chooser_dialog_new (gtk->gtkw_title,
NULL, /* parent_window */
gtw_action_type,
GTK_STOCK_CANCEL,
GTK_RESPONSE_CANCEL,
gtw_action_type == GTK_FILE_CHOOSER_ACTION_SAVE ?
GTK_STOCK_SAVE : GTK_STOCK_OPEN,
GTK_RESPONSE_ACCEPT,
NULL);
// did we create a valid dialog widget?
if(!gtk->gtkw_ptr) {
// fail
return -1;
}
// set the dialog properties
switch (_btype) {
case BROWSE_MULTI_DIRECTORY:
case BROWSE_MULTI_FILE:
fl_gtk_file_chooser_set_select_multiple((GtkFileChooser *)gtk->gtkw_ptr,
TRUE);
break;
case BROWSE_SAVE_FILE:
if((_options & SAVEAS_CONFIRM) != 0)
fl_gtk_file_chooser_set_do_overwrite_confirmation ((GtkFileChooser
*)gtk->gtkw_ptr, TRUE);
fl_gtk_file_chooser_set_current_name ((GtkFileChooser *)gtk->gtkw_ptr,
_preset_file);
if((_options & NEW_FOLDER) != 0)
fl_gtk_file_chooser_set_create_folders((GtkFileChooser *)gtk->gtkw_ptr, TRUE);
break;
case BROWSE_SAVE_DIRECTORY:
if((_options & NEW_FOLDER) != 0)
fl_gtk_file_chooser_set_create_folders((GtkFileChooser *)gtk->gtkw_ptr, TRUE);
//if((_options & SAVEAS_CONFIRM) != 0)
fl_gtk_file_chooser_set_do_overwrite_confirmation ((GtkFileChooser
*)gtk->gtkw_ptr, TRUE);
break;
case BROWSE_DIRECTORY:
case BROWSE_FILE:
default:
break;
}
if (_directory && _directory[0])
fl_gtk_file_chooser_set_current_folder((GtkFileChooser *)gtk->gtkw_ptr,
_directory);
GtkFileFilter **filter_tab = NULL;
if (_parsedfilt) {
filter_tab = new GtkFileFilter*[_nfilters];
char *filter = strdup(_parsedfilt);
char *p = strtok(filter, "\t");
int count = 0;
while (p) {
filter_tab[count] = fl_gtk_file_filter_new();
fl_gtk_file_filter_set_name(filter_tab[count], p);
p = strchr(p, '(') + 1;
char *q = strchr(p, ')'); *q = 0;
fl_gtk_file_filter_add_custom(filter_tab[count],
GTK_FILE_FILTER_FILENAME,
fl_custom_gtk_filter_function, strdup(p),
free);
fl_gtk_file_chooser_add_filter((GtkFileChooser *)gtk->gtkw_ptr,
filter_tab[count]);
p = strtok(NULL, "\t");
count++;
}
free(filter);
fl_gtk_file_chooser_set_filter((GtkFileChooser *)gtk->gtkw_ptr,
filter_tab[_filtvalue]);
if (gtw_action_type == GTK_FILE_CHOOSER_ACTION_OPEN) {
GtkFileFilter* gfilter = fl_gtk_file_filter_new();
fl_gtk_file_filter_set_name(gfilter, Fl_File_Chooser::all_files_label);
fl_gtk_file_filter_add_pattern(gfilter, "*");
fl_gtk_file_chooser_add_filter((GtkFileChooser *)gtk->gtkw_ptr, gfilter);
}
}
GtkWidget *toggle =
fl_gtk_check_button_new_with_label(Fl_File_Chooser::hidden_label);
fl_gtk_widget_show(toggle);
fl_gtk_file_chooser_set_extra_widget((GtkFileChooser *)gtk->gtkw_ptr, toggle);
fl_g_signal_connect_data(toggle, "toggled", G_CALLBACK(hidden_files_cb),
gtk->gtkw_ptr, NULL, (GConnectFlags) 0);
fl_gtk_widget_show(gtk->gtkw_ptr);
gboolean state = fl_gtk_file_chooser_get_show_hidden((GtkFileChooser
*)gtk->gtkw_ptr);
fl_gtk_toggle_button_set_active((GtkToggleButton *)toggle, state);
if (fl_gtk_dialog_run ((GtkDialog *)gtk->gtkw_ptr) == GTK_RESPONSE_ACCEPT) {
if (_parsedfilt) {
GtkFileFilter *gfilter = fl_gtk_file_chooser_get_filter((GtkFileChooser
*)gtk->gtkw_ptr);
for (_filtvalue = 0; _filtvalue < _nfilters; _filtvalue++) {
if (filter_tab[_filtvalue] == gfilter) break;
}
}
// discard any filenames or lists from previous calls
if(gtk->gtkw_filename) {
fl_g_free(gtk->gtkw_filename);
gtk->gtkw_filename = NULL;
}
if(gtk->gtkw_slist) {
GSList *iter = (GSList *)gtk->gtkw_slist;
while(iter) {
if(iter->data) fl_g_free(iter->data);
iter = g_slist_next(iter);
}
fl_g_slist_free((GSList *)gtk->gtkw_slist);
gtk->gtkw_slist = NULL;
}
gtk->gtkw_count = 0; // assume we have no files selected now
if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtk->gtkw_ptr)
== FALSE) {
gtk->gtkw_filename = fl_gtk_file_chooser_get_filename ((GtkFileChooser
*)gtk->gtkw_ptr);
if (gtk->gtkw_filename) {
gtk->gtkw_count = 1;
result = 0;
//printf("single: %s\n", gtkw_filename);
}
}
else {
gtk->gtkw_slist = fl_gtk_file_chooser_get_filenames((GtkFileChooser
*)gtk->gtkw_ptr);
gtk->gtkw_count = fl_g_slist_length((GSList *)gtk->gtkw_slist);
if(gtk->gtkw_count) result = 0;
// puts("multiple");
// GSList *iter = (GSList *)gtk->gtkw_slist;
// printf ("Selected %d files\n", gtk->gtkw_count);
// while(iter) {
// char *nm = (char *)iter->data;
// printf("%s\n", nm);
// iter = g_slist_next(iter);
// }
}
}
delete[] filter_tab;
fl_gtk_widget_hide (gtk->gtkw_ptr);
// I think this is analogus to doing an Fl::check() - we need this here to
make sure
// the GtkFileChooserDialog is removed from the display correctly
while (fl_gtk_events_pending ()) fl_gtk_main_iteration ();
return result;
} // fl_gtk_chooser_wrapper
#endif // _TEST_GTK_FILE_CHOOSER
/**
Post the chooser's dialog. Blocks until dialog has been completed or
cancelled.
\returns
- 0 -- user picked a file
- 1 -- user cancelled
- -1 -- failed; errmsg() has reason
*/
int Fl_Native_File_Chooser::show() {
if(!did_find_GTK_libs) { // use FLTK built-in file chooser
// FILTER
if ( _parsedfilt ) {
_file_chooser->filter(_parsedfilt);
}
// FILTER VALUE
// Set this /after/ setting the filter
//
_file_chooser->filter_value(_filtvalue);
// DIRECTORY
if ( _directory && _directory[0] ) {
_file_chooser->directory(_directory);
} else {
_file_chooser->directory(_prevvalue);
}
// PRESET FILE
if ( _preset_file ) {
_file_chooser->value(_preset_file);
}
// OPTIONS: PREVIEW
_file_chooser->preview( (options() & PREVIEW) ? 1 : 0);
// OPTIONS: NEW FOLDER
if ( options() & NEW_FOLDER )
_file_chooser->type(_file_chooser->type() | FLTK_CHOOSER_CREATE); // on
// SHOW
_file_chooser->show();
// BLOCK WHILE BROWSER SHOWN
while ( _file_chooser->shown() ) {
Fl::wait();
}
if ( _file_chooser->value() && _file_chooser->value()[0] ) {
_prevvalue = strfree(_prevvalue);
_prevvalue = strnew(_file_chooser->value());
_filtvalue = _file_chooser->filter_value(); // update filter value
// HANDLE SHOWING 'SaveAs' CONFIRM
if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
struct stat buf;
if ( stat(_file_chooser->value(), &buf) != -1 ) {
if ( buf.st_mode & S_IFREG ) { // Regular file + exists?
if ( exist_dialog() == 0 ) {
return(1);
}
}
}
}
}
if ( _file_chooser->count() ) return(0);
else return(1);
}
#ifdef _TEST_GTK_FILE_CHOOSER
else { // use GtkFileChooserDialog
char *p, **before = new char*[20];
int val;
for (val = 0; val < 20; val++) { // memorize the state of all components of
the current locale
if (val == LC_ALL) continue;
p = setlocale(val, NULL);
if (!p) break;
before[val] = strdup(p);
}
int retval = fl_gtk_chooser_wrapper(); // may change the locale
for (int i = 0; i < val; i++) { // set all components of the locale to
their previous state
if (i == LC_ALL) continue;
if (before[i]) {
setlocale(i, before[i]);
free(before[i]);
}
}
delete[] before;
return retval;
}
#else
return -1; //error
#endif // _TEST_GTK_FILE_CHOOSER
}
/**
Returns a system dependent error message for the last method that failed.
This message should at least be flagged to the user in a dialog box, or to
some kind of error log.
Contents will be valid only for methods that document errmsg() will have info
on failures.
*/
const char *Fl_Native_File_Chooser::errmsg() const {
return(_errmsg ? _errmsg : "No error");
}
/**
Return the filename the user chose.
Use this if only expecting a single filename.
If more than one filename is expected, use filename(int) instead.
Return value may be "" if no filename was chosen (eg. user cancelled).
*/
const char* Fl_Native_File_Chooser::filename() const {
if ((!did_find_GTK_libs) && ( _file_chooser->count() > 0 )) {
return(_file_chooser->value());
}
#ifdef _TEST_GTK_FILE_CHOOSER
// else...
if (did_find_GTK_libs) {
Fl_GTK_File_Chooser *gtk = (Fl_GTK_File_Chooser*)_file_chooser;
if(gtk->gtkw_ptr) {
if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser
*)gtk->gtkw_ptr) == FALSE) {
return gtk->gtkw_filename;
}
else {
GSList *iter = (GSList *)gtk->gtkw_slist;
char *nm = (char *)iter->data;
return nm;
}
}
}
#endif // _TEST_GTK_FILE_CHOOSER
// else...
return("");
}
/**
Return one of the filenames the user selected.
Use count() to determine how many filenames the user selected.
<P>
\b Example:
\code
if ( fnfc->show() == 0 ) {
// Print all filenames user selected
for (int n=0; n<fnfc->count(); n++ ) {
printf("%d) '%s'\n", n, fnfc->filename(n));
}
}
\endcode
*/
const char* Fl_Native_File_Chooser::filename(int i) const {
if(!did_find_GTK_libs) {
if ( i < _file_chooser->count() )
return(_file_chooser->value(i+1)); // convert fltk 1 based to our 0
based
}
#ifdef _TEST_GTK_FILE_CHOOSER
else {
Fl_GTK_File_Chooser *gtk = (Fl_GTK_File_Chooser*)_file_chooser;
if(fl_gtk_file_chooser_get_select_multiple((GtkFileChooser *)gtk->gtkw_ptr)
== FALSE) {
return gtk->gtkw_filename;
}
else {
if ((unsigned)i < gtk->gtkw_count) {
GSList *iter = (GSList *)gtk->gtkw_slist;
char *nm = (char *)fl_g_slist_nth_data(iter, i);
return nm;
}
}
}
#endif // _TEST_GTK_FILE_CHOOSER
// else...
return("");
}
/**
Set the title of the file chooser's dialog window.
Can be NULL if no title desired.
The default title varies according to the platform, so you are advised to set
the title explicitly.
*/
void Fl_Native_File_Chooser::title(const char *val) {
if(!did_find_GTK_libs) {
_file_chooser->label(val);
}
#ifdef _TEST_GTK_FILE_CHOOSER
else { // gtk version...
Fl_GTK_File_Chooser *gtk = (Fl_GTK_File_Chooser*)_file_chooser;
strfree(gtk->gtkw_title);
gtk->gtkw_title = strnew(val);
}
#endif // _TEST_GTK_FILE_CHOOSER
}
/**
Get the title of the file chooser's dialog window.
Return value may be NULL if no title was set.
*/
const char *Fl_Native_File_Chooser::title() const {
if(!did_find_GTK_libs) {
return(_file_chooser->label());
}
#ifdef _TEST_GTK_FILE_CHOOSER
else {
return ((Fl_GTK_File_Chooser*)_file_chooser)->gtkw_title;
}
#else
return "";
#endif // _TEST_GTK_FILE_CHOOSER
}
/**
Sets the filename filters used for browsing.
The default is NULL, which browses all files.
<P>
The filter string can be any of:
<P>
- A single wildcard (eg. "*.txt")
- Multiple wildcards (eg. "*.{cxx,h,H}")
- A descriptive name followed by a "\t" and a wildcard (eg. "Text
Files\t*.txt")
- A list of separate wildcards with a "\n" between each (eg.
"*.{cxx,H}\n*.txt")
- A list of descriptive names and wildcards (eg. "C++ Files\t*.{cxx,H}\nTxt
Files\t*.txt")
<P>
The format of each filter is a wildcard, or an optional user description
followed by '\\t' and the wildcard.
<P>
On most platforms, each filter is available to the user via a pulldown menu
in the file chooser. The 'All Files' option is always available to the user.
*/
void Fl_Native_File_Chooser::filter(const char *val) {
_filter = strfree(_filter);
_filter = strnew(val);
parse_filter();
}
/**
Returns the filter string last set.
Can be NULL if no filter was set.
*/
const char *Fl_Native_File_Chooser::filter() const {
return(_filter);
}
/**
Gets how many filters were available, not including "All Files"
*/
int Fl_Native_File_Chooser::filters() const {
return(_nfilters);
}
/**
Sets which filter will be initially selected.
The first filter is indexed as 0.
If filter_value()==filters(), then "All Files" was chosen.
If filter_value() > filters(), then a custom filter was set.
*/
void Fl_Native_File_Chooser::filter_value(int val) {
_filtvalue = val;
}
/**
Returns which filter value was last selected by the user.
This is only valid if the chooser returns success.
*/
int Fl_Native_File_Chooser::filter_value() const {
return(_filtvalue);
}
/**
Returns the number of filenames (or directory names) the user selected.
<P>
\b Example:
\code
if ( fnfc->show() == 0 ) {
// Print all filenames user selected
for (int n=0; n<fnfc->count(); n++ ) {
printf("%d) '%s'\n", n, fnfc->filename(n));
}
}
\endcode
*/
int Fl_Native_File_Chooser::count() const {
if(!did_find_GTK_libs) return(_file_chooser->count());
#ifdef _TEST_GTK_FILE_CHOOSER
if (((Fl_GTK_File_Chooser*)_file_chooser)->gtkw_ptr) { return
((Fl_GTK_File_Chooser*)_file_chooser)->gtkw_count; }
#endif // _TEST_GTK_FILE_CHOOSER
else return 0;
}
/**
Preset the directory the browser will show when opened.
If \p val is NULL, or no directory is specified, the chooser will attempt
to use the last non-cancelled folder.
*/
void Fl_Native_File_Chooser::directory(const char *val) {
_directory = strfree(_directory);
_directory = strnew(val);
}
/**
Returns the current preset directory() value.
*/
const char *Fl_Native_File_Chooser::directory() const {
return(_directory);
}
// PRIVATE: Convert our filter format to fltk's chooser format
// FROM TO (FLTK)
// ------------------------- --------------------------
// "*.cxx" "*.cxx Files(*.cxx)"
// "C Files\t*.{cxx,h}" "C Files(*.{cxx,h})"
// "C Files\t*.{cxx,h}\nText Files\t*.txt" "C Files(*.{cxx,h})\tText
Files(*.txt)"
//
// Returns a modified version of the filter that the caller is responsible
// for freeing with strfree().
//
void Fl_Native_File_Chooser::parse_filter() {
_parsedfilt = strfree(_parsedfilt); // clear previous parsed filter (if any)
_nfilters = 0;
char *in = _filter;
if ( !in ) return;
int has_name = strchr(in, '\t') ? 1 : 0;
char mode = has_name ? 'n' : 'w'; // parse mode: n=title, w=wildcard
char wildcard[1024] = ""; // parsed wildcard
char name[1024] = "";
// Parse filter user specified
for ( ; 1; in++ ) {
/*** DEBUG
printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n",
*in, mode, name, wildcard);
***/
switch (*in) {
// FINISHED PARSING NAME?
case '\t':
if ( mode != 'n' ) goto regchar;
mode = 'w';
break;
// ESCAPE NEXT CHAR
case '\\':
++in;
goto regchar;
// FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
case '\r':
case '\n':
case '\0':
// APPEND NEW FILTER TO LIST
if ( wildcard[0] ) {
// OUT: "name(wild)\tname(wild)"
char comp[2048];
sprintf(comp, "%s%.511s(%.511s)", ((_parsedfilt)?"\t":""),
name, wildcard);
_parsedfilt = strapp(_parsedfilt, comp);
_nfilters++;
//DEBUG printf("DEBUG: PARSED FILT NOW <%s>\n", _parsedfilt);
}
// RESET
wildcard[0] = name[0] = '\0';
mode = strchr(in, '\t') ? 'n' : 'w';
// DONE?
if ( *in == '\0' ) return; // done
else continue; // not done yet, more filters
// Parse all other chars
default: // handle all non-special chars
regchar: // handle regular char
switch ( mode ) {
case 'n': chrcat(name, *in); continue;
case 'w': chrcat(wildcard, *in); continue;
}
break;
}
}
//NOTREACHED
}
/**
Sets the default filename for the chooser.
Use directory() to set the default directory.
Mainly used to preset the filename for save dialogs,
and on most platforms can be used for opening files as well.
*/
void Fl_Native_File_Chooser::preset_file(const char* val) {
_preset_file = strfree(_preset_file);
_preset_file = strnew(val);
}
/**
Get the preset filename.
*/
const char* Fl_Native_File_Chooser::preset_file() const {
return(_preset_file);
}
int Fl_Native_File_Chooser::exist_dialog() {
return(fl_choice("%s", fl_cancel, fl_ok, NULL, file_exists_message));
}
//
// End of "$Id: $".
//
_______________________________________________
fltk-dev mailing list
fltk-dev@easysw.com
http://lists.easysw.com/mailman/listinfo/fltk-dev