proposal of GtkFileSeletion replacement's API



 Hello,

 There were some discussions here and on 
gtkfilesel-devel@lists.sourceforge.net about the API of new filesel widget.
Here I propose API I designed, with idea of hooking arbitrary filesel "engine"
in mind. This API doesn't make any assumptions on the widgets that are in the 
filesel window (thus it allows arbitrary file selectors, like nautilus' view
or selector present in current gtk-1.2) (well, both mentioned candidates won't
select multiplie file selection, but can be easily used for single file
selection). 

 I'm open to your ideas on this topic.

Intro:
    The file selection window is GtkObject derived from GtkWindow. I didn't
    decide how to call that widget, but I suggest GtkFileSelectionWindow 
    (though I call it GtkFileSelector in the text below).
    All API functions below that start with '_' in realty should start with
    prefix depending on the name we choose for new fileselection widget.
    All arguments with name 'fs' are meant to be pointers to the instance of
    GtkFileSelector. GtkFileSelector is supposed to support multiplie and single
    file selectors (allowing to select a set of files in different directories
    at once for multifile selectors). Also, support for differentiation of
    save and open dialogs is done.
    
    There is a notion of 'filesel engine' - the 'struct GtkFileSelEngine' 
    with virtual functions (pointed by a member 'filesel_engine' of 
    GtkFileSelector) corresponding to each engine-dependant API function. 
    The virtual functions  will be called with validated and cloned values, so 
    filesel engine writers shouldn't bother strdupping and memcpy'ing values 
    (or cutting and pasting code :)
	It's assumed that filesel engines will be distributed as gmodules. User
    will have to add a path to their favourite filesel gmodule to the 
    environment variable $GTK_MODULES (probably gnome control center will
    provide ability to select filesel engine and configure it, as it allows
    with window managers).  
    

/*code for managing engines*/
    /* 
       Engine at the top of stack is used for creating filesel windows (but the
       (*new_instance) method of that engine can order to use different engine 
       in the returned GtkFileSelector*  (by setting 'filesel_engine' member to
       something else).
       By default, the builting implementation of file selector is on top of the
       stack.
     */
void 			_engine_push(GtkFileSelEngine* engine);
void 			_engine_pop();
GtkFileSelEngine* 	_default_engine();//to allow pushing it.
void 			_engine_register(GtkFileSelEngine* engine);
GList* 			_query_engines();
    /*
	So, each filesel engine should call _engine_register(self) and 
	_engine_push(self) when its gmodule's init function is called.
    */
    

typedef enum 
{
    GTK_FILESEL_MODE_SINGLE,
    GTK_FILESEL_MODE_MULTIPLIE
} GtkFileSelMode;

typedef enum
{
    GTK_FILESEL_ROLE_OPEN, 
	/* for example open for viewing or executing documents (primary
	    type of documents application can open).
	*/
	
    GTK_FILESEL_ROLE_SAVE, 
	/* for saving versions of the primary document type that application can
	   open directly (i.e. images for image editor).	   
	*/
	
    GTK_FILESEL_ROLE_AUX_OPEN,
    GTK_FILESEL_ROLE_AUX_SAVE,
	/* just for use - like selecting style/skin for use, etc - i.e. for 
	   documents of kind secondary to this application.
	   Documents opened with this role won't be added to 'recently opened' 
	   or 'recently edited' lists.
	   
	   For example, when one opens mp3 file in xmms, then the role of the
	   file selector dialog should be GTK_FILESEL_ROLE_OPEN (thus that file
	   will probably be added to 'recently opened..' list. But when skin
	   selector is opened for xmms, the role of that filesel dialog should
	   be GTK_FILESEL_ROLE_AUX_OPEN since viewing skins is not a primary
	   usage of xmms.	
	*/
} GtkFileSelRole;

typedef enum
{
    GTK_FILESEL_REGISTER_CLASS_GENERIC,
    GTK_FILESEL_REGISTER_CLASS_IMPORTANT,    
    GTK_FILESEL_REGISTER_CLASS_UNIMPORTANT,
    GTK_FILESEL_REGISTER_CLASS_DONT,    
} GtkFileSelRegisterImportance;
    /*
	'detail' specifies the description of this file operation. It's a 
	   string, that needn't be human-readable (and it neend't be 
	    translated to user's language). This string should uniquely 
	    describe the use of this file option in 
	    the given application, and it will 
	    propably be used as a key for retriving settings of the dialog
	    assigned by the user and/or widget itself (for example, recently 
	    opened filename, recently used directory that are specific to this
	    operation). This string won't be shown to the user in the dialog 
	    (but will probably be used as a key, together with app name, in 
	    some config file). A good example of value 'detail' is "skin" 
	    or "texture", bad are "xmms-skin-open" (since name of 
	    application and type of operation are already known to the widget, 
	    there is no  need to duplicate this information).
	    

	Using GTK_FILESEL_MODE_MULTIPLIE and GTK_FILESEL_ROLE_*SAVE is 
	    prohibbited.
    */
GtkFileSelector* _new(GtkFileSelMode mode,GtkFileSelRole role,char* detail);


    /*  moves to specified directory and selects or places filename into 
	filename prompt. It's not recommended to call this function.
    */
void _set_path(GtkFileSelector* fs,char* directory,char* filename);
    
void _clear_selection(fs);

    /*  allows to peek at list of selected files. The order of the files is 
	implementation-dependant.
    */
GList* _get_selection(fs);
    
    /*
	The list is owned by caller (so it should be freed by caller). 
	Implementation can reorder the list of filenames in any way it likes.
	If 'filenames' is NULL, then selection is cleared.
    */    
void _set_selection(fs,GList* filenames)


    /*	returns first item in the list (mostly for use by single file 
	selectors).
    */
char* _get_filename(fs);

    /*	clears selection. Selects only one file. If it's single fileselector,
	then dirname of 'filename' becomes current directory of filesel.
    */
void _set_filename(fs,char* filename);

struct _GtkFileSelectorExtensionInfo
{
    char* description;
	/* will be shown in popup or the like, 
	   e.g. "TIFF file format (.tiff)" - can be "" - then description 
	   will be constructed from patterns. If NULL, then it marks the last
	   item in the array of extension infos.
	*/

    char* canon_tail;
	/* e.g. ".tiff", - exactly that string will be appended to 
	  basename when that format is selected. If NULL, then 1st item 
	  in 'patterns[]' will be used.
	  */

    char* patterns[8];
	/* a list of suffixes, each element - one suffix, e.g.
	   ".tiff". Use NULL to teminate the list. Suffixes will be matched
	   case-insensitive.*/
	   
    gpointer user_data;
	/*
	    Arbitrary data writable by the user.	    
	*/
    gpointer engine_data;
	
	/*
	    Arbitrary data that shouldn't be changed by the user.
	*/
};
typedef struct _GtkFileSelectorExtensionInfo GtkFileSelectorExtensionInfo;

    /*
	Set extension infos. The item with NULL in .description terminates
	the array. 'default' is the index of default extension or -1 for 
	"All files".
	Widget will strdup these infos.
	It's safe to call this only once.
    */
void _set_extension_info(fs,GtkFileSelectorExtensionInfo* extinfo, int default);

    /*
	This sets index of default extension. -1 means "all files". Used mainly
	for setting widget's arguments.
    */
void _set_default_extension_info_index(fs,int idx);

    /*
	Returns extension info of default filename. If user didn't set any 
	extinfo information, then extinfo corresponding to 'all files' will
	be returned.
    */
GtkFileSelectorExtensionInfo* _get_default_extension_info(fs);

/*auxilary functions follow - no virtual function correspond to them.*/
    /*
	This is auxilary function used by engine implementation for freeing
	duplicated array of GtkFileSelectorExtensionInfo (every "valid" 
	string member will be freed).
    */
    
void _free_extension_info(GtkFileSelectorExtensionInfo* extinfo)

    /*
	This will return strdupped string.
step 1:	If filename doesn't contain slash, than name of filesel's current dir
	is prepended.
	
step 2:	If mode is GTK_FILESEL_MODE_SINGLE and role is GTK_FILESEL_ROLE_*OPEN,
	this will do the following:
	    if that file exist, it will return name verbatim.
	    if that file doesn't exist and its suffix matches current
		filter's suffix, filename will be returned verbatim;
	    otherwise canonical suffix for currently selected extension info
		will be appended to filename and returned
	otherwise result of step 1 will be returned.
    */
char* _get_filename_with_extension(GtkFileSelectorExtensionInfo* fs,
	char* filename)

typedef struct _GtkFileSelEngine
{
    /*
	This is used for quering various implementation-specific parameters
	(like engine name, version, properties).
    */
    GtkData data;
    /*
	This could return object of type derived from 'GtkFileSelector'
	(thus extending a set of arguments).
    */	
    GtkFileSelector* (*new_instance)(GtkFileSelMode mode,GtkFileSelRole role,
	char* detail);
        
    /*  the following member correspond to functions for dealing with FileSel*/

    /*  moves to specified directory and selects or places filename into 
	filename prompt. Engine should check whether the dir exists and do 
	all things like running signal handlers.
    */
    void (*set_path)(GtkFileSelector* fs,char* directory,char* filename);
    
    void (*clear_selection)(GtkFileSelector* fs);

    /*  allows to peek at list of selected files. The order of the files is 
	implementation-dependant.
    */
    GList* (*get_selection)(GtkFileSelector* fs);
    
    /*
	The list is owned by caller (so it should be freed by caller). 
	Implementation can reorder the list of filenames in any way it likes.
	If 'filenames' is NULL, then selection is cleared.
    */    
    void (*set_selection)(GtkFileSelector* fs,GList* filenames)


    /*	returns first item in the list (mostly for use by single file 
	selectors).
    */
    char* (*get_filename)(GtkFileSelector* fs);

    /*	clears selection. Selects only one file. If it's single fileselector,
	then dirname of 'filename' becomes current directory of filesel.
    */
    void (*set_filename)(GtkFileSelector* fs,char* filename);
    
    /*
	Set extension infos. The item with NULL in .description terminates
	the array. 'default' is the index of default extension or -1 for 
	"All files".
	
	The extinfo will be strdupped and "normalized". All that fs engine 
	should do is to free previous info using _free_extension_info, set the
	members to fs to new values (passed as argument) and recreate
	the widget that allows selection of extension.
    */
    void (*set_extension_info)(fs,GtkFileSelectorExtensionInfo* newextinfo, 
	    int newdefault);

    /*
	This sets index of default extension. -1 means "all files". 
	The value passed will already be validated.
    */
    void (*set_default_extension_info_index)(fs,int newidx);
} GtkFileSelEngine;

struct _GtkFileSelector
{
    GtkWindow window;/*it's derived from gtkwindow*/
    
    /*all members shouldn't be modified by apps*/
    GtkFileSelEngine* filesel_engine;
    /*next 2 members are private to implementation*/
    gpointer engine_data;
    gpointer widget_data;
    
    GtkFileSelMode mode;
    GtkFileSelRole role;
    char*	detail;/*that value is managed by the widget.*/
    
    /*current directory*/
    char* 	current_directory;    
    /*number of files and dirs (excluding . and ..) shown.*/
    guint nfiles;
    guint ndirs;
    
    /*these values contain filenames or NULL if nothing is focused.*/
    char* focused_file;
    char* focused_directory;    
    char* filename;/*the filename typed by user (most probably it will be
	equal to either 'focused_file' or 'focused_directory'.*/
	
    
    GtkFileSelectorExtensionInfo* extinfo;
    guint numextinfos;
    int current_extinfo;
    
    /*	the buttons will already have title appropriate for operation, but in 
	rare cases app can change them. */    
    GtkWidget*  ok_button;/*even if selection of file is performed by
	double click, this button will be clicked by filesel implementation.
	So app should trap dialog closing using this button. */
    
    
    GtkWidget*  cancel_button;
    
    GtkWidget* free_vbox;/*vbox to the right of the widget, where app can place
			    buttons*/
    GtkWidget* buttons_free_hbox;/*hbox where app can add additional buttons*/
};

signals (exported by GtkFileSelector):
    /*
	Called to check whether filename can be added to selection (only makes 
	sense for mutlifile selection). If 1 is returned, then file can be 
	added.
	Callback can popup something. If no handlers are attached, then 
	it's assumed that the file can be selected.
	
	Not used for single file selector.
    */
    gboolean "check-can-select-filename" (fs,filename,data);

    /*
	Called to check whether filename can be removed to selection (only 
	makes sense for mutlifile selection). If 1 is returned, then file can
	be added. Callback can popup some dialog. 

	Not used for single file selector.	
    */    
    gboolean "check-can-deselect-filename" (fs,filename,data);


    
    /*
	The next two are used for filtering of contents.
    */
    gboolean "can-show-filename"(fs,filename,data);
    gboolean "can-show-dirname"(fs,filename,data);    
    
    /*
	Not used for single file selector.	
    */
    void "selection-changed"(fs,data);
    
    
    /*
	This will be called when directory is changed or current directory 
	content is reloaded. Current directory name can be read directly from
	the widget.
    */
    void "directory-changed"(fs,char* olddirname,data);

    /*
	This is called when modifies filename to save to by editing its name in
	the entry (this has nothing to do with file renaming existing file).
    */
    void "filename-changed"(fs,data);    
    

    /*
	will be called when user puts focus on some file. 'file' is an object
	that is not directory and not symlink to directory.
    */    
    void "file-focus-in"(fs,char* filename,data)
    void "file-focus-out"(fs,char* filename,data)

    /*
	will be called when user puts focus on some directory. 'directory' is 
	an object that is directory or a symlink to directory.	
	
	It's guaranteed that that extactly zero or one file and directory will 
	be focused at time (i.e., one dir and one file, dir only, file only
	or nothing can be focused at a time). 
    */
    void "dir-focus-in"(fs,char* filename,data)
    void "dir-focus-out"(fs,char* filename,data)
    
    /*
	Current filter settings can be read directly from the widget.
    */
    void "extension-filter-changed"(fs,GtkFileSelectorExtensionInfo* old,data);
signals end


/*A typical use of file selector will be */
GtkFileSelector* fs =_new(GTK_FILESEL_MODE_SINGLE,GTK_FILESEL_ROLE_OPEN,"doc");
gtk_signal_connect(fs->ok_button,"clicked",ok_handler,NULL);
gtk_signal_connect(fs->cancel_button,"clicked",cancel_handler,NULL);
gtk_widget_show_all(GTK_WIDGET(fs));
/*....*/
char* filename = strdup(_get_filename(fs));
gtk_widget_destroy(GTK_WIDGET(fs));


 Best regards,
  -Vlad






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]