summaryrefslogtreecommitdiff
path: root/src/Fl_FileChooser2.cxx
diff options
context:
space:
mode:
authorNo Author <No Author>2001-08-01 21:24:49 +0000
committerNo Author <No Author>2001-08-01 21:24:49 +0000
commit3cb5ebe0e811f3db008085d985b7761725589a74 (patch)
tree0a7184a5f02fffe927af911758f3a9a4a2f4a37e /src/Fl_FileChooser2.cxx
parent4477e166400f197bed50b09e01e695221cde96b6 (diff)
This commit was manufactured by cvs2svn to create branch 'branch-1.1'.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1513 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_FileChooser2.cxx')
-rw-r--r--src/Fl_FileChooser2.cxx669
1 files changed, 669 insertions, 0 deletions
diff --git a/src/Fl_FileChooser2.cxx b/src/Fl_FileChooser2.cxx
new file mode 100644
index 000000000..40837e910
--- /dev/null
+++ b/src/Fl_FileChooser2.cxx
@@ -0,0 +1,669 @@
+//
+// "$Id: Fl_FileChooser2.cxx,v 1.15 2001/07/29 22:04:43 spitzak Exp $"
+//
+// More Fl_FileChooser routines for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1997-2000 by Easy Software Products.
+//
+// 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@easysw.com".
+//
+// Contents:
+//
+// Fl_FileChooser::directory() - Set the directory in the file chooser.
+// Fl_FileChooser::count() - Return the number of selected files.
+// Fl_FileChooser::value() - Return a selected filename.
+// Fl_FileChooser::up() - Go up one directory.
+// Fl_FileChooser::newdir() - Make a new directory.
+// Fl_FileChooser::rescan() - Rescan the current directory.
+// Fl_FileChooser::fileListCB() - Handle clicks (and double-clicks) in the
+// FileBrowser.
+// Fl_FileChooser::fileNameCB() - Handle text entry in the FileBrowser.
+//
+
+//
+// Include necessary headers.
+//
+
+#include <fltk/Fl_FileChooser.h>
+#include <fltk/filename.h>
+#include <fltk/fl_ask.h>
+#include <fltk/vsnprintf.h>
+#include <fltk/x.h>
+#include <config.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if defined(_WIN32)
+# include <direct.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <pwd.h>
+#endif /* _WIN32 */
+
+//
+// 'Fl_FileChooser::directory()' - Set the directory in the file chooser.
+//
+
+void
+Fl_FileChooser::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
+
+
+ // 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 ++;
+ }
+ else
+ *pathptr++ = *dirptr++;
+ }
+
+ if (pathptr > pathname)
+ {
+ *pathptr = '\0';
+ dirMenu->add(pathname);
+ levels ++;
+ }
+
+ dirMenu->value(levels);
+ dirMenu->redraw();
+
+ // Rescan the directory...
+ rescan();
+}
+
+
+//
+// 'Fl_FileChooser::count()' - Return the number of selected files.
+//
+
+int // O - Number of selected files
+Fl_FileChooser::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')
+ snprintf(pathname, sizeof(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 = 0, 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')
+ snprintf(pathname, sizeof(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_FileChooser::value()' - Return a selected filename.
+//
+
+const char * // O - Filename or NULL
+Fl_FileChooser::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);
+
+ snprintf(pathname, sizeof(pathname), "%s/%s", directory_, name);
+ return ((const char *)pathname);
+ }
+
+ for (i = 0, count = 0; i < fileList->size(); i ++)
+ if (fileList->selected(i))
+ {
+ // See if this file is a directory...
+ name = fileList->text(i);
+ snprintf(pathname, sizeof(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_FileChooser::value()' - Set the current filename.
+//
+
+void
+Fl_FileChooser::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
+
+
+ // See if the filename is actually a directory...
+ if (filename == NULL || filename_isdir(filename))
+ {
+ // Yes, just change the current directory...
+ directory(filename);
+ return;
+ }
+
+ if (!filename[0])
+ {
+ // Just show the current directory...
+ directory(NULL);
+ 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
+ {
+ directory(NULL);
+ 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 = 0; i < count; i ++)
+ if (strcmp(fileList->text(i), slash) == 0)
+ {
+ fileList->select(i);
+ break;
+ }
+}
+
+
+//
+// 'Fl_FileChooser::up()' - Go up one directory.
+//
+
+void
+Fl_FileChooser::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_FileChooser::newdir()' - Make a new directory.
+//
+
+void
+Fl_FileChooser::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)
+ 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__ */
+ snprintf(pathname, sizeof(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 || __EMX__ */
+ if (errno != EEXIST)
+ {
+ fl_alert("Unable to create directory!");
+ return;
+ }
+
+ // Show the new directory...
+ directory(pathname);
+}
+
+
+//
+// 'Fl_FileChooser::rescan()' - Rescan the current directory.
+//
+
+void
+Fl_FileChooser::rescan()
+{
+ // Clear the current filename
+ fileName->value("");
+ okButton->deactivate();
+
+ // Build the file list...
+ fileList->load(directory_);
+ fileList->redraw();
+}
+
+
+//
+// 'Fl_FileChooser::fileListCB()' - Handle clicks (and double-clicks) in the
+// FileBrowser.
+//
+
+void
+Fl_FileChooser::fileListCB()
+{
+ char filename[1024], // New filename
+ pathname[1024]; // Full pathname to file
+
+
+ strncpy(filename, fileList->text(fileList->value()), sizeof(filename) - 1);
+ filename[sizeof(filename) - 1] = '\0';
+
+#if defined(_WIN32) || defined(__EMX__)
+ if (directory_[0] != '\0' && filename[0] != '/' && filename[0] != '\\' &&
+ !(isalpha(filename[0]) && filename[1] == ':'))
+ snprintf(pathname, sizeof(pathname), "%s/%s", directory_, filename);
+ else
+ {
+ strncpy(pathname, filename, sizeof(pathname) - 1);
+ pathname[sizeof(pathname) - 1] = '\0';
+ }
+#else
+ if (directory_[0] != '\0' && filename[0] != '/')
+ snprintf(pathname, sizeof(pathname), "%s/%s", directory_, filename);
+ else
+ {
+ strncpy(pathname, filename, sizeof(pathname) - 1);
+ pathname[sizeof(pathname) - 1] = '\0';
+ }
+#endif /* _WIN32 || __EMX__ */
+
+ if (Fl::event_clicks() || Fl::event_key() == FL_Enter)
+ {
+ puts("double-click");
+ if (filename_isdir(pathname))
+ {
+ puts("directory");
+ directory(pathname);
+ upButton->activate();
+ }
+ else
+ window->hide();
+ }
+ else
+ {
+ fileName->value(filename);
+ okButton->activate();
+ }
+}
+
+
+//
+// 'Fl_FileChooser::fileNameCB()' - Handle text entry in the FileBrowser.
+//
+
+void
+Fl_FileChooser::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] == ':'))
+ snprintf(pathname, sizeof(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) - strlen(pathname) - 1);
+ }
+ else
+ snprintf(pathname, sizeof(pathname), "%s/%s", directory_, filename);
+
+ endpwent();
+ }
+ else if (directory_[0] != '\0' && filename[0] != '/')
+ snprintf(pathname, sizeof(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 (filename_isdir(pathname))
+ 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);
+
+ // Hide the window to signal things are done...
+ window->hide();
+ }
+ else
+ {
+ // File doesn't exist, so 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 = 0; 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);
+
+ // 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, strlen(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...
+ snprintf(pathname, sizeof(pathname), "%s/%s", directory_, fileName->value());
+
+ if (type_ == CREATE || access(pathname, 0) == 0)
+ okButton->activate();
+ else
+ okButton->deactivate();
+ }
+}
+
+
+//
+// End of "$Id: Fl_FileChooser2.cxx,v 1.15 2001/07/29 22:04:43 spitzak Exp $".
+//