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)  

Fl_Native_File_Chooser_FLTK.cxx

Go to the documentation of this file.
00001 // "$Id: Fl_Native_File_Chooser_FLTK.cxx 7913 2010-11-29 18:18:27Z greg.ercolano $"
00002 //
00003 // FLTK native OS file chooser widget
00004 //
00005 // Copyright 1998-2010 by Bill Spitzak and others.
00006 // Copyright 2004 Greg Ercolano.
00007 // API changes + filter improvements by Nathan Vander Wilt 2005
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Library General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Library General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Library General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00022 // USA.
00023 //
00024 // Please report all bugs and problems to:
00025 //
00026 //     http://www.fltk.org/str.php
00027 //
00028 
00029 #include <FL/Fl_Native_File_Chooser.H>
00030 #include <FL/Fl_File_Icon.H>
00031 #define FLTK_CHOOSER_SINGLE    Fl_File_Chooser::SINGLE
00032 #define FLTK_CHOOSER_DIRECTORY Fl_File_Chooser::DIRECTORY
00033 #define FLTK_CHOOSER_MULTI     Fl_File_Chooser::MULTI
00034 #define FLTK_CHOOSER_CREATE    Fl_File_Chooser::CREATE
00035 
00036 #include "Fl_Native_File_Chooser_common.cxx"
00037 #include <sys/stat.h>
00038 #include <string.h>
00039 
00045 Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
00055   _btype       = val;
00056   _options     = NO_OPTIONS;
00057   _filter      = NULL;
00058   _filtvalue   = 0;
00059   _parsedfilt  = NULL;
00060   _preset_file = NULL;
00061   _prevvalue   = NULL;
00062   _directory   = NULL;
00063   _errmsg      = NULL;
00064   _file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL);
00065   type(val);                    // do this after _file_chooser created
00066   _nfilters    = 0;
00067 
00068   // Added by MG
00069   Fl_Button *b = _file_chooser->previewButton;
00070   Fl_Window *w = b->window();
00071   Fl_Group::current(w);         // adds a "Show hidden files" check button in _file_chooser's window
00072   show_hidden = new Fl_Check_Button(b->x() + b->w() + 10, b->y(), 145, b->h(), "Show hidden files");
00073   show_hidden->callback((Fl_Callback*)show_hidden_cb, this);
00074   my_fileList = _file_chooser->browser();
00075   _old_dir = 0;                                         // to detect directory changes
00076   prev_filtervalue = _file_chooser->filter_value();     // to detect filter changes
00077 } 
00078 
00083 Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
00084   delete _file_chooser;
00085   _filter      = strfree(_filter);
00086   _parsedfilt  = strfree(_parsedfilt);
00087   _preset_file = strfree(_preset_file);
00088   _prevvalue   = strfree(_prevvalue);
00089   _directory   = strfree(_directory);
00090   _errmsg      = strfree(_errmsg);
00091   _old_dir     = strfree(_old_dir);
00092 }
00093 
00094 // PRIVATE: SET ERROR MESSAGE
00095 void Fl_Native_File_Chooser::errmsg(const char *msg) {
00096   _errmsg = strfree(_errmsg);
00097   _errmsg = strnew(msg);
00098 }
00099 
00100 // PRIVATE: translate Native types to Fl_File_Chooser types
00101 int Fl_Native_File_Chooser::type_fl_file(int val) {
00102   switch (val) {
00103     case BROWSE_FILE:
00104       return(FLTK_CHOOSER_SINGLE);
00105     case BROWSE_DIRECTORY:
00106       return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_DIRECTORY);
00107     case BROWSE_MULTI_FILE:
00108       return(FLTK_CHOOSER_MULTI);
00109     case BROWSE_MULTI_DIRECTORY:
00110       return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI);
00111     case BROWSE_SAVE_FILE:
00112       return(FLTK_CHOOSER_SINGLE | FLTK_CHOOSER_CREATE);
00113     case BROWSE_SAVE_DIRECTORY:
00114       return(FLTK_CHOOSER_DIRECTORY | FLTK_CHOOSER_MULTI | FLTK_CHOOSER_CREATE);
00115     default:
00116       return(FLTK_CHOOSER_SINGLE);
00117   }
00118 }
00119 
00123 void Fl_Native_File_Chooser::type(int val) {
00124   _btype = val;
00125   _file_chooser->type(type_fl_file(val));
00126 }
00127 
00131 int Fl_Native_File_Chooser::type() const {
00132   return(_btype);
00133 }
00134 
00148 void Fl_Native_File_Chooser::options(int val) {
00149   _options = val;
00150 }
00151 
00155 int Fl_Native_File_Chooser::options() const {
00156   return(_options);
00157 }
00158 
00166 int Fl_Native_File_Chooser::show() {
00167   // FILTER
00168   if ( _parsedfilt ) {
00169     _file_chooser->filter(_parsedfilt);
00170   }
00171 
00172   // FILTER VALUE
00173   //     Set this /after/ setting the filter
00174   //
00175   _file_chooser->filter_value(_filtvalue);
00176 
00177   // DIRECTORY
00178   if ( _directory && _directory[0] ) {
00179     _file_chooser->directory(_directory);
00180   } else {
00181     _file_chooser->directory(_prevvalue);
00182   }
00183 
00184   // PRESET FILE
00185   if ( _preset_file ) {
00186     _file_chooser->value(_preset_file);
00187   }
00188 
00189   // OPTIONS: PREVIEW
00190   _file_chooser->preview( (options() & PREVIEW) ? 1 : 0);
00191 
00192   // OPTIONS: NEW FOLDER
00193   if ( options() & NEW_FOLDER )
00194     _file_chooser->type(_file_chooser->type() | FLTK_CHOOSER_CREATE);   // on
00195 
00196   // SHOW
00197   _file_chooser->show();
00198 
00199   // BLOCK WHILE BROWSER SHOWN
00200   while ( _file_chooser->shown() ) {
00201     if (_old_dir==0 || strcmp(_old_dir, _file_chooser->directory()) != 0) {
00202       _old_dir = strfree(_old_dir);
00203       _old_dir = strnew(_file_chooser->directory());
00204       if (!show_hidden->value()) remove_hidden_files(my_fileList);
00205     } else if (prev_filtervalue != _file_chooser->filter_value() ) {
00206       prev_filtervalue = _file_chooser->filter_value();
00207       if (!show_hidden->value() ) remove_hidden_files(my_fileList);
00208     }
00209     Fl::wait();
00210   }
00211 
00212   if ( _file_chooser->value() && _file_chooser->value()[0] ) {
00213     _prevvalue = strfree(_prevvalue);
00214     _prevvalue = strnew(_file_chooser->value());
00215     _filtvalue = _file_chooser->filter_value(); // update filter value
00216 
00217     // HANDLE SHOWING 'SaveAs' CONFIRM
00218     if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
00219       struct stat buf;
00220       if ( stat(_file_chooser->value(), &buf) != -1 ) {
00221         if ( buf.st_mode & S_IFREG ) {          // Regular file + exists?
00222           if ( exist_dialog() == 0 ) {
00223             return(1);
00224           }
00225         }
00226       }
00227     }
00228   }
00229 
00230   if ( _file_chooser->count() ) return(0);
00231   else return(1);
00232 }
00233 
00239 const char *Fl_Native_File_Chooser::errmsg() const {
00240   return(_errmsg ? _errmsg : "No error");
00241 }
00242 
00249 const char* Fl_Native_File_Chooser::filename() const {
00250   if ( _file_chooser->count() > 0 ) return(_file_chooser->value());
00251   return("");
00252 }
00253 
00268 const char* Fl_Native_File_Chooser::filename(int i) const {
00269   if ( i < _file_chooser->count() )
00270     return(_file_chooser->value(i+1));  // convert fltk 1 based to our 0 based
00271   return("");
00272 }
00273 
00279 void Fl_Native_File_Chooser::title(const char *val) {
00280   _file_chooser->label(val);
00281 }
00282 
00287 const char *Fl_Native_File_Chooser::title() const {
00288   return(_file_chooser->label());
00289 }
00290 
00309 void Fl_Native_File_Chooser::filter(const char *val) {
00310   _filter = strfree(_filter);
00311   _filter = strnew(val);
00312   parse_filter();
00313 }
00314 
00319 const char *Fl_Native_File_Chooser::filter() const {
00320   return(_filter);
00321 }
00322 
00326 int Fl_Native_File_Chooser::filters() const {
00327   return(_nfilters);
00328 }
00329 
00337 void Fl_Native_File_Chooser::filter_value(int val) {
00338   _filtvalue = val;
00339 }
00340 
00345 int Fl_Native_File_Chooser::filter_value() const {
00346   return(_filtvalue);
00347 }
00348 
00362 int Fl_Native_File_Chooser::count() const {
00363   return(_file_chooser->count());
00364 }
00365 
00371 void Fl_Native_File_Chooser::directory(const char *val) {
00372   _directory = strfree(_directory);
00373   _directory = strnew(val);
00374 }
00375 
00379 const char *Fl_Native_File_Chooser::directory() const {
00380   return(_directory);
00381 }
00382 
00383 // PRIVATE: Convert our filter format to fltk's chooser format
00384 //     FROM                                     TO (FLTK)
00385 //     -------------------------                --------------------------
00386 //     "*.cxx"                                  "*.cxx Files(*.cxx)"
00387 //     "C Files\t*.{cxx,h}"                     "C Files(*.{cxx,h})"
00388 //     "C Files\t*.{cxx,h}\nText Files\t*.txt"  "C Files(*.{cxx,h})\tText Files(*.txt)"
00389 //
00390 //     Returns a modified version of the filter that the caller is responsible
00391 //     for freeing with strfree().
00392 //
00393 void Fl_Native_File_Chooser::parse_filter() {
00394   _parsedfilt = strfree(_parsedfilt);   // clear previous parsed filter (if any)
00395   _nfilters = 0;
00396   char *in = _filter;
00397   if ( !in ) return;
00398 
00399   int has_name = strchr(in, '\t') ? 1 : 0;
00400 
00401   char mode = has_name ? 'n' : 'w';     // parse mode: n=title, w=wildcard
00402   char wildcard[1024] = "";             // parsed wildcard
00403   char name[1024] = "";
00404 
00405   // Parse filter user specified
00406   for ( ; 1; in++ ) {
00407     /*** DEBUG
00408     printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n",
00409                         *in, mode,     name,     wildcard);
00410     ***/
00411 
00412     switch (*in) {
00413       // FINISHED PARSING NAME?
00414       case '\t':
00415         if ( mode != 'n' ) goto regchar;
00416         mode = 'w';
00417         break; 
00418       // ESCAPE NEXT CHAR
00419       case '\\':
00420         ++in;
00421         goto regchar; 
00422       // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
00423       case '\r':
00424       case '\n':
00425       case '\0':
00426         // APPEND NEW FILTER TO LIST
00427         if ( wildcard[0] ) {
00428           // OUT: "name(wild)\tname(wild)"
00429           char comp[2048];
00430           sprintf(comp, "%s%.511s(%.511s)", ((_parsedfilt)?"\t":""),
00431                                             name, wildcard);
00432           _parsedfilt = strapp(_parsedfilt, comp);
00433           _nfilters++;
00434           //DEBUG printf("DEBUG: PARSED FILT NOW <%s>\n", _parsedfilt);
00435         }
00436         // RESET
00437         wildcard[0] = name[0] = '\0';
00438         mode = strchr(in, '\t') ? 'n' : 'w';
00439         // DONE?
00440         if ( *in == '\0' ) return;      // done
00441         else continue;                  // not done yet, more filters
00442 
00443       // Parse all other chars
00444       default:                          // handle all non-special chars
00445       regchar:                          // handle regular char
00446         switch ( mode ) {
00447           case 'n': chrcat(name, *in);     continue;
00448           case 'w': chrcat(wildcard, *in); continue;
00449         }
00450         break;
00451     }
00452   }
00453   //NOTREACHED
00454 }
00455 
00462 void Fl_Native_File_Chooser::preset_file(const char* val) {
00463   _preset_file = strfree(_preset_file);
00464   _preset_file = strnew(val);
00465 }
00466 
00470 const char* Fl_Native_File_Chooser::preset_file() const {
00471   return(_preset_file);
00472 }
00473 
00474 void Fl_Native_File_Chooser::show_hidden_cb(Fl_Check_Button *o, void *data)
00475 {
00476   Fl_Native_File_Chooser *mychooser = (Fl_Native_File_Chooser *)data;
00477   if (o->value()) {
00478     mychooser->my_fileList->load(mychooser->_file_chooser->directory());
00479   } else {
00480     remove_hidden_files(mychooser->my_fileList);
00481     mychooser->my_fileList->redraw();
00482   }
00483 }
00484 
00485 // PRIVATE: Don't show hidden files
00486 void Fl_Native_File_Chooser::remove_hidden_files(Fl_File_Browser *my_fileList)
00487 {
00488   int count = my_fileList->size();
00489   for(int num = count; num >= 1; num--) {
00490     const char *p = my_fileList->text(num);
00491     if (*p == '.' && strcmp(p, "../") != 0) my_fileList->remove(num);
00492   }
00493   my_fileList->topline(1);
00494 }
00495 
00496 // PRIVATE: Don't show hidden files
00497 int Fl_Native_File_Chooser::exist_dialog() {
00498   return(fl_choice("File exists. Are you sure you want to overwrite?", 
00499                    "Cancel", "   OK   ", NULL));
00500 }
00501 
00502 //
00503 // End of "$Id: Fl_Native_File_Chooser_FLTK.cxx 7913 2010-11-29 18:18:27Z greg.ercolano $".
00504 //