Hello,

using the Dillo web-browser i could experience a rather nasty nuisance:
whenever changing directory in the dialog for choosing where to save a
file, the (suggested or just before selected) filename is erased and
only the directory is displayed for further selecting...

Attached you find a patch, that will fix this issue.


kind regards

peter

        Using the Dillo web-browser i could experience some rather nasty
        nuisance: whenever changing directory in the dialog for choosing
        where to save a file, the (suggested or just before selected)
        filename is erased and only the directory is displayed for
        further selecting.
        Closer examination showed that there is no way to change this
        behaviour outside FLTK, that in fact fltk::FileChooser was the
        culprit.

        So, here comes a patch to fix this issue (i hope to use FLTK's
        next release "out of the box" ;-):

        1) FileChooser::directory(..) no longer simply overwrites
           fileName with directory_. Now it retains the basename in
           there, if it is not a directory and is existing or to be
           created.
           The actual work is now done by a private directory(..), that
           allows to control whether fileName should be overwritten by
           directory_ at all (e.g. given, when called from FileChooser::
           value(..)).

        2) Changing directory in FileInput::handle_button(..) now also
           retains the basename if appropriate, since it looks - let's
           say - not easy to handle this correctly at an upper level.
           (It maybe possible though, by examining the FileInput flags
           - fileNameCB(FileInput*,void*) instead of fileNameCB() - to
           find out how the change was done and by always maintaining
           an additional fileName-backup in FileChooser. But didn't do
           any deeper investigation into that yet.)

        besides:

        3) Consistency of directory_ and fileName is now forced upon
           return from each of public FileChooser::directory(..) and
           FileChooser::value(..).  FileChooser::rescan() is no longer
           involved in updating/overwriting fileName.
           (IMHO, rescan() is really not the place to do that. Let alone
           making this adjustment dependent on window state!)          


        FYI: Debugging/testing was actually done with fltk-2.0.x-r6671 on
        Linux (i86,Mips) with gcc, but the affected files are still identical
        in fltk-2.0.x-r7725, the issue is not OS-related and the changes are
        not the kind to cause problems for any decent compiler.




--- fltk-2.0.x-r7725/fltk/FileChooser.h Fri Feb 22 23:50:59 2008
+++ fltk-2.0.x-r7725/fltk/FileChooser.h Mon Oct 25 00:37:44 2010
@@ -43,6 +43,8 @@
   void update_favorites();
   void update_preview();
   int favorites_showing;
+  void activate_okButton_if_file();
+  void directory(const char *d, bool);
 public:
   FileChooser(const char *d, const char *p, int t, const char *title);
 private:


        Was it intentional to define the FileInput::text methods here,
        but to leave any call to one of the (heavily used) value methods
        falling back to a base-class Input::value method ?  If so, some
        comment should have explained this.  To me it didn't make any
        sense, and so these are supplemented here:

--- fltk-2.0.x-r7725/fltk/FileInput.h   Thu Mar 30 11:55:32 2006
+++ fltk-2.0.x-r7725/fltk/FileInput.h   Mon Oct 25 00:37:44 2010
@@ -55,7 +55,11 @@
   void                 errorcolor(Color c) { errorcolor_ = c; }
   int                  text(const char*);
   int                  text(const char*, int);
-  const char *         text() { return Input::text(); }
+  const char *         text() const { return Input::text(); }
+
+  int          value(const char* v) { return text(v); }
+  int          value(const char* v, int n) { return text(v,n); }
+  const char*  value() const { return text(); }
 };
 
 }


--- fltk-2.0.x-r7725/fltk/filename.h    Wed Oct 22 09:01:02 2008
+++ fltk-2.0.x-r7725/fltk/filename.h    Mon Oct 25 00:37:44 2010
@@ -111,6 +111,7 @@
 FL_API bool filename_match(const char *, const char *pattern); // glob match
 FL_API bool filename_exist(const char*);
 FL_API bool filename_isdir(const char*);
+FL_API bool filename_isfile(const char*);
 FL_API FL_FILESIZE_T filename_size(const char *); // return size of file
 FL_API long int filename_mtime(const char *); // return modification time
 


        The distributed src/FileChooser.fl didn't exactly reproduce the
        related fltk/FileChooser.h and src/FileChooser.cxx files, so i
        didn't use it to (re)generate the code and this patch is provided
        for completeness' sake only:

--- fltk-2.0.x-r7725/src/FileChooser.fl Thu Mar 20 17:32:46 2008
+++ fltk-2.0.x-r7725/src/FileChooser.fl Mon Oct 25 00:37:44 2010
@@ -62,6 +62,8 @@
     decl {void update_favorites();} {}
     decl {void update_preview();} {}
     decl {int favorites_showing;} {}
+    decl {void activate_okButton_if_file();} {}
+    decl {void directory(const char *d, bool);} {}
     Function {FileChooser(const char *d, const char *p, int t, const char 
*title)} {open
     } {
       {fltk::Window} window {


--- fltk-2.0.x-r7725/src/FileChooser2.cxx       Tue Jun 17 02:48:20 2008
+++ fltk-2.0.x-r7725/src/FileChooser2.cxx       Mon Oct 25 00:37:44 2010
@@ -157,6 +157,13 @@ FileChooser::count() {
 void
 FileChooser::directory(const char *d)// I - Directory to change to
 {
+  return directory(d, true);
+}
+
+void
+FileChooser::directory(const char *d,// I - Directory to change to
+                       bool       f)// I - update file name field?
+{
   char *dirptr;                        // Pointer into directory
 
 
@@ -218,6 +225,24 @@ FileChooser::directory(const char *d)// 
   else
     directory_[0] = '\0';
 
+  if (f) {
+    // Update the current filename accordingly...
+    char pathname[sizeof(directory_)]; // New pathname for filename field
+
+    strlcpy(pathname, directory_, sizeof(pathname));
+    if (pathname[0] && pathname[strlen(pathname) - 1] != '/')
+      strlcat(pathname, "/", sizeof(pathname));
+
+    // Prevent users from cursing us: keep basename, if not a directory
+    if (!fltk::filename_isdir(fileName->text())) {
+      dirptr = strchr(pathname, 0);
+      strlcat(pathname, fltk::filename_name(fileName->text()), 
sizeof(pathname));
+      if (!(type_ & CREATE) && !fltk::filename_isfile(pathname))
+        *dirptr = 0;
+    }
+    fileName->text(pathname);
+  }
+
   if (shown()) {
     // Rescan the directory...
     rescan();
@@ -421,7 +446,7 @@ FileChooser::fileListCB()
 #endif /* WIN32 || __EMX__ */
     {
       // Change directories...
-      directory(pathname);
+      directory(pathname, true);
 
       // Reset the click count so that a click in the same spot won't
       // be treated as a triple-click.  We use a value of -1 because
@@ -464,7 +489,10 @@ FileChooser::fileListCB()
     if (*filename == '/') *filename = '\0';
 
 //    puts("Setting fileName from fileListCB...");
-    fileName->value(pathname);
+    if (fltk::filename_isdir(pathname))
+      directory(pathname, true);
+    else
+      fileName->value(pathname);
 
     // Update the preview box...
     fltk::remove_timeout((TimeoutHandler)previewCB, this);
@@ -474,7 +502,7 @@ FileChooser::fileListCB()
     if (callback_) (*callback_)(this, data_);
 
     // Activate the OK button as needed...
-    if (!fltk::filename_isdir(pathname) || (type_ & DIRECTORY))
+    if (!fltk::filename_isdir(fileName->text()) || (type_ & DIRECTORY))
       okButton->activate();
     else
       okButton->deactivate();
@@ -541,7 +569,7 @@ void FileChooser::fileNameCB() {
     if (fltk::filename_isdir(pathname) &&
        compare_dirnames(pathname, directory_)) {
 #endif /* WIN32 || __EMX__ */
-      directory(pathname);
+      directory(pathname, false);
     } else if ((type_ & CREATE) || access(pathname, 0) == 0) {
       if (!fltk::filename_isdir(pathname) || (type_ & DIRECTORY)) {
        // Update the preview box...
@@ -580,7 +608,7 @@ void FileChooser::fileNameCB() {
       int p = fileName->position();
       int m = fileName->mark();
 
-      directory(pathname);
+      directory(pathname, false);
 
       if (filename[0]) {
        char tempname[1024];
@@ -663,22 +691,13 @@ void FileChooser::fileNameCB() {
     }
 
     // See if we need to enable the OK button...
-    if (((type_ & CREATE) || !access(fileName->text(), 0)) &&
-        (!fltk::filename_isdir(fileName->text()) || (type_ & DIRECTORY))) {
-      okButton->activate();
-    } else {
-      okButton->deactivate();
-    }
+    activate_okButton_if_file();
+
   } else {
     // fltk::DeleteKey or fltk::BackSpace
     fileList->deselect(0);
     fileList->redraw();
-    if (((type_ & CREATE) || !access(fileName->text(), 0)) &&
-        (!fltk::filename_isdir(fileName->text()) || (type_ & DIRECTORY))) {
-      okButton->activate();
-    } else {
-      okButton->deactivate();
-    }
+    activate_okButton_if_file();
   }
 }
 
@@ -822,21 +841,7 @@ FileChooser::previewCB(FileChooser *fc) 
 void
 FileChooser::rescan()
 {
-  char pathname[1024];         // New pathname for filename field
-
-
-  // Clear the current filename
-  strlcpy(pathname, directory_, sizeof(pathname));
-  if (pathname[0] && pathname[strlen(pathname) - 1] != '/') {
-    strlcat(pathname, "/", sizeof(pathname));
-  }
-//  puts("Setting fileName in rescan()");
-  fileName->text(pathname);
-
-  if (type_ & DIRECTORY)
-    okButton->activate();
-  else
-    okButton->deactivate();
+  activate_okButton_if_file();
 
   // Build the file list...
   fileList->load(directory_, sort);
@@ -1103,7 +1108,7 @@ FileChooser::value(const char *filename)
   // See if the filename is the "My System" directory...
   if (filename == NULL || !filename[0]) {
     // Yes, just change the current directory...
-    directory(filename);
+    directory(filename, false);
     fileName->value("");
     okButton->deactivate();
     return;
@@ -1125,25 +1130,24 @@ FileChooser::value(const char *filename)
 
   // See if there is a directory in there...
   fltk::filename_absolute(pathname, sizeof(pathname), filename);
-  char dir[1024]="";
-  strlcpy(dir,pathname,sizeof(dir));
-  if ((slash = strrchr(dir, '/')) != NULL) {
+  if ((slash = strrchr(pathname, '/')) != NULL) {
     // Yes, change the display to the directory... 
-    if (!fltk::filename_isdir(dir)) *slash++ = '\0';
+    if (fltk::filename_isdir(pathname))
+      slash = pathname;
+    else
+      *slash++ = 0;
 
-    directory(dir);
-    if (!shown()) fileList->load(dir);
-    if (*slash == '/') slash = dir;
+    directory(pathname, false);
+    if (!shown()) fileList->load(pathname);
+    if (slash > pathname) slash[-1] = '/';
   } else {
-    directory(".");
-    slash = dir;
+    directory(".", false);
+    slash = pathname;
   }
 
   // Set the input field to the absolute path...
-  if (slash > dir) slash[-1] = '/';
-
-  if (slash && *slash) fileName->value(pathname);
-  fileName->position(0, strlen(dir));
+  fileName->value(pathname);   // Why "if(*slash)..." ?
+  fileName->position(0, strlen(pathname));
   okButton->activate();
 
   // Then find the file in the file list and select it...
@@ -1165,6 +1169,17 @@ FileChooser::value(const char *filename)
       okButton->activate();
       break;
     }
+}
+
+
+void
+FileChooser::activate_okButton_if_file()
+{
+    if (((type_ & CREATE) || !access(fileName->text(), 0)) &&
+        (!fltk::filename_isdir(fileName->text()) || (type_ & DIRECTORY)))
+      okButton->activate();
+    else
+      okButton->deactivate();
 }
 
 


        class FileInput should have some 'ftype_' field (CREATE, DIRECTORY,
        ...) to reflect its caller's intentions. For now - since the input
        is checked for "(type_ & CREATE) || fltk::filename_isfile()" at the
        upper level (FileChooser) anyway - we get away without defining it
        and its corresponding methods (leaving a FileInput object even
        binary compatible :-)

--- fltk-2.0.x-r7725/src/FileInput.cxx  Tue Jun 26 20:49:21 2007
+++ fltk-2.0.x-r7725/src/FileInput.cxx  Mon Oct 25 00:37:44 2010
@@ -27,6 +27,7 @@
 //
 
 #include <fltk/FileInput.h>
+#include <fltk/filename.h>
 #include <fltk/Window.h>
 #include <fltk/draw.h>
 #include <fltk/damage.h>
@@ -333,13 +334,33 @@ FileInput::handle_button(int event)               // 
     }
 
     if (i < 0) {
+       char c = *start; // possibly start == basename
+       const char *basename = 0;
+       if (!fltk::filename_isdir(newtext))
+           if (!*(basename = fltk::filename_name(newtext)))
+               basename = 0;
+
        // Found the end; truncate the text and update the buttons...
        *start = '\0';
-       text(newtext, start - newtext);
 
-       // Then do the callbacks, if necessary...
-       set_changed();
-       if (when() & WHEN_CHANGED) do_callback();
+       // Prevent users from cursing us: keep basename, if not a directory
+       if (basename) {
+           *start = c;
+           memmove(start, basename, strlen(basename)+1);
+           // Should have some 'ftype_' field to reflect the caller's
+           // intentions, but for now we get along without...
+           //if (!(ftype_ & CREATE) && !fltk::filename_isfile(newtext))
+               //*start = 0;
+           //else
+               if (start == basename) i = 0; // unchanged!
+       }
+       if (i < 0) {
+           text(newtext);
+
+           // Then do the callbacks, if necessary...
+           set_changed();
+           if (when() & WHEN_CHANGED) do_callback();
+       }
     }
 
     return 1;


--- fltk-2.0.x-r7725/src/filename_isdir.cxx     Thu Feb 21 01:43:54 2008
+++ fltk-2.0.x-r7725/src/filename_isdir.cxx     Mon Oct 25 00:37:44 2010
@@ -71,6 +71,12 @@ bool fltk::filename_isdir(const char* na
   return (last_stat.st_mode&0170000)==0040000;
 }
 
+/** Returns true if the file exists and is a regular file. */
+bool fltk::filename_isfile(const char* name) {
+  if (!fill_stat(name)) return false;
+  return (last_stat.st_mode&0170000)==0100000;
+}
+
 /** Returns the size of the file in bytes. Returns zero if it does not exist.*/
 FL_FILESIZE_T fltk::filename_size(const char* name) {
   if (!fill_stat(name)) return 0;
_______________________________________________
fltk-bugs mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk-bugs

Reply via email to