Progress on GtkFileChooser



I've just imported a bunch of code and header files
into the gtkfilechooser/ module in GNOME CVS. 

There's lots of stuff working in there - UNIX and 
gnome-vfs backends, incremental filling, simple
completion.

But even more not - icons, bookmarks, having the
file selector return filenames typed in in Save
mode.

Some questions that might be asked:

- Why didn't you start from Y? You should look at 
  Y, it is much better than the pitiful attempt
  attempt at a UI you have there.

  My concern here was largely the API and a clean
  split between interface/GUI implementation/
  file system implementation. While other filesel
  implementations almost certainly farther along
  in functionality, I thought it was easiest to
  start from a clean slate.

- Why doesn't your UI do X?

  A) Because I haven't implemented it yet. B) Because
  you haven't implemented it yet. C) Because it's
  the wrong thing to do. 

  The user interface is there because I couldn't test
  out the pieces without a user interface but it
  is not meant as any sort of proposal for the
  final UI. 

  (I think there are some neat things about what I 
  did for the UI, I suspect that some people
  will like it. But nonetheless it is most likely
  wrong.)

  I'm hoping at this point we can start a UI design 
  process where we figure out some concrete criteria for
  the UI and get some mockups and functional prototypes
  for people to pay with. 

- Didn't you just do all the fun stuff and leave all
  the hard details for other people to do?

  Yes. So? 

  Actually, I think there is plenty of fun stuff
  left on the UI side of things, both in design
  and implementation. While I did grab off most
  of the API/architecture design work, and I think
  what I ended up is pretty functional, there is
  still room for adjustment there, and even major 
  changes if someone has better ideas.

- How the @$ ! do I compile this thing? Could you have
  made it any harder?

  It isn't *that* bad. It only requires glib-head, gtk-head,
  and a couple of patches to both. (Details in the
  README.)   Presumably, we'll get properties-on-interfaces
  into GLib at some time in the near future and the
  GtkTreeView fixes into GTK+.
  
- Aren't you just trying to steal all the oil?

README and TODO attached.

Regards,
                               Owen

Introduction
============

The code in this directory is the start of an implementation of the
file selector designed proposed in:

 http://people.redhat.com/otaylor/fosdem2003/file-selector.html

What is found here includes:

 - Header files for public, semi-public, and private interfaces that
   allow for flexible choices of UI backend and file systme back end.

 - Implementations of these interfaces.

 - A sample user interface backend .. GtkFileChooserImplDefault.

 - Several reusable components that are used to build
   GtkFileChooserImplDefault:
  
    GtkFileSystemModel  - GtkTreeModel wrapping a GtkFileSystem
    GtkFileChooserEntry - entry with completion

 - Two sample file system backends: GtkFileSystemUnix and
   GtkFilesystemGnomeVFS.

 - A small test program

It should be emphasized here that the user interface here should *not*
be considered final, or even a proposal as to what the final user
interface.

I'm not interested in critiques of this user interface; what would be
more useful would be complete proposals for how the user interface
should look including:

 - What elements should be present and how they should interact
 - Some rational for the above (how will people be using the file
   selector, what are the important tasks that should be easy to do,
   what is the relationship to file selectors that people are already
   familiar with, if any.)

Designs could be text only, or include mocked-up-screenshots, or
screenshots of a existing implementation. They could even include a
working or semi-working implementation along the lines of
GtkFileChooseImplDefault, but that's far from necessary.


API Design
==========

>From the application programmer's perspective, the API is extremely
simple:

 GtkFileChooser is an interface that represents a graphical file
 selecctor in a pretty straightforward fashion.

 GtkFileChooserWidget implements GtkFileChooser as an embeddable
 widget.

 GtkFileChooserWidget implements GtkFileChooser as an embeddable
 widget.

There is a second level of semi-public interfaces that won't be
exposed to applications but will be installed so that people can write
custom file system models. The two interfaces that a custom file
system model needs to implement are:

 GtkFileSystem - an entire file system

 GtkFileFolder - one folder within a GtkFileSystem

There are some auxiliary types that are used with GtkFileSystem and
GtkFileFolder... in particular, GtkFileInfo holds information about
the properties of a single file.


Implementation
==============

Just a few notes about the implementation here:

 - The intent was to break up the code so that relatively little
   code was actually in GtkFileChooserImplDefault and as much
   as possible in reusable components such as GtkFileChooserEntry
   and GtkFileSystemModel.

   This is to allow people to experiment with alternate UIs
   without having to duplicate a lot of code.

 - The way that GtkFileChooserDialog and GtkFileChooserWidget
   are implemented may be a little confusing. They way they 
   work is that they "delegate" the methods and properties
   GtkFileChooser to their child widget. 

   The utilities in gtkfilechooserutils.c are largely to
   avoid having to duplicate a bunch of code to do the
   delegation between the two widgets. 

Compiling
=========

The code here makes extensive use of properties on interfaces, which
aren't yet an official part of GLib, so you'll need to apply the
included glib-interface-properties-0.2.patch to your GLib.

It also uses instance-private-data, so you'll need to use CVS head of
GLib.

The GtkTreeView patches attached to:

 http://bugzilla.gnome.org/show_bug.cgi?id=109289
 http://bugzilla.gnome.org/show_bug.cgi?id=109292

Are also probably useful. The first fixes a warning that this code
triggers, the second is a massive performance improvement for
GtkTreeModelSort.


Files
=====

Public APIs:

 gtkfilechooser.[ch]
  Abstract interface for file selector GUIs
 gtkfilechooserwidget.[ch]
  Embeddable file selector widget
 gtkfilechooserdialog.[ch]
  File selector dialog

Semi-public APIs:

 gtkfilesystem.[ch]
  File selector dialog

Implementation details:
 
 gtkfilechooserentry.[ch]
  Entry with filename completion
 gtkfilechooserimpldefault.[ch]
  Default implementation of GtkFileChooser
 gtkfilechooserutils.[ch]
  Private utility functions useful for implementing a 
  GtkFileChooser interface
 gtkfilesystemgnomevfs.[ch]
  Implementation of GtkFileSystem for gnome-vfs
 gtkfilesystemmodel.[ch]
  GtkTreeModel wrapping a GtkFileSystem
 gtkfilesystemunix.[ch]
  Default implementation of GtkFileSystem for UNIX-like systems

Auto-generated enumeration types:

 gtkfilechooserenums.[ch]

Test Code:

 testfilechooser.c 
  Test program
 prop-editor.c
  Property editor code copied from gtk+/tests


Credits
=======

Many people contributed to ideas that appear in this code; the basic
organization is partly derived from a proposal by Havoc Pennington who
did a massive API review of existing file selectors.

Various ideas were taking from EggFileSystem as implemented by Bastien
Nocera.

Credit should also be given to all those people who wrote alternate
GTK+ file selectors that I foolishly ignored when writing this. Among
others Jacob Berkman and the Anjuta team have done file selectors
that are prettier, more functional and perhaps even better designed
than this.


License
=======

The code in this directory is licensed under the GNU Library General
Public License (see the COPYING file.)

Most code here is copyright Red Hat Inc, 2003. gtkfilesystemgnomevfs.c
also contains a small amount of code taken from libeel and copyright
1999, 2000 Eazel, Inc.

Owen Taylor
26 March 2003
Not yet implemented
===================

 - The filename portions of the GtkFileChooser API ...  currently,
   only the URI based function calls are present.

 - Preview widget. The properties and API for this are mostly there,
   but there is no implementation in
   GtkFileChooserImplDefault. Implementing this should be relatively
   easy (basically just packing the widget into the chooser); a test
   case of some sort would also need to be added to testfilechooser.

 - Filtering. gtkfilechooser.h has some bits that are #if 0'ed out,
   but they aren't finalized and absolutely nothing has been
   implemented.  gtkfilesystemmodel.c:file_model_node_is_visible

 - A reference widget. For displaying authentication dialogs, and some
   types of error dialogs the file system *model* needs to get a
   pointer to a window to use as a transient parent.

 - Icons. Nothing is currently implemented in this area at all. There
   probably needs to be some adaptation of the current API so that
   sizes can be worked out properly. One possibility is that instead
   of of GdkPixbuf, GdkIconInfo should contain a handle that can be
   rendered at multiple sizes. This is especially important if, as
   currently, one GdkIconInfo is cached for multiple views.

 - Mime types for GtkFileSystemUnix ... we should probably include an
   implementation of the new standard mime type spec being discussed
   on xdg-list freedesktop org

 - Loading notification. GtkFileFolder should probably have signals so
   that someone that is using it can tell when the initial load
   finishes and display appropriate feedback to the user. You'd then
   want to propagate that in some way to the GtkFileSystemModel
   interface (is any referenced folder currently loading?) to allow
   the file selector to display feedback or keep the selected row
   scrolled visible during the incremental load.

 - Network URI's for GtkFileSystemGnomeVFS ... there is a need to tie
   every URI back to a file system root, at least for the sample
   chooser user interface with the tree. (And for sanity, in general.)

   Probably the right way to do this is to have a special root - say
   'network-servers:' that has as children the toplevel URI for every
   referenced network folder:

    network-servers:
      http://www.gnome.org/
      ftp://ftp.gnome.og

   Or whatever.

 - Most-recently-used and/or bookmarks. The file system object should
   provide a change notified list or lists. Should it also have ways
   of adding bookmarks and/or a "do the manage bookmarks thing" call?

 - Interaction of the entry line with the "selected_uris" In single
   selection mode, it's something like:
   
    - In save mode contents of the entry line should be the result
      unless it is empty, in which case if there is a file selected in
      the list view, it should be the result. In open mode, the
      selected URI in the list view is canonical since an existing
      file must be selected.
  
    - If the user types a file in the entry line that matches the name
      of a file in the list view, that file should be selected and
      scrolled to.

   In multiple selection mode, things get more complicated.
   GtkFileSelection has the right logic for this (involving a concept
   of the last file selected)

 - Folder mode ... not really working with GtkFileChooserImplDefault

 - The final mechanism for selecting a GtkFileSystem and loading 
   it from a dynamically loaded module needs to be decided upon.
   When that is done, the file-system construct property for 
   GtkFileChooser can be removed.

Possible major API changes
==========================

 - Right now, there are two types of file/folder identifications in
   the API - filenames and URI's. There is a fairly strong argument
   for changing this to a threeway split:

    Opaque Reference
    File
    URI
   
   With vfuncs in GtkFileSystem for converting opaque references to
   either files or URIs. Using URI's all over the api works well for
   GtkFileSystemGnomeVFS but badly/inefficiently for
   GtkFileSystemUnix.

   The opaque reference could either be just a string ... simplest but
   can involve copies, or it could be some sort of more complex
   reference counted object. (See EggFileSystemItem (?)  in libegg for
   an example of how this could work.)

   Note that GtkFileSystemModel needs to be able to sort the
   references for the children of a model in a way that is stable
   against multiple readdirs/insertions/deletions, which it currently
   does with strcmp() against the URI.

   We also need to decide exactly how the encoding of file:// URIs
   work:

   The GLib scheme of file:// uri's always being UTF-8 encoded (then
   octet encoded) has the problem of not being able to represent
   invalid-encoded URI's at all. It also depends on the receiver and
   the sender thinking the same things about how filenames are encoded
   on diesk.

   The Nautilus scheme of matching the filesystem encoding encoded as
   octets may not be entirely RFC compliant (it wasn't very clear last
   time I looked) displaying the URI's contents to the user may also be
   difficult (but no harder than displaying a filename.)
   

API tweaks
==========

 - We need GTK_FILE_SYSTEM_ERROR_PERMISSION

 - The names gtk_file_info_get_is_folder(), etc, are a little
   strange. Maybe it would be better to go with the asymmetrical pair

    gtk_file_info_set_is_folder()/gtk_file_info_is_folder()
 
 - The docs for gtk_file_system_parse() describe it looking at the
   file system, but neither implementation does so
   currently. (Authentication might require blocking, so we can't tell
   definitively whether some directory exists in a synchronous
   fashion.)

 - Moving the GtkFileChooserIface structure private would simplifiy
   the public headers and also allow us to refer to
   GtkFileSystem-specific stuff in the virtual functions if necessary.

 - The GtkFileChooserIface functions would look cleaner if they didn't
   have _uri() in the names. Since we don't have the filename/uri
   pairs in the vfuncs, there probably is no need for the _uri() in
   the names.

 - There is no way of telling whether a display name is an exact
   reconvertable representation of the filename or an approximation of
   a misencoded filename. This is needed to know whether we should
   fill in the entry or not. Possible API:

    gtk_file_info_set_display_name (info, display_name, exact);
    gtk_file_info_get_display_name (info)
    gtk_file_info_get_display_name_exact (info)
    

Implementation strutural changes
================================

 - Right now, every GtkFileSystemModel and GtkFileEntry separately
   talks the GtkFileSystemModel. This results in duplicate loading and
   duplicate storage. A better model might be:

     GtkFileSytemModel  GtkFileSystemModel  GtkFileEntry
            |                   |                |
            \-------------------|----------------/
                                |
                          GtkFileStore
                                |
                          GtkFileSystem

   Where GtKFileStore would basically be the tree of nodes in
   GtkFileSystemModel and GtkFileSystemModel would be a lightweight
   object.

   There are some things that would make this rather challenging:

    - Paths are different for each GtkFileSystemModel attached to the
      same GtkFileStore, which makes it difficult when we need to emit
      notificatins.
  
    - Visibility is different for each GtkFileSystemModel.  (idea -
      limit it to 32 Models for each Store, use a bitfield.)

    - Whether you have dummy nodes or not is different ..  Probably
      the way you want to do a dummy node is to use a second field in
      the iter structure to indicate that "this iter points to a dummy
      child of iter->user_data" rather than actually storing dummy
      nodes.

Implementation Details
======================

 - Going to an unreadable directory crashes the file selector
   currently. We probably should detect when a directory is obviously
   unreadable and not allow the user to go there at all (possibly gray
   out the directory if we have a directory tree) However for remote
   file systems we won't find about the unreadability until later.
  
   The KDE file selector allows you to go into an unreadable directory
   then shows something along the lines of "you don't have permissions
   to read this directory" instead of the file list.

 - The stat() calls in gtkfilesystemunix.c probably aren't properly
   gettting the sizes of >2GB files. Do we need to
   -D_FILE_OFFSET_BITS=64? I think gnome-vfs probably has the right
   configure checks.

 - Error checking is messy and sloppy currently. All the places with a
   /* NULL-GError */ comment need to be checked through to see whether
   we actually should be propagated the error back up, displaying it
   to the user.

 - Currently, there are memory leaks all over the place, effort has to
   be spent to make sure that folders get unreferenced, that when they
   get unreferenced fully, everything gets freed, etc.

 - GtkFileSystemModel has considerable duplicated in the area of
   creating child nodes and creating dummy nodes that should be
   factored out.

 - GtkFileSystemGnomeVFS has duplicated code to create and fill in
   FolderChild structures that should be factored out.

 - GtkFileSystemGnomeVFS shares folders between callers, but if the
   second caller wants more types of information than the first
   caller, things don't work.  ensure_types() needs to be
   implemented. (Note that refetching information may need to cause a
   ::changed signal if the already existing information is changed.
   Also, the refetch should likely be done using the GnomeVFS async
   API's) This is not particularly simple.

 - gtkfilesystemmodel.c:model_refilter_recurse() doesn't properly
   handle inserting the dummy node if on refiltering there are no
   visible nodes.

Efficiency improvements
=======================

 - Many parts of FileModelNode are folder-only. It's probably better
   to use a union for file-only and folder-only parts and then just
   allocate the node as big as necessary. (This requires knowing
   file-vs-folder when before allocating the node, but we always check
   immediately after anyways.)

 - When we create a new GtkFileSystemModel, we first create it showing
   both files and folders, then call set_show_files() or
   set_show_folders(), causing an immediate
   refilter. show_files/show_folders probably should be arguments to
   the constructor.

 - gtkfilesystmemodel.c:do_files_removed() has to walk through all the
   child nodes just to figure out whether a dummy node needs to be
   inserted.

   We probably should track the visible count in the node rather than
   just a one bit flag. (See above comment about using different sized
   nodes for folders and files.)

   Though removing nodes isn't common, so this doesn't matter a whole
   lot; it's just a bit ugly.

Other stuff
===========
 
 - Documentation comments for all public and semi-public functions
   need to be finished.


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