diff options
| author | Michael R Sweet <michael.r.sweet@gmail.com> | 2001-09-29 14:38:59 +0000 |
|---|---|---|
| committer | Michael R Sweet <michael.r.sweet@gmail.com> | 2001-09-29 14:38:59 +0000 |
| commit | 6a4714ce12d546c8131389853fe5593555c73b77 (patch) | |
| tree | 158726de167a805d6aaa325f8250b89bf3a2db08 /src/Fl_File_Chooser2.cxx | |
| parent | de6c7f66eeaeeae52ca33221db885ae6cd7ea114 (diff) | |
Fl_FileXYZ -> Fl_File_XYZ
Fl_HelpXYZ -> Fl_Help_XYZ
Fl_File_Chooser now supports directory choosing.
Added fl_dir_chooser() function.
Now set FLTK_DOCDIR env var in test/demo.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1612 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_File_Chooser2.cxx')
| -rw-r--r-- | src/Fl_File_Chooser2.cxx | 688 |
1 files changed, 688 insertions, 0 deletions
diff --git a/src/Fl_File_Chooser2.cxx b/src/Fl_File_Chooser2.cxx new file mode 100644 index 000000000..801c6050d --- /dev/null +++ b/src/Fl_File_Chooser2.cxx @@ -0,0 +1,688 @@ +// +// "$Id: Fl_File_Chooser2.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $" +// +// More Fl_File_Chooser routines. +// +// Copyright 1999-2001 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@fltk.org". +// +// Contents: +// +// Fl_File_Chooser::directory() - Set the directory in the file chooser. +// Fl_File_Chooser::count() - Return the number of selected files. +// Fl_File_Chooser::value() - Return a selected filename. +// Fl_File_Chooser::up() - Go up one directory. +// Fl_File_Chooser::newdir() - Make a new directory. +// Fl_File_Chooser::rescan() - Rescan the current directory. +// Fl_File_Chooser::fileListCB() - Handle clicks (and double-clicks) in the +// FileBrowser. +// Fl_File_Chooser::fileNameCB() - Handle text entry in the FileBrowser. +// + +// +// Include necessary headers. +// + +#include <FL/Fl_File_Chooser.H> +#include <FL/filename.H> +#include <FL/fl_ask.H> +#include <FL/x.H> + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <ctype.h> + +#if defined(WIN32) +# include <direct.h> +# include <io.h> +#else +# include <unistd.h> +# include <pwd.h> +#endif /* WIN32 */ + + +// +// 'Fl_File_Chooser::directory()' - Set the directory in the file chooser. +// + +void +Fl_File_Chooser::directory(const char *d) // I - Directory to change to +{ + char pathname[1024], // Full path of directory + *pathptr, // Pointer into full path + *dirptr; // Pointer into directory + int levels; // Number of levels in directory + + +// printf("Fl_File_Chooser::directory(\"%s\")\n", d == NULL ? "(null)" : d); + + // NULL == current directory + if (d == NULL) + d = "."; + + if (d[0] != '\0') + { + // Make the directory absolute... +#if defined(WIN32) || defined(__EMX__) + if (d[0] != '/' && d[0] != '\\' && d[1] != ':') +#else + if (d[0] != '/' && d[0] != '\\') +#endif /* WIN32 || __EMX__ */ + filename_absolute(directory_, d); + else + { + strncpy(directory_, d, sizeof(directory_) - 1); + directory_[sizeof(directory_) - 1] = '\0'; + } + + // Strip any trailing slash and/or period... + dirptr = directory_ + strlen(directory_) - 1; + if (*dirptr == '.') + *dirptr-- = '\0'; + if ((*dirptr == '/' || *dirptr == '\\') && dirptr > directory_) + *dirptr = '\0'; + } + else + directory_[0] = '\0'; + + // Clear the directory menu and fill it as needed... + dirMenu->clear(); +#if defined(WIN32) || defined(__EMX__) + dirMenu->add("My Computer"); +#else + dirMenu->add("File Systems"); +#endif /* WIN32 || __EMX__ */ + + levels = 0; + for (dirptr = directory_, pathptr = pathname; *dirptr != '\0';) + { + if (*dirptr == '/' || *dirptr == '\\') + { + // Need to quote the slash first, and then add it to the menu... + *pathptr++ = '\\'; + *pathptr++ = '/'; + *pathptr++ = '\0'; + dirptr ++; + + dirMenu->add(pathname); + levels ++; + pathptr = pathname; + } + else + *pathptr++ = *dirptr++; + } + + if (pathptr > pathname) + { + *pathptr = '\0'; + dirMenu->add(pathname); + levels ++; + } + + dirMenu->value(levels); + + // Rescan the directory... + rescan(); +} + + +// +// 'Fl_File_Chooser::count()' - Return the number of selected files. +// + +int // O - Number of selected files +Fl_File_Chooser::count() +{ + int i; // Looping var + int count; // Number of selected files + const char *filename; // Filename in input field or list + char pathname[1024]; // Full path to file + + + if (!(type_ & MULTI)) + { + // Check to see if the file name input field is blank... + filename = fileName->value(); + if (filename == NULL || filename[0] == '\0') + return (0); + + // Is the file name a directory? + if (directory_[0] != '\0') + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } + + if (filename_isdir(pathname)) + return (0); + else + return (1); + } + + for (i = 1, count = 0; i <= fileList->size(); i ++) + if (fileList->selected(i)) + { + // See if this file is a directory... + filename = (char *)fileList->text(i); + if (directory_[0] != '\0') + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } + + if (!filename_isdir(pathname)) + count ++; + } + + return (count); +} + + +// +// 'Fl_File_Chooser::value()' - Return a selected filename. +// + +const char * // O - Filename or NULL +Fl_File_Chooser::value(int f) // I - File number +{ + int i; // Looping var + int count; // Number of selected files + const char *name; // Current filename + static char pathname[1024]; // Filename + directory + + + if (!(type_ & MULTI)) + { + name = fileName->value(); + if (name[0] == '\0') + return (NULL); + + sprintf(pathname, "%s/%s", directory_, name); + return ((const char *)pathname); + } + + for (i = 1, count = 0; i <= fileList->size(); i ++) + if (fileList->selected(i)) + { + // See if this file is a directory... + name = fileList->text(i); + sprintf(pathname, "%s/%s", directory_, name); + + if (!filename_isdir(pathname)) + { + // Nope, see if this this is "the one"... + count ++; + if (count == f) + return ((const char *)pathname); + } + } + + return (NULL); +} + + +// +// 'Fl_File_Chooser::value()' - Set the current filename. +// + +void +Fl_File_Chooser::value(const char *filename) // I - Filename + directory +{ + int i, // Looping var + count; // Number of items in list + char *slash; // Directory separator + char pathname[1024]; // Local copy of filename + + +// printf("Fl_File_Chooser::value(\"%s\")\n", filename == NULL ? "(null)" : filename); + + // See if the filename is actually a directory... + if (filename == NULL || !filename[0] || filename_isdir(filename)) + { + // Yes, just change the current directory... + directory(filename); + return; + } + + // Switch to single-selection mode as needed + if (type_ & MULTI) + type(SINGLE); + + // See if there is a directory in there... + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + + if ((slash = strrchr(pathname, '/')) == NULL) + slash = strrchr(pathname, '\\'); + + if (slash != NULL) + { + // Yes, change the display to the directory... + *slash++ = '\0'; + directory(pathname); + } + else + slash = pathname; + + // Set the input field to the remaining portion + fileName->value(slash); + fileName->position(0, strlen(slash)); + okButton->activate(); + + // Then find the file in the file list and select it... + count = fileList->size(); + + for (i = 1; i <= count; i ++) + if (strcmp(fileList->text(i), slash) == 0) + { + fileList->select(i); + break; + } +} + + +// +// 'Fl_File_Chooser::up()' - Go up one directory. +// + +void +Fl_File_Chooser::up() +{ + char *slash; // Trailing slash + + + if ((slash = strrchr(directory_, '/')) == NULL) + slash = strrchr(directory_, '\\'); + + if (directory_[0] != '\0') + dirMenu->value(dirMenu->value() - 1); + + if (slash != NULL) + *slash = '\0'; + else + { + upButton->deactivate(); + directory_[0] = '\0'; + } + + rescan(); +} + + +// +// 'Fl_File_Chooser::newdir()' - Make a new directory. +// + +void +Fl_File_Chooser::newdir() +{ + const char *dir; // New directory name + char pathname[1024]; // Full path of directory + + + // Get a directory name from the user + if ((dir = fl_input("New Directory?", NULL)) == NULL) + return; + + // Make it relative to the current directory as needed... +#if defined(WIN32) || defined(__EMX__) + if (dir[0] != '/' && dir[0] != '\\' && dir[1] != ':') +#else + if (dir[0] != '/' && dir[0] != '\\') +#endif /* WIN32 || __EMX__ */ + sprintf(pathname, "%s/%s", directory_, dir); + else + { + strncpy(pathname, dir, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } + + // Create the directory; ignore EEXIST errors... +#if defined(WIN32) + if (mkdir(pathname)) +#else + if (mkdir(pathname, 0777)) +#endif /* WIN32 */ + if (errno != EEXIST) + { + fl_alert("Unable to create directory!"); + return; + } + + // Show the new directory... + directory(pathname); +} + + +// +// 'Fl_File_Chooser::rescan()' - Rescan the current directory. +// + +void +Fl_File_Chooser::rescan() +{ +// printf("Fl_File_Chooser::rescan(); directory = \"%s\"\n", directory_); + + // Clear the current filename + fileName->value(""); + okButton->deactivate(); + + // Build the file list... + fileList->load(directory_); +} + + +// +// 'Fl_File_Chooser::fileListCB()' - Handle clicks (and double-clicks) in the +// FileBrowser. +// + +void +Fl_File_Chooser::fileListCB() +{ + char *filename, // New filename + pathname[1024]; // Full pathname to file + + + filename = (char *)fileList->text(fileList->value()); + if (directory_[0] != '\0') + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } + + if (Fl::event_clicks()) + { +#if defined(WIN32) || defined(__EMX__) + if ((strlen(pathname) == 2 && pathname[1] == ':') || + filename_isdir(pathname)) +#else + if (filename_isdir(pathname)) +#endif /* WIN32 || __EMX__ */ + { + directory(pathname); + upButton->activate(); + } + else + { + // Do any callback that is registered... + if (callback_) + (*callback_)(this, data_); + + // Hide the window... + window->hide(); + } + } + else + { + fileName->value(filename); + + if (!filename_isdir(pathname) || (type_ & DIRECTORY)) + okButton->activate(); + } +} + + +// +// 'Fl_File_Chooser::fileNameCB()' - Handle text entry in the FileBrowser. +// + +void +Fl_File_Chooser::fileNameCB() +{ + char *filename, // New filename + *slash, // Pointer to trailing slash + pathname[1024]; // Full pathname to file + int i, // Looping var + min_match, // Minimum number of matching chars + max_match, // Maximum number of matching chars + num_files, // Number of files in directory + first_line; // First matching line + const char *file; // File from directory + + + // Get the filename from the text field... + filename = (char *)fileName->value(); + + if (filename == NULL || filename[0] == '\0') + { + okButton->deactivate(); + return; + } + +#if defined(WIN32) || defined(__EMX__) + if (directory_[0] != '\0' && + filename[0] != '/' && + filename[0] != '\\' && + !(isalpha(filename[0]) && filename[1] == ':')) + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } +#else + if (filename[0] == '~') + { + // Lookup user... + struct passwd *pwd; + + if (!filename[1] || filename[1] == '/') + pwd = getpwuid(getuid()); + else + { + strncpy(pathname, filename + 1, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + + i = strlen(pathname) - 1; + if (pathname[i] == '/') + pathname[i] = '\0'; + + pwd = getpwnam(pathname); + } + + if (pwd) + { + strncpy(pathname, pwd->pw_dir, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + + if (filename[strlen(filename) - 1] == '/') + strncat(pathname, "/", sizeof(pathname) - 1); + } + else + sprintf(pathname, "%s/%s", directory_, filename); + + endpwent(); + } + else if (directory_[0] != '\0' && + filename[0] != '/') + sprintf(pathname, "%s/%s", directory_, filename); + else + { + strncpy(pathname, filename, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + } +#endif /* WIN32 || __EMX__ */ + + if (Fl::event_key() == FL_Enter) + { + // Enter pressed - select or change directory... + +#if defined(WIN32) || defined(__EMX__) + if ((strlen(pathname) == 2 && pathname[1] == ':') || + filename_isdir(pathname)) +#else + if (filename_isdir(pathname)) +#endif /* WIN32 || __EMX__ */ + directory(pathname); + else if ((type_ & CREATE) || access(pathname, 0) == 0) + { + // New file or file exists... If we are in multiple selection mode, + // switch to single selection mode... + if (type_ & MULTI) + type(SINGLE); + + // Do any callback that is registered... + if (callback_) + (*callback_)(this, data_); + + // Hide the window to signal things are done... + window->hide(); + } + else + { + // File doesn't exist, so beep at and alert the user... + fl_alert("Please choose an existing file!"); + } + } + else if (Fl::event_key() != FL_Delete) + { + // Check to see if the user has entered a directory... + if ((slash = strrchr(filename, '/')) == NULL) + slash = strrchr(filename, '\\'); + + if (slash != NULL) + { + // Yes, change directories and update the file name field... + if ((slash = strrchr(pathname, '/')) == NULL) + slash = strrchr(pathname, '\\'); + + if (slash > pathname) // Special case for "/" + *slash++ = '\0'; + else + slash++; + + if (strcmp(filename, "../") == 0) // Special case for "../" + up(); + else + directory(pathname); + + // If the string ended after the slash, we're done for now... + if (*slash == '\0') + return; + + // Otherwise copy the remainder and proceed... + fileName->value(slash); + fileName->position(strlen(slash)); + filename = slash; + } + + // Other key pressed - do filename completion as possible... + num_files = fileList->size(); + min_match = strlen(filename); + max_match = 100000; + first_line = 0; + + for (i = 1; i <= num_files && max_match > min_match; i ++) + { + file = fileList->text(i); + +#if defined(WIN32) || defined(__EMX__) + if (strnicmp(filename, file, min_match) == 0) +#else + if (strncmp(filename, file, min_match) == 0) +#endif // WIN32 || __EMX__ + { + // OK, this one matches; check against the previous match + if (max_match == 100000) + { + // First match; copy stuff over... + strncpy(pathname, file, sizeof(pathname) - 1); + pathname[sizeof(pathname) - 1] = '\0'; + max_match = strlen(pathname); + + // Strip trailing /, if any... + if (pathname[max_match - 1] == '/') + { + max_match --; + pathname[max_match] = '\0'; + } + + // And then make sure that the item is visible + fileList->topline(i); + first_line = i; + } + else + { + // Succeeding match; compare to find maximum string match... + while (max_match > min_match) +#if defined(WIN32) || defined(__EMX__) + if (strnicmp(file, pathname, max_match) == 0) +#else + if (strncmp(file, pathname, max_match) == 0) +#endif // WIN32 || __EMX__ + break; + else + max_match --; + + // Truncate the string as needed... + pathname[max_match] = '\0'; + } + } + } + + fileList->deselect(0); + fileList->redraw(); + + // If we have any matches, add them to the input field... + if (first_line > 0 && min_match == max_match && + max_match == (int)strlen(fileList->text(first_line))) + fileList->select(first_line); + else if (max_match > min_match && max_match != 100000) + { + // Add the matching portion... + fileName->replace(0, min_match, pathname); + + // Highlight it; if the user just pressed the backspace + // key, position the cursor at the start of the selection. + // Otherwise, put the cursor at the end of the selection so + // s/he can press the right arrow to accept the selection + // (Tab and End also do this for both cases.) + if (Fl::event_key() == FL_BackSpace) + fileName->position(min_match - 1, max_match); + else + fileName->position(max_match, min_match); + } + + // See if we need to enable the OK button... + sprintf(pathname, "%s/%s", directory_, fileName->value()); + + if ((type_ & CREATE || access(pathname, 0) == 0) && + (!filename_isdir(pathname) || type_ & DIRECTORY)) + okButton->activate(); + else + okButton->deactivate(); + } +} + + +// +// End of "$Id: Fl_File_Chooser2.cxx,v 1.1.2.1 2001/09/29 14:38:59 easysw Exp $". +// |
