|
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 // "$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 //