|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: Fl_File_Chooser2.cxx 8063 2010-12-19 21:20:10Z matt $" 00003 // 00004 // More Fl_File_Chooser routines. 00005 // 00006 // Copyright 1999-2010 by Michael Sweet. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 // fabien: ATTENTION: Only Out Of Source Gen. because cxx/H files are autogenerated by fluid. 00310 // *** END OF OUT OF SOURCE DOC *** 00311 00312 // Contents: 00313 // 00314 // Fl_File_Chooser::count() - Return the number of selected files. 00315 // Fl_File_Chooser::directory() - Set the directory in the file chooser. 00316 // Fl_File_Chooser::filter() - Set the filter(s) for the chooser. 00317 // Fl_File_Chooser::newdir() - Make a new directory. 00318 // Fl_File_Chooser::value() - Return a selected filename. 00319 // Fl_File_Chooser::rescan() - Rescan the current directory. 00320 // Fl_File_Chooser::favoritesButtonCB() - Handle favorites selections. 00321 // Fl_File_Chooser::fileListCB() - Handle clicks (and double-clicks) 00322 // in the Fl_File_Browser. 00323 // Fl_File_Chooser::fileNameCB() - Handle text entry in the FileBrowser. 00324 // Fl_File_Chooser::showChoiceCB() - Handle show selections. 00325 // compare_dirnames() - Compare two directory names. 00326 // quote_pathname() - Quote a pathname for a menu. 00327 // unquote_pathname() - Unquote a pathname from a menu. 00328 // 00329 // Fl_File_Chooser::add_extra() - add extra widget at the bottom, return pointer 00330 // to previous extra widget or NULL if none, 00331 // If argument is NULL extra widget removed. 00332 // NOTE! file chooser does't delete extra widget in 00333 // destructor! To prevent memory leakage don't forget 00334 // delete unused extra widgets by yourself. 00335 // 00336 00337 // 00338 // Include necessary headers. 00339 // 00340 00341 #include <FL/Fl_File_Chooser.H> 00342 #include <FL/filename.H> 00343 #include <FL/fl_ask.H> 00344 #include <FL/x.H> 00345 #include <FL/Fl_Shared_Image.H> 00346 00347 #include <stdio.h> 00348 #include <stdlib.h> 00349 #include "flstring.h" 00350 #include <errno.h> 00351 #include <sys/types.h> 00352 #include <sys/stat.h> 00353 00354 #if defined(WIN32) && ! defined (__CYGWIN__) 00355 # include <direct.h> 00356 # include <io.h> 00357 // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs 00358 // on Windows, which is supposed to be POSIX compliant... 00359 # define access _access 00360 # define mkdir _mkdir 00361 // Apparently Borland C++ defines DIRECTORY in <direct.h>, which 00362 // interfers with the Fl_File_Icon enumeration of the same name. 00363 # ifdef DIRECTORY 00364 # undef DIRECTORY 00365 # endif // DIRECTORY 00366 #else 00367 # include <unistd.h> 00368 # include <pwd.h> 00369 #endif /* WIN32 */ 00370 00371 00372 // 00373 // File chooser label strings and sort function... 00374 // 00375 00376 Fl_Preferences Fl_File_Chooser::prefs_(Fl_Preferences::USER, "fltk.org", "filechooser"); 00377 00378 const char *Fl_File_Chooser::add_favorites_label = "Add to Favorites"; 00379 const char *Fl_File_Chooser::all_files_label = "All Files (*)"; 00380 const char *Fl_File_Chooser::custom_filter_label = "Custom Filter"; 00381 const char *Fl_File_Chooser::existing_file_label = "Please choose an existing file!"; 00382 const char *Fl_File_Chooser::favorites_label = "Favorites"; 00383 const char *Fl_File_Chooser::filename_label = "Filename:"; 00384 #ifdef WIN32 00385 const char *Fl_File_Chooser::filesystems_label = "My Computer"; 00386 #else 00387 const char *Fl_File_Chooser::filesystems_label = "File Systems"; 00388 #endif // WIN32 00389 const char *Fl_File_Chooser::manage_favorites_label = "Manage Favorites"; 00390 const char *Fl_File_Chooser::new_directory_label = "New Directory?"; 00391 const char *Fl_File_Chooser::new_directory_tooltip = "Create a new directory."; 00392 const char *Fl_File_Chooser::preview_label = "Preview"; 00393 const char *Fl_File_Chooser::save_label = "Save"; 00394 const char *Fl_File_Chooser::show_label = "Show:"; 00395 Fl_File_Sort_F *Fl_File_Chooser::sort = fl_numericsort; 00396 00397 00398 // 00399 // Local functions... 00400 // 00401 00402 static int compare_dirnames(const char *a, const char *b); 00403 static void quote_pathname(char *, const char *, int); 00404 static void unquote_pathname(char *, const char *, int); 00405 00406 00407 // 00408 // 'Fl_File_Chooser::count()' - Return the number of selected files. 00409 // 00410 00411 int // O - Number of selected files 00412 Fl_File_Chooser::count() { 00413 int i; // Looping var 00414 int fcount; // Number of selected files 00415 const char *filename; // Filename in input field or list 00416 00417 00418 filename = fileName->value(); 00419 00420 if (!(type_ & MULTI)) { 00421 // Check to see if the file name input field is blank... 00422 if (!filename || !filename[0]) return 0; 00423 else return 1; 00424 } 00425 00426 for (i = 1, fcount = 0; i <= fileList->size(); i ++) 00427 if (fileList->selected(i)) { 00428 // See if this file is a directory... 00429 // matt: why would we do that? It is perfectly legal to select multiple 00430 // directories in a DIR chooser. They are visually selected and value(i) 00431 // returns all of them as expected 00432 //filename = (char *)fileList->text(i); 00433 00434 //if (filename[strlen(filename) - 1] != '/') 00435 fcount ++; 00436 } 00437 00438 if (fcount) return fcount; 00439 else if (!filename || !filename[0]) return 0; 00440 else return 1; 00441 } 00442 00443 00444 // 00445 // 'Fl_File_Chooser::directory()' - Set the directory in the file chooser. 00446 // 00447 00448 void 00449 Fl_File_Chooser::directory(const char *d)// I - Directory to change to 00450 { 00451 char *dirptr; // Pointer into directory 00452 00453 00454 // printf("Fl_File_Chooser::directory(\"%s\")\n", d == NULL ? "(null)" : d); 00455 00456 // NULL == current directory 00457 if (d == NULL) 00458 d = "."; 00459 00460 #ifdef WIN32 00461 // See if the filename contains backslashes... 00462 char *slash; // Pointer to slashes 00463 char fixpath[FL_PATH_MAX]; // Path with slashes converted 00464 if (strchr(d, '\\')) { 00465 // Convert backslashes to slashes... 00466 strlcpy(fixpath, d, sizeof(fixpath)); 00467 00468 for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\')) 00469 *slash = '/'; 00470 00471 d = fixpath; 00472 } 00473 #endif // WIN32 00474 00475 if (d[0] != '\0') 00476 { 00477 // Make the directory absolute... 00478 #if (defined(WIN32) && ! defined(__CYGWIN__))|| defined(__EMX__) 00479 if (d[0] != '/' && d[0] != '\\' && d[1] != ':') 00480 #else 00481 if (d[0] != '/' && d[0] != '\\') 00482 #endif /* WIN32 || __EMX__ */ 00483 fl_filename_absolute(directory_, d); 00484 else 00485 strlcpy(directory_, d, sizeof(directory_)); 00486 00487 // Strip any trailing slash... 00488 dirptr = directory_ + strlen(directory_) - 1; 00489 if ((*dirptr == '/' || *dirptr == '\\') && dirptr > directory_) 00490 *dirptr = '\0'; 00491 00492 // See if we have a trailing .. or . in the filename... 00493 dirptr = directory_ + strlen(directory_) - 3; 00494 if (dirptr >= directory_ && strcmp(dirptr, "/..") == 0) { 00495 // Yes, we have "..", so strip the trailing path... 00496 *dirptr = '\0'; 00497 while (dirptr > directory_) { 00498 if (*dirptr == '/') break; 00499 dirptr --; 00500 } 00501 00502 if (dirptr >= directory_ && *dirptr == '/') 00503 *dirptr = '\0'; 00504 } else if ((dirptr + 1) >= directory_ && strcmp(dirptr + 1, "/.") == 0) { 00505 // Strip trailing "."... 00506 dirptr[1] = '\0'; 00507 } 00508 } 00509 else 00510 directory_[0] = '\0'; 00511 00512 if (shown()) { 00513 // Rescan the directory... 00514 rescan(); 00515 } 00516 } 00517 00518 00519 // 00520 // 'Fl_File_Chooser::favoritesButtonCB()' - Handle favorites selections. 00521 // 00522 00523 void 00524 Fl_File_Chooser::favoritesButtonCB() 00525 { 00526 int v; // Current selection 00527 char pathname[FL_PATH_MAX], // Pathname 00528 menuname[FL_PATH_MAX]; // Menu name 00529 00530 00531 v = favoritesButton->value(); 00532 00533 if (!v) { 00534 // Add current directory to favorites... 00535 if (getenv("HOME")) v = favoritesButton->size() - 5; 00536 else v = favoritesButton->size() - 4; 00537 00538 sprintf(menuname, "favorite%02d", v); 00539 00540 prefs_.set(menuname, directory_); 00541 prefs_.flush(); 00542 00543 quote_pathname(menuname, directory_, sizeof(menuname)); 00544 favoritesButton->add(menuname); 00545 00546 if (favoritesButton->size() > 104) { 00547 ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate(); 00548 } 00549 } else if (v == 1) { 00550 // Manage favorites... 00551 favoritesCB(0); 00552 } else if (v == 2) { 00553 // Filesystems/My Computer 00554 directory(""); 00555 } else { 00556 unquote_pathname(pathname, favoritesButton->text(v), sizeof(pathname)); 00557 directory(pathname); 00558 } 00559 } 00560 00561 00562 // 00563 // 'Fl_File_Chooser::favoritesCB()' - Handle favorites dialog. 00564 // 00565 00566 void 00567 Fl_File_Chooser::favoritesCB(Fl_Widget *w) 00568 // I - Widget 00569 { 00570 int i; // Looping var 00571 char name[32], // Preference name 00572 pathname[1024]; // Directory in list 00573 00574 00575 if (!w) { 00576 // Load the favorites list... 00577 favList->clear(); 00578 favList->deselect(); 00579 00580 for (i = 0; i < 100; i ++) { 00581 // Get favorite directory 0 to 99... 00582 sprintf(name, "favorite%02d", i); 00583 00584 prefs_.get(name, pathname, "", sizeof(pathname)); 00585 00586 // Stop on the first empty favorite... 00587 if (!pathname[0]) break; 00588 00589 // Add the favorite to the list... 00590 favList->add(pathname, 00591 Fl_File_Icon::find(pathname, Fl_File_Icon::DIRECTORY)); 00592 } 00593 00594 favUpButton->deactivate(); 00595 favDeleteButton->deactivate(); 00596 favDownButton->deactivate(); 00597 favOkButton->deactivate(); 00598 00599 favWindow->hotspot(favList); 00600 favWindow->show(); 00601 } else if (w == favList) { 00602 i = favList->value(); 00603 if (i) { 00604 if (i > 1) favUpButton->activate(); 00605 else favUpButton->deactivate(); 00606 00607 favDeleteButton->activate(); 00608 00609 if (i < favList->size()) favDownButton->activate(); 00610 else favDownButton->deactivate(); 00611 } else { 00612 favUpButton->deactivate(); 00613 favDeleteButton->deactivate(); 00614 favDownButton->deactivate(); 00615 } 00616 } else if (w == favUpButton) { 00617 i = favList->value(); 00618 00619 favList->insert(i - 1, favList->text(i), favList->data(i)); 00620 favList->remove(i + 1); 00621 favList->select(i - 1); 00622 00623 if (i == 2) favUpButton->deactivate(); 00624 00625 favDownButton->activate(); 00626 00627 favOkButton->activate(); 00628 } else if (w == favDeleteButton) { 00629 i = favList->value(); 00630 00631 favList->remove(i); 00632 00633 if (i > favList->size()) i --; 00634 favList->select(i); 00635 00636 if (i < favList->size()) favDownButton->activate(); 00637 else favDownButton->deactivate(); 00638 00639 if (i > 1) favUpButton->activate(); 00640 else favUpButton->deactivate(); 00641 00642 if (!i) favDeleteButton->deactivate(); 00643 00644 favOkButton->activate(); 00645 } else if (w == favDownButton) { 00646 i = favList->value(); 00647 00648 favList->insert(i + 2, favList->text(i), favList->data(i)); 00649 favList->remove(i); 00650 favList->select(i + 1); 00651 00652 if ((i + 1) == favList->size()) favDownButton->deactivate(); 00653 00654 favUpButton->activate(); 00655 00656 favOkButton->activate(); 00657 } else if (w == favOkButton) { 00658 // Copy the new list over... 00659 for (i = 0; i < favList->size(); i ++) { 00660 // Set favorite directory 0 to 99... 00661 sprintf(name, "favorite%02d", i); 00662 00663 prefs_.set(name, favList->text(i + 1)); 00664 } 00665 00666 // Clear old entries as necessary... 00667 for (; i < 100; i ++) { 00668 // Clear favorite directory 0 to 99... 00669 sprintf(name, "favorite%02d", i); 00670 00671 prefs_.get(name, pathname, "", sizeof(pathname)); 00672 00673 if (pathname[0]) prefs_.set(name, ""); 00674 else break; 00675 } 00676 00677 update_favorites(); 00678 prefs_.flush(); 00679 00680 favWindow->hide(); 00681 } 00682 } 00683 00684 00685 // 00686 // 'Fl_File_Chooser::fileListCB()' - Handle clicks (and double-clicks) in the 00687 // Fl_File_Browser. 00688 // 00689 00690 void 00691 Fl_File_Chooser::fileListCB() 00692 { 00693 char *filename, // New filename 00694 pathname[FL_PATH_MAX]; // Full pathname to file 00695 00696 00697 filename = (char *)fileList->text(fileList->value()); 00698 if (!filename) 00699 return; 00700 00701 if (!directory_[0]) { 00702 strlcpy(pathname, filename, sizeof(pathname)); 00703 } else if (strcmp(directory_, "/") == 0) { 00704 snprintf(pathname, sizeof(pathname), "/%s", filename); 00705 } else { 00706 snprintf(pathname, sizeof(pathname), "%s/%s", directory_, filename); 00707 } 00708 00709 if (Fl::event_clicks()) { 00710 #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__) 00711 if ((strlen(pathname) == 2 && pathname[1] == ':') || 00712 _fl_filename_isdir_quick(pathname)) 00713 #else 00714 if (_fl_filename_isdir_quick(pathname)) 00715 #endif /* WIN32 || __EMX__ */ 00716 { 00717 // Change directories... 00718 directory(pathname); 00719 00720 // Reset the click count so that a click in the same spot won't 00721 // be treated as a triple-click. We use a value of -1 because 00722 // the next click will increment click count to 0, which is what 00723 // we really want... 00724 Fl::event_clicks(-1); 00725 } 00726 else 00727 { 00728 // Hide the window - picked the file... 00729 window->hide(); 00730 if (callback_) (*callback_)(this, data_); 00731 } 00732 } 00733 else 00734 { 00735 // Check if the user clicks on a directory when picking files; 00736 // if so, make sure only that item is selected... 00737 filename = pathname + strlen(pathname) - 1; 00738 00739 if ((type_ & MULTI) && !(type_ & DIRECTORY)) { 00740 if (*filename == '/') { 00741 // Clicked on a directory, deselect everything else... 00742 int i = fileList->value(); 00743 fileList->deselect(); 00744 fileList->select(i); 00745 } else { 00746 // Clicked on a file - see if there are other directories selected... 00747 int i; 00748 const char *temp; 00749 for (i = 1; i <= fileList->size(); i ++) { 00750 if (i != fileList->value() && fileList->selected(i)) { 00751 temp = fileList->text(i); 00752 temp += strlen(temp) - 1; 00753 if (*temp == '/') break; // Yes, selected directory 00754 } 00755 } 00756 00757 if (i <= fileList->size()) { 00758 i = fileList->value(); 00759 fileList->deselect(); 00760 fileList->select(i); 00761 } 00762 } 00763 } 00764 // Strip any trailing slash from the directory name... 00765 if (*filename == '/') *filename = '\0'; 00766 00767 // puts("Setting fileName from fileListCB..."); 00768 fileName->value(pathname); 00769 00770 // Update the preview box... 00771 Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this); 00772 Fl::add_timeout(1.0, (Fl_Timeout_Handler)previewCB, this); 00773 00774 // Do any callback that is registered... 00775 if (callback_) (*callback_)(this, data_); 00776 00777 // Activate the OK button as needed... 00778 if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY)) 00779 okButton->activate(); 00780 else 00781 okButton->deactivate(); 00782 } 00783 } 00784 00785 00786 // 00787 // 'Fl_File_Chooser::fileNameCB()' - Handle text entry in the FileBrowser. 00788 // 00789 00790 void 00791 Fl_File_Chooser::fileNameCB() 00792 { 00793 char *filename, // New filename 00794 *slash, // Pointer to trailing slash 00795 pathname[FL_PATH_MAX], // Full pathname to file 00796 matchname[FL_PATH_MAX]; // Matching filename 00797 int i, // Looping var 00798 min_match, // Minimum number of matching chars 00799 max_match, // Maximum number of matching chars 00800 num_files, // Number of files in directory 00801 first_line; // First matching line 00802 const char *file; // File from directory 00803 00804 // puts("fileNameCB()"); 00805 // printf("Event: %s\n", fl_eventnames[Fl::event()]); 00806 00807 // Get the filename from the text field... 00808 filename = (char *)fileName->value(); 00809 00810 if (!filename || !filename[0]) { 00811 okButton->deactivate(); 00812 return; 00813 } 00814 00815 // Expand ~ and $ variables as needed... 00816 if (strchr(filename, '~') || strchr(filename, '$')) { 00817 fl_filename_expand(pathname, sizeof(pathname), filename); 00818 filename = pathname; 00819 value(pathname); 00820 } 00821 00822 // Make sure we have an absolute path... 00823 #if (defined(WIN32) && !defined(__CYGWIN__)) || defined(__EMX__) 00824 if (directory_[0] != '\0' && filename[0] != '/' && 00825 filename[0] != '\\' && 00826 !(isalpha(filename[0] & 255) && (!filename[1] || filename[1] == ':'))) { 00827 #else 00828 if (directory_[0] != '\0' && filename[0] != '/') { 00829 #endif /* WIN32 || __EMX__ */ 00830 fl_filename_absolute(pathname, sizeof(pathname), filename); 00831 value(pathname); 00832 fileName->mark(fileName->position()); // no selection after expansion 00833 } else if (filename != pathname) { 00834 // Finally, make sure that we have a writable copy... 00835 strlcpy(pathname, filename, sizeof(pathname)); 00836 } 00837 00838 filename = pathname; 00839 00840 // Now process things according to the key pressed... 00841 if (Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter) { 00842 // Enter pressed - select or change directory... 00843 #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__) 00844 if ((isalpha(pathname[0] & 255) && pathname[1] == ':' && !pathname[2]) || 00845 (_fl_filename_isdir_quick(pathname) && 00846 compare_dirnames(pathname, directory_))) { 00847 #else 00848 if (_fl_filename_isdir_quick(pathname) && 00849 compare_dirnames(pathname, directory_)) { 00850 #endif /* WIN32 || __EMX__ */ 00851 directory(pathname); 00852 } else if ((type_ & CREATE) || access(pathname, 0) == 0) { 00853 if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY)) { 00854 // Update the preview box... 00855 update_preview(); 00856 00857 // Do any callback that is registered... 00858 if (callback_) (*callback_)(this, data_); 00859 00860 // Hide the window to signal things are done... 00861 window->hide(); 00862 } 00863 } else { 00864 // File doesn't exist, so beep at and alert the user... 00865 fl_alert("%s",existing_file_label); 00866 } 00867 } 00868 else if (Fl::event_key() != FL_Delete && 00869 Fl::event_key() != FL_BackSpace) { 00870 // Check to see if the user has entered a directory... 00871 if ((slash = strrchr(pathname, '/')) == NULL) 00872 slash = strrchr(pathname, '\\'); 00873 00874 if (!slash) return; 00875 00876 // Yes, change directories if necessary... 00877 *slash++ = '\0'; 00878 filename = slash; 00879 00880 #if defined(WIN32) || defined(__EMX__) 00881 if (strcasecmp(pathname, directory_) && 00882 (pathname[0] || strcasecmp("/", directory_))) { 00883 #else 00884 if (strcmp(pathname, directory_) && 00885 (pathname[0] || strcasecmp("/", directory_))) { 00886 #endif // WIN32 || __EMX__ 00887 int p = fileName->position(); 00888 int m = fileName->mark(); 00889 00890 directory(pathname); 00891 00892 if (filename[0]) { 00893 char tempname[FL_PATH_MAX]; 00894 00895 snprintf(tempname, sizeof(tempname), "%s/%s", directory_, filename); 00896 fileName->value(tempname); 00897 strlcpy(pathname, tempname, sizeof(pathname)); 00898 } 00899 00900 fileName->position(p, m); 00901 } 00902 00903 // Other key pressed - do filename completion as possible... 00904 num_files = fileList->size(); 00905 min_match = strlen(filename); 00906 max_match = min_match + 1; 00907 first_line = 0; 00908 00909 for (i = 1; i <= num_files && max_match > min_match; i ++) { 00910 file = fileList->text(i); 00911 00912 #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__) 00913 if (strncasecmp(filename, file, min_match) == 0) { 00914 #else 00915 if (strncmp(filename, file, min_match) == 0) { 00916 #endif // WIN32 || __EMX__ 00917 // OK, this one matches; check against the previous match 00918 if (!first_line) { 00919 // First match; copy stuff over... 00920 strlcpy(matchname, file, sizeof(matchname)); 00921 max_match = strlen(matchname); 00922 00923 // Strip trailing /, if any... 00924 if (matchname[max_match - 1] == '/') { 00925 max_match --; 00926 matchname[max_match] = '\0'; 00927 } 00928 00929 // And then make sure that the item is visible 00930 fileList->topline(i); 00931 first_line = i; 00932 } else { 00933 // Succeeding match; compare to find maximum string match... 00934 while (max_match > min_match) 00935 #if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__) 00936 if (strncasecmp(file, matchname, max_match) == 0) 00937 #else 00938 if (strncmp(file, matchname, max_match) == 0) 00939 #endif // WIN32 || __EMX__ 00940 break; 00941 else 00942 max_match --; 00943 00944 // Truncate the string as needed... 00945 matchname[max_match] = '\0'; 00946 } 00947 } 00948 } 00949 00950 // If we have any matches, add them to the input field... 00951 if (first_line > 0 && min_match == max_match && 00952 max_match == (int)strlen(fileList->text(first_line))) { 00953 // This is the only possible match... 00954 fileList->deselect(0); 00955 fileList->select(first_line); 00956 fileList->redraw(); 00957 } else if (max_match > min_match && first_line) { 00958 // Add the matching portion... 00959 fileName->replace(filename - pathname, filename - pathname + min_match, 00960 matchname); 00961 00962 // Highlight it with the cursor at the end of the selection so 00963 // s/he can press the right arrow to accept the selection 00964 // (Tab and End also do this for both cases.) 00965 fileName->position(filename - pathname + max_match, 00966 filename - pathname + min_match); 00967 } else if (max_match == 0) { 00968 fileList->deselect(0); 00969 fileList->redraw(); 00970 } 00971 00972 // See if we need to enable the OK button... 00973 if (((type_ & CREATE) || !access(fileName->value(), 0)) && 00974 (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) { 00975 okButton->activate(); 00976 } else { 00977 okButton->deactivate(); 00978 } 00979 } else { 00980 // FL_Delete or FL_BackSpace 00981 fileList->deselect(0); 00982 fileList->redraw(); 00983 if (((type_ & CREATE) || !access(fileName->value(), 0)) && 00984 (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) { 00985 okButton->activate(); 00986 } else { 00987 okButton->deactivate(); 00988 } 00989 } 00990 } 00991 00992 00993 // 00994 // 'Fl_File_Chooser::filter()' - Set the filter(s) for the chooser. 00995 // 00996 00997 void 00998 Fl_File_Chooser::filter(const char *p) // I - Pattern(s) 00999 { 01000 char *copyp, // Copy of pattern 01001 *start, // Start of pattern 01002 *end; // End of pattern 01003 int allfiles; // Do we have a "*" pattern? 01004 char temp[FL_PATH_MAX]; // Temporary pattern string 01005 01006 01007 // Make sure we have a pattern... 01008 if (!p || !*p) p = "*"; 01009 01010 // Copy the pattern string... 01011 copyp = strdup(p); 01012 01013 // Separate the pattern string as necessary... 01014 showChoice->clear(); 01015 01016 for (start = copyp, allfiles = 0; start && *start; start = end) { 01017 end = strchr(start, '\t'); 01018 if (end) *end++ = '\0'; 01019 01020 if (strcmp(start, "*") == 0) { 01021 showChoice->add(all_files_label); 01022 allfiles = 1; 01023 } else { 01024 quote_pathname(temp, start, sizeof(temp)); 01025 showChoice->add(temp); 01026 if (strstr(start, "(*)") != NULL) allfiles = 1; 01027 } 01028 } 01029 01030 free(copyp); 01031 01032 if (!allfiles) showChoice->add(all_files_label); 01033 01034 showChoice->add(custom_filter_label); 01035 01036 // TODO: add a menu item to switch hidden files on and off 01037 01038 showChoice->value(0); 01039 showChoiceCB(); 01040 } 01041 01042 01043 // 01044 // 'Fl_File_Chooser::newdir()' - Make a new directory. 01045 // 01046 01047 void 01048 Fl_File_Chooser::newdir() 01049 { 01050 const char *dir; // New directory name 01051 char pathname[FL_PATH_MAX]; // Full path of directory 01052 01053 01054 // Get a directory name from the user 01055 if ((dir = fl_input("%s", NULL, new_directory_label)) == NULL) 01056 return; 01057 01058 // Make it relative to the current directory as needed... 01059 #if (defined(WIN32) && ! defined (__CYGWIN__)) || defined(__EMX__) 01060 if (dir[0] != '/' && dir[0] != '\\' && dir[1] != ':') 01061 #else 01062 if (dir[0] != '/' && dir[0] != '\\') 01063 #endif /* WIN32 || __EMX__ */ 01064 snprintf(pathname, sizeof(pathname), "%s/%s", directory_, dir); 01065 else 01066 strlcpy(pathname, dir, sizeof(pathname)); 01067 01068 // Create the directory; ignore EEXIST errors... 01069 #if defined(WIN32) && ! defined (__CYGWIN__) 01070 if (mkdir(pathname)) 01071 #else 01072 if (mkdir(pathname, 0777)) 01073 #endif /* WIN32 */ 01074 if (errno != EEXIST) 01075 { 01076 fl_alert("%s", strerror(errno)); 01077 return; 01078 } 01079 01080 // Show the new directory... 01081 directory(pathname); 01082 } 01083 01084 01085 01087 void Fl_File_Chooser::preview(int e) 01088 { 01089 previewButton->value(e); 01090 prefs_.set("preview", e); 01091 prefs_.flush(); 01092 01093 Fl_Group *p = previewBox->parent(); 01094 if (e) { 01095 int w = p->w() * 2 / 3; 01096 fileList->resize(fileList->x(), fileList->y(), 01097 w, fileList->h()); 01098 previewBox->resize(fileList->x()+w, previewBox->y(), 01099 p->w()-w, previewBox->h()); 01100 previewBox->show(); 01101 update_preview(); 01102 } else { 01103 fileList->resize(fileList->x(), fileList->y(), 01104 p->w(), fileList->h()); 01105 previewBox->resize(p->x()+p->w(), previewBox->y(), 01106 0, previewBox->h()); 01107 previewBox->hide(); 01108 } 01109 p->init_sizes(); 01110 01111 fileList->parent()->redraw(); 01112 } 01113 01114 01115 // 01116 // 'Fl_File_Chooser::previewCB()' - Timeout handler for the preview box. 01117 // 01118 01119 void 01120 Fl_File_Chooser::previewCB(Fl_File_Chooser *fc) { // I - File chooser 01121 fc->update_preview(); 01122 } 01123 01124 01125 // 01126 // 'Fl_File_Chooser::rescan()' - Rescan the current directory. 01127 // 01128 01129 void 01130 Fl_File_Chooser::rescan() 01131 { 01132 char pathname[FL_PATH_MAX]; // New pathname for filename field 01133 01134 01135 // Clear the current filename 01136 strlcpy(pathname, directory_, sizeof(pathname)); 01137 if (pathname[0] && pathname[strlen(pathname) - 1] != '/') { 01138 strlcat(pathname, "/", sizeof(pathname)); 01139 } 01140 // puts("Setting fileName in rescan()"); 01141 fileName->value(pathname); 01142 01143 if (type_ & DIRECTORY) 01144 okButton->activate(); 01145 else 01146 okButton->deactivate(); 01147 01148 // Build the file list... 01149 fileList->load(directory_, sort); 01150 01151 // Update the preview box... 01152 update_preview(); 01153 } 01154 01155 // 01160 void Fl_File_Chooser::rescan_keep_filename() 01161 { 01162 // if no filename was set, this is likely a diretory browser 01163 const char *fn = fileName->value(); 01164 if (!fn || !*fn || fn[strlen(fn) - 1]=='/') { 01165 rescan(); 01166 return; 01167 } 01168 01169 int i; 01170 char pathname[FL_PATH_MAX]; // New pathname for filename field 01171 strlcpy(pathname, fn, sizeof(pathname)); 01172 01173 // Build the file list... 01174 fileList->load(directory_, sort); 01175 01176 // Update the preview box... 01177 update_preview(); 01178 01179 // and select the chosen file 01180 char found = 0; 01181 char *slash = strrchr(pathname, '/'); 01182 if (slash) 01183 slash++; 01184 else 01185 slash = pathname; 01186 for (i = 1; i <= fileList->size(); i ++) 01187 #if defined(WIN32) || defined(__EMX__) 01188 if (strcasecmp(fileList->text(i), slash) == 0) { 01189 #else 01190 if (strcmp(fileList->text(i), slash) == 0) { 01191 #endif // WIN32 || __EMX__ 01192 fileList->topline(i); 01193 fileList->select(i); 01194 found = 1; 01195 break; 01196 } 01197 01198 // update OK button activity 01199 if (found || type_ & CREATE) 01200 okButton->activate(); 01201 else 01202 okButton->deactivate(); 01203 } 01204 01205 01206 // 01207 // 'Fl_File_Chooser::showChoiceCB()' - Handle show selections. 01208 // 01209 01210 void 01211 Fl_File_Chooser::showChoiceCB() 01212 { 01213 const char *item, // Selected item 01214 *patstart; // Start of pattern 01215 char *patend; // End of pattern 01216 char temp[FL_PATH_MAX]; // Temporary string for pattern 01217 01218 01219 item = showChoice->text(showChoice->value()); 01220 01221 if (strcmp(item, custom_filter_label) == 0) { 01222 if ((item = fl_input("%s", pattern_, custom_filter_label)) != NULL) { 01223 strlcpy(pattern_, item, sizeof(pattern_)); 01224 01225 quote_pathname(temp, item, sizeof(temp)); 01226 showChoice->add(temp); 01227 showChoice->value(showChoice->size() - 2); 01228 } 01229 } else if ((patstart = strchr(item, '(')) == NULL) { 01230 strlcpy(pattern_, item, sizeof(pattern_)); 01231 } else { 01232 strlcpy(pattern_, patstart + 1, sizeof(pattern_)); 01233 if ((patend = strrchr(pattern_, ')')) != NULL) *patend = '\0'; 01234 } 01235 01236 fileList->filter(pattern_); 01237 01238 if (shown()) { 01239 // Rescan the directory... 01240 rescan_keep_filename(); 01241 } 01242 } 01243 01244 01245 // 01246 // 'Fl_File_Chooser::update_favorites()' - Update the favorites menu. 01247 // 01248 01249 void 01250 Fl_File_Chooser::update_favorites() 01251 { 01252 int i; // Looping var 01253 char pathname[FL_PATH_MAX], // Pathname 01254 menuname[2048]; // Menu name 01255 const char *home; // Home directory 01256 01257 01258 favoritesButton->clear(); 01259 favoritesButton->add("bla"); 01260 favoritesButton->clear(); 01261 favoritesButton->add(add_favorites_label, FL_ALT + 'a', 0); 01262 favoritesButton->add(manage_favorites_label, FL_ALT + 'm', 0, 0, FL_MENU_DIVIDER); 01263 favoritesButton->add(filesystems_label, FL_ALT + 'f', 0); 01264 01265 if ((home = getenv("HOME")) != NULL) { 01266 quote_pathname(menuname, home, sizeof(menuname)); 01267 favoritesButton->add(menuname, FL_ALT + 'h', 0); 01268 } 01269 01270 for (i = 0; i < 100; i ++) { 01271 sprintf(menuname, "favorite%02d", i); 01272 prefs_.get(menuname, pathname, "", sizeof(pathname)); 01273 if (!pathname[0]) break; 01274 01275 quote_pathname(menuname, pathname, sizeof(menuname)); 01276 01277 if (i < 10) favoritesButton->add(menuname, FL_ALT + '0' + i, 0); 01278 else favoritesButton->add(menuname); 01279 } 01280 01281 if (i == 100) ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate(); 01282 } 01283 01284 01285 // 01286 // 'Fl_File_Chooser::update_preview()' - Update the preview box... 01287 // 01288 01289 void 01290 Fl_File_Chooser::update_preview() 01291 { 01292 const char *filename; // Current filename 01293 const char *newlabel = 0; // New label text 01294 Fl_Shared_Image *image = 0, // New image 01295 *oldimage; // Old image 01296 int pbw, pbh; // Width and height of preview box 01297 int w, h; // Width and height of preview image 01298 int set = 0; // Set this flag as soon as a decent preview is found 01299 01300 01301 if (!previewButton->value()) return; 01302 01303 filename = value(); 01304 if (filename == NULL) { 01305 // no file name at all, so we have an empty preview 01306 set = 1; 01307 } else if (fl_filename_isdir(filename)) { 01308 // filename is a directory, show a folder icon 01309 newlabel = "@fileopen"; 01310 set = 1; 01311 } else { 01312 struct stat s; 01313 if (fl_stat(filename, &s)==0) { 01314 if ((s.st_mode&S_IFMT)!=S_IFREG) { 01315 // this is no regular file, probably some kind of device 01316 newlabel = "@-3refresh"; // a cross 01317 set = 1; 01318 } else if (s.st_size==0) { 01319 // this file is emty 01320 newlabel = "<empty file>"; 01321 set = 1; 01322 } else { 01323 // if this file is an image, try to load it 01324 window->cursor(FL_CURSOR_WAIT); 01325 Fl::check(); 01326 01327 image = Fl_Shared_Image::get(filename); 01328 01329 if (image) { 01330 window->cursor(FL_CURSOR_DEFAULT); 01331 Fl::check(); 01332 set = 1; 01333 } 01334 } 01335 } 01336 } 01337 01338 oldimage = (Fl_Shared_Image *)previewBox->image(); 01339 01340 if (oldimage) oldimage->release(); 01341 01342 previewBox->image(0); 01343 01344 if (!set) { 01345 FILE *fp; 01346 int bytes; 01347 char *ptr; 01348 01349 if (filename) fp = fl_fopen(filename, "rb"); 01350 else fp = NULL; 01351 01352 if (fp != NULL) { 01353 // Try reading the first 1k of data for a label... 01354 bytes = fread(preview_text_, 1, sizeof(preview_text_) - 1, fp); 01355 preview_text_[bytes] = '\0'; 01356 fclose(fp); 01357 } else { 01358 // Assume we can't read any data... 01359 preview_text_[0] = '\0'; 01360 } 01361 01362 window->cursor(FL_CURSOR_DEFAULT); 01363 Fl::check(); 01364 01365 // Scan the buffer for printable UTF8 chars... 01366 for (ptr = preview_text_; *ptr; ptr++) { 01367 uchar c = uchar(*ptr); 01368 if ( (c&0x80)==0 ) { 01369 if (!isprint(c&255) && !isspace(c&255)) break; 01370 } else if ( (c&0xe0)==0xc0 ) { 01371 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break; 01372 ptr++; 01373 } else if ( (c&0xf0)==0xe0 ) { 01374 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break; 01375 ptr++; 01376 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break; 01377 ptr++; 01378 } else if ( (c&0xf8)==0xf0 ) { 01379 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break; 01380 ptr++; 01381 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break; 01382 ptr++; 01383 if (ptr[1] && (ptr[1]&0xc0)!=0x80) break; 01384 ptr++; 01385 } 01386 } 01387 // *ptr && (isprint(*ptr & 255) || isspace(*ptr & 255)); 01388 // ptr ++); 01389 01390 // Scan the buffer for printable characters in 8 bit 01391 if (*ptr || ptr == preview_text_) { 01392 for (ptr = preview_text_; 01393 *ptr && (isprint(*ptr & 255) || isspace(*ptr & 255)); 01394 ptr ++); 01395 } 01396 01397 if (*ptr || ptr == preview_text_) { 01398 // Non-printable file, just show a big ?... 01399 previewBox->label(filename ? "?" : 0); 01400 previewBox->align(FL_ALIGN_CLIP); 01401 previewBox->labelsize(75); 01402 previewBox->labelfont(FL_HELVETICA); 01403 } else { 01404 // Show the first 1k of text... 01405 int size = previewBox->h() / 20; 01406 if (size < 6) size = 6; 01407 else if (size > 14) size = 14; 01408 01409 previewBox->label(preview_text_); 01410 previewBox->align((Fl_Align)(FL_ALIGN_CLIP | FL_ALIGN_INSIDE | 01411 FL_ALIGN_LEFT | FL_ALIGN_TOP)); 01412 previewBox->labelsize(size); 01413 previewBox->labelfont(FL_COURIER); 01414 } 01415 } else if (image) { 01416 pbw = previewBox->w() - 20; 01417 pbh = previewBox->h() - 20; 01418 01419 if (image->w() > pbw || image->h() > pbh) { 01420 w = pbw; 01421 h = w * image->h() / image->w(); 01422 01423 if (h > pbh) { 01424 h = pbh; 01425 w = h * image->w() / image->h(); 01426 } 01427 01428 oldimage = (Fl_Shared_Image *)image->copy(w, h); 01429 previewBox->image((Fl_Image *)oldimage); 01430 01431 image->release(); 01432 } else { 01433 previewBox->image((Fl_Image *)image); 01434 } 01435 01436 previewBox->align(FL_ALIGN_CLIP); 01437 previewBox->label(0); 01438 } else if (newlabel) { 01439 previewBox->label(newlabel); 01440 previewBox->align(FL_ALIGN_CLIP); 01441 previewBox->labelsize(newlabel[0]=='@'?75:12); 01442 previewBox->labelfont(FL_HELVETICA); 01443 } 01444 01445 previewBox->redraw(); 01446 } 01447 01448 01449 // 01450 // 'Fl_File_Chooser::value()' - Return a selected filename. 01451 // 01452 01453 const char * // O - Filename or NULL 01454 Fl_File_Chooser::value(int f) // I - File number 01455 { 01456 int i; // Looping var 01457 int fcount; // Number of selected files 01458 const char *name; // Current filename 01459 static char pathname[FL_PATH_MAX]; // Filename + directory 01460 01461 01462 name = fileName->value(); 01463 01464 if (!(type_ & MULTI)) { 01465 // Return the filename in the filename field... 01466 if (!name || !name[0]) return NULL; 01467 else return name; 01468 } 01469 01470 // Return a filename from the list... 01471 for (i = 1, fcount = 0; i <= fileList->size(); i ++) 01472 if (fileList->selected(i)) { 01473 // See if this file is a selected file/directory... 01474 name = fileList->text(i); 01475 01476 fcount ++; 01477 01478 if (fcount == f) { 01479 if (directory_[0]) { 01480 snprintf(pathname, sizeof(pathname), "%s/%s", directory_, name); 01481 } else { 01482 strlcpy(pathname, name, sizeof(pathname)); 01483 } 01484 01485 return pathname; 01486 } 01487 } 01488 01489 // If nothing is selected, use the filename field... 01490 if (!name || !name[0]) return NULL; 01491 else return name; 01492 } 01493 01494 01495 // 01496 // 'Fl_File_Chooser::value()' - Set the current filename. 01497 // 01498 01499 void 01500 Fl_File_Chooser::value(const char *filename) 01501 // I - Filename + directory 01502 { 01503 int i, // Looping var 01504 fcount; // Number of items in list 01505 char *slash; // Directory separator 01506 char pathname[FL_PATH_MAX]; // Local copy of filename 01507 01508 01509 // printf("Fl_File_Chooser::value(\"%s\")\n", filename == NULL ? "(null)" : filename); 01510 01511 // See if the filename is the "My System" directory... 01512 if (filename == NULL || !filename[0]) { 01513 // Yes, just change the current directory... 01514 directory(filename); 01515 fileName->value(""); 01516 okButton->deactivate(); 01517 return; 01518 } 01519 01520 #ifdef WIN32 01521 // See if the filename contains backslashes... 01522 char fixpath[FL_PATH_MAX]; // Path with slashes converted 01523 if (strchr(filename, '\\')) { 01524 // Convert backslashes to slashes... 01525 strlcpy(fixpath, filename, sizeof(fixpath)); 01526 01527 for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\')) 01528 *slash = '/'; 01529 01530 filename = fixpath; 01531 } 01532 #endif // WIN32 01533 01534 // See if there is a directory in there... 01535 fl_filename_absolute(pathname, sizeof(pathname), filename); 01536 01537 if ((slash = strrchr(pathname, '/')) != NULL) { 01538 // Yes, change the display to the directory... 01539 if (!fl_filename_isdir(pathname)) *slash++ = '\0'; 01540 01541 directory(pathname); 01542 if (*slash == '/') slash = pathname; 01543 } else { 01544 directory("."); 01545 slash = pathname; 01546 } 01547 01548 // Set the input field to the absolute path... 01549 if (slash > pathname) slash[-1] = '/'; 01550 01551 fileName->value(pathname); 01552 fileName->position(0, strlen(pathname)); 01553 okButton->activate(); 01554 01555 // Then find the file in the file list and select it... 01556 fcount = fileList->size(); 01557 01558 fileList->deselect(0); 01559 fileList->redraw(); 01560 01561 for (i = 1; i <= fcount; i ++) 01562 #if defined(WIN32) || defined(__EMX__) 01563 if (strcasecmp(fileList->text(i), slash) == 0) { 01564 #else 01565 if (strcmp(fileList->text(i), slash) == 0) { 01566 #endif // WIN32 || __EMX__ 01567 // printf("Selecting line %d...\n", i); 01568 fileList->topline(i); 01569 fileList->select(i); 01570 break; 01571 } 01572 } 01573 01574 01575 // 01576 // 'compare_dirnames()' - Compare two directory names. 01577 // 01578 01579 static int 01580 compare_dirnames(const char *a, const char *b) { 01581 int alen, blen; 01582 01583 // Get length of each string... 01584 alen = strlen(a) - 1; 01585 blen = strlen(b) - 1; 01586 01587 if (alen < 0 || blen < 0) return alen - blen; 01588 01589 // Check for trailing slashes... 01590 if (a[alen] != '/') alen ++; 01591 if (b[blen] != '/') blen ++; 01592 01593 // If the lengths aren't the same, then return the difference... 01594 if (alen != blen) return alen - blen; 01595 01596 // Do a comparison of the first N chars (alen == blen at this point)... 01597 #ifdef WIN32 01598 return strncasecmp(a, b, alen); 01599 #else 01600 return strncmp(a, b, alen); 01601 #endif // WIN32 01602 } 01603 01604 01605 // 01606 // 'quote_pathname()' - Quote a pathname for a menu. 01607 // 01608 01609 static void 01610 quote_pathname(char *dst, // O - Destination string 01611 const char *src, // I - Source string 01612 int dstsize) // I - Size of destination string 01613 { 01614 dstsize --; 01615 01616 while (*src && dstsize > 1) { 01617 if (*src == '\\') { 01618 // Convert backslash to forward slash... 01619 *dst++ = '\\'; 01620 *dst++ = '/'; 01621 src ++; 01622 } else { 01623 if (*src == '/') *dst++ = '\\'; 01624 01625 *dst++ = *src++; 01626 } 01627 } 01628 01629 *dst = '\0'; 01630 } 01631 01632 01633 // 01634 // 'unquote_pathname()' - Unquote a pathname from a menu. 01635 // 01636 01637 static void 01638 unquote_pathname(char *dst, // O - Destination string 01639 const char *src, // I - Source string 01640 int dstsize) // I - Size of destination string 01641 { 01642 dstsize --; 01643 01644 while (*src && dstsize > 1) { 01645 if (*src == '\\') src ++; 01646 *dst++ = *src++; 01647 } 01648 01649 *dst = '\0'; 01650 } 01651 01652 01653 // 01654 // End of "$Id: Fl_File_Chooser2.cxx 8063 2010-12-19 21:20:10Z matt $". 01655 //