FLTK logo

Re: [RFE] STR #3520: Fixing a FileChooser feature

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.bugs  ]
 
Previous Message ]New Message | Reply ]Next Message ]

Re: [RFE] STR #3520: Fixing a FileChooser feature Albrecht Schlosser May 19, 2019  
 
DO NOT REPLY TO THIS MESSAGE.  INSTEAD, POST ANY RESPONSES TO THE LINK BELOW.

[STR New]

Link: https://www.fltk.org/str.php?L3520
Version: 1.4-feature


Thanks for the patches.

Note: Looking at the patches I found some embedded comments and some code
formatting issues. I created a new patch for FLTK 1.4 (based on commit
357dad1e5, uploaded as 'FileChooser.1.4.0_357dad1e5.diff') w/o comments and
some (probably not all) formatting fixes.

I'll also upload 'comments.txt' with all comments I found for reference.

I did not test or review the patch as such, i.e. for functionality, leaving
this for others for now.


Link: https://www.fltk.org/str.php?L3520
Version: 1.4-feature
From 18c592661fdfce7222dd9172874fc1efaaf47e7a Mon Sep 17 00:00:00 2001
From: Albrecht Schlosser <albrechts.fltk@online.de>
Date: Sun, 19 May 2019 14:01:32 +0200
Subject: [PATCH] Patch as given by OP in STR 3520

See: FileChooser.1.4.0.diff (inside .tar file)

Modified slightly to be closer to the FLTK coding standard:
 - remove trailing spaces
 - fix indenting
 - other minor formatting issues
---
 FL/Fl_File_Chooser.H     |  3 +-
 FL/filename.H            |  1 +
 src/Fl_File_Chooser.fl   |  4 +-
 src/Fl_File_Chooser2.cxx | 86 +++++++++++++++++++++++-----------------
 src/Fl_File_Input.cxx    | 28 ++++++++++---
 src/filename_isdir.cxx   |  6 +++
 6 files changed, 84 insertions(+), 44 deletions(-)

diff --git a/FL/Fl_File_Chooser.H b/FL/Fl_File_Chooser.H
index 4ce459ebf..6f3beac1f 100644
--- a/FL/Fl_File_Chooser.H
+++ b/FL/Fl_File_Chooser.H
@@ -65,6 +65,7 @@ private:
   void showChoiceCB(); 
   void update_favorites(); 
   void update_preview(); 
+  void activate_okButton_if_file();
 public:
   Fl_File_Chooser(const char *d, const char *p, int t, const char *title);
 private:
@@ -132,7 +133,7 @@ public:
   void color(Fl_Color c);
   Fl_Color color();
   int count(); 
-  void directory(const char *d); 
+  void directory(const char *d, bool f = true);
   char * directory();
   void filter(const char *p); 
   const char * filter();
diff --git a/FL/filename.H b/FL/filename.H
index 9d41008a9..cfda5d1fa 100644
--- a/FL/filename.H
+++ b/FL/filename.H
@@ -54,6 +54,7 @@ FL_EXPORT int fl_filename_absolute(char *to, int tolen, const char *from);
 FL_EXPORT int fl_filename_relative(char *to, int tolen, const char *from);
 FL_EXPORT int fl_filename_match(const char *name, const char *pattern);
 FL_EXPORT int fl_filename_isdir(const char *name);
+FL_EXPORT int fl_filename_isfile(const char *name);
 
 #  if defined(__cplusplus) && !defined(FL_DOXYGEN)
 /*
diff --git a/src/Fl_File_Chooser.fl b/src/Fl_File_Chooser.fl
index fca0a32f3..dcb80dc6f 100644
--- a/src/Fl_File_Chooser.fl
+++ b/src/Fl_File_Chooser.fl
@@ -68,6 +68,8 @@ class FL_EXPORT Fl_File_Chooser {open
   }
   decl {void update_preview();} {private local
   }
+  decl {void activate_okButton_if_file();} {
+  }
   Function {Fl_File_Chooser(const char *d, const char *p, int t, const char *title)} {} {
     code {if (!prefs_) {
   prefs_ = new Fl_Preferences(Fl_Preferences::USER, "fltk.org", "filechooser");
@@ -267,7 +269,7 @@ data_     = d;} {}
   }
   decl {int count();} {public local
   }
-  decl {void directory(const char *d);} {public local
+  decl {void directory(const char *d, bool f = true);} {public local
   }
   Function {directory()} {return_type {char *}
   } {
diff --git a/src/Fl_File_Chooser2.cxx b/src/Fl_File_Chooser2.cxx
index 80d842bcf..06b99e107 100644
--- a/src/Fl_File_Chooser2.cxx
+++ b/src/Fl_File_Chooser2.cxx
@@ -430,7 +430,8 @@ Fl_File_Chooser::count() {
 //
 
 void
-Fl_File_Chooser::directory(const char *d)// I - Directory to change to
+Fl_File_Chooser::directory(const char *d,// I - Directory to change to
+                       bool       f)// I - update file name field?
 {
   char	*dirptr;			    // Pointer into directory
   char  fixpath[FL_PATH_MAX];   // Path with slashes converted
@@ -489,6 +490,24 @@ Fl_File_Chooser::directory(const char *d)// I - Directory to change to
   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 (!fl_filename_isdir(fileName->value())) {
+      dirptr = strchr(pathname, 0);
+      strlcat(pathname, fl_filename_name(fileName->value()), sizeof(pathname));
+      if (!(type_ & CREATE) && !fl_filename_isfile(pathname))
+        *dirptr = 0;
+    }
+    fileName->value(pathname);
+  }
+
   if (shown()) {
     // Rescan the directory...
     rescan();
@@ -743,7 +762,10 @@ Fl_File_Chooser::fileListCB()
     if (*filename == '/') *filename = '\0';
 
 //    puts("Setting fileName from fileListCB...");
-    fileName->value(pathname);
+    if (!*pathname || fl_filename_isdir(pathname))
+      directory(pathname);
+    else
+      fileName->value(pathname);
 
     // Update the preview box...
     Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this);
@@ -753,7 +775,7 @@ Fl_File_Chooser::fileListCB()
     if (callback_) (*callback_)(this, data_);
 
     // Activate the OK button as needed...
-    if (!Fl::system_driver()->filename_isdir_quick(pathname) || (type_ & DIRECTORY))
+    if (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))
       okButton->activate();
     else
       okButton->deactivate();
@@ -818,7 +840,7 @@ Fl_File_Chooser::fileNameCB()
     if (Fl::system_driver()->colon_is_drive()) condition = isalpha(pathname[0] & 255) && pathname[1] == ':' && !pathname[2];
     if (!condition) condition = ( Fl::system_driver()->filename_isdir_quick(pathname) && compare_dirnames(pathname, directory_) );
     if (condition) {
-      directory(pathname);
+      directory(pathname, false);
     } else if ((type_ & CREATE) || fl_access(pathname, 0) == 0) {
       if (!Fl::system_driver()->filename_isdir_quick(pathname) || (type_ & DIRECTORY)) {
 	// Update the preview box...
@@ -853,7 +875,7 @@ Fl_File_Chooser::fileNameCB()
       int p = fileName->position();
       int m = fileName->mark();
 
-      directory(pathname);
+      directory(pathname, false);
 
       if (filename[0]) {
 	char tempname[FL_PATH_MAX];
@@ -933,22 +955,13 @@ Fl_File_Chooser::fileNameCB()
     }
 
     // See if we need to enable the OK button...
-    if (((type_ & CREATE) || !fl_access(fileName->value(), 0)) &&
-        (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) {
-      okButton->activate();
-    } else {
-      okButton->deactivate();
-    }
+    activate_okButton_if_file();
+
   } else {
     // FL_Delete or FL_BackSpace
     fileList->deselect(0);
     fileList->redraw();
-    if (((type_ & CREATE) || !fl_access(fileName->value(), 0)) &&
-        (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) {
-      okButton->activate();
-    } else {
-      okButton->deactivate();
-    }
+    activate_okButton_if_file();
   }
 }
 
@@ -1082,21 +1095,7 @@ Fl_File_Chooser::previewCB(Fl_File_Chooser *fc) {	// I - File chooser
 void
 Fl_File_Chooser::rescan()
 {
-  char	pathname[FL_PATH_MAX];		// 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->value(pathname);
-
-  if (type_ & DIRECTORY)
-    okButton->activate();
-  else
-    okButton->deactivate();
+  activate_okButton_if_file();
 
   // Build the file list...
   fileList->load(directory_, sort);
@@ -1470,7 +1469,7 @@ Fl_File_Chooser::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;
@@ -1495,12 +1494,16 @@ Fl_File_Chooser::value(const char *filename)
 
   if ((slash = strrchr(pathname, '/')) != NULL) {
     // Yes, change the display to the directory... 
-    if (!fl_filename_isdir(pathname)) *slash++ = '\0';
+    if (fl_filename_isdir(pathname))
+      slash = pathname;
+    else
+      *slash++ = '\0';
 
-    directory(pathname);
-    if (*slash == '/') slash = pathname;
+    directory(pathname, false);
+    if (!shown()) fileList->load(pathname);
+    if (slash > pathname) slash[-1] = '/';
   } else {
-    directory(".");
+    directory(".", false);
     slash = pathname;
   }
 
@@ -1525,6 +1528,15 @@ Fl_File_Chooser::value(const char *filename)
       break;
     }
 }
+
+void Fl_File_Chooser::activate_okButton_if_file() {
+
+  if (((type_ & CREATE) || !fl_access(fileName->value(), 0)) &&
+      (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY)))
+    okButton->activate();
+  else
+    okButton->deactivate();
+}
   
 void Fl_File_Chooser::show()
 {
diff --git a/src/Fl_File_Input.cxx b/src/Fl_File_Input.cxx
index 201101809..05e52aef0 100644
--- a/src/Fl_File_Input.cxx
+++ b/src/Fl_File_Input.cxx
@@ -266,12 +266,30 @@ Fl_File_Input::handle_button(int event)		// I - Event
 
   if (i < 0) {
     // Found the end; truncate the value and update the buttons...
-    *start = '\0';
-    value(newvalue, (int) (start - newvalue) );
+    const char *basename = 0;
+    if (!fl_filename_isdir(newvalue))
+      if (!*(basename = fl_filename_name(newvalue)))
+	basename = 0;
+
+    if (!basename)
+      *start = '\0';
+    else {
+      // Prevent users from cursing us: keep basename, if not a directory
+      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) && !fl_filename_isfile(newvalue))
+      //   *start = 0;
+      // else
+      if (start == basename) i = 0; // unchanged!
+    }
+    if (i < 0) {
+      value(newvalue);
 
-    // Then do the callbacks, if necessary...
-    set_changed();
-    if (when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE) ) do_callback();
+      // Then do the callbacks, if necessary...
+      set_changed();
+      if (when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE) ) do_callback();
+    }
   }
 
   return 1;
diff --git a/src/filename_isdir.cxx b/src/filename_isdir.cxx
index 5488f9131..e39ee11aa 100644
--- a/src/filename_isdir.cxx
+++ b/src/filename_isdir.cxx
@@ -81,6 +81,12 @@ int Fl_System_Driver::filename_isdir(const char* n) {
  \endcond
  */
 
+/** Returns true if the file exists and is a regular file. */
+int fl_filename_isfile(const char* name) {
+  struct stat s;
+  return !fl_stat(name, &s) && (s.st_mode & 0170000) == 0100000;
+}
+
 //
 // End of "$Id$".
 //
-- 
2.20.1

Direct Link to Message ]
 
     
Previous Message ]New Message | Reply ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.