|
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_WIN32.cxx 7977 2010-12-08 13:16:27Z AlbrechtS $" 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 // Any application to multi-folder implementation: 00030 // http://www.codeproject.com/dialog/selectfolder.asp 00031 // 00032 00033 #ifndef FL_DOXYGEN // PREVENT DOXYGEN'S USE OF THIS FILE 00034 00035 #include <stdio.h> // debugging 00036 #include <wchar.h> //MG 00037 #include "Fl_Native_File_Chooser_common.cxx" // strnew/strfree/strapp/chrcat 00038 typedef const wchar_t *LPCWSTR; //MG 00039 LPCWSTR utf8towchar(const char *in); //MG 00040 char *wchartoutf8(LPCWSTR in); //MG 00041 00042 #include <FL/Fl_Native_File_Chooser.H> 00043 00044 #define LCURLY_CHR '{' 00045 #define RCURLY_CHR '}' 00046 #define LBRACKET_CHR '[' 00047 #define RBRACKET_CHR ']' 00048 #define MAXFILTERS 80 00049 00050 void fl_OleInitialize(); // in Fl.cxx (Windows only) 00051 00052 // STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG) 00053 #ifdef DEBUG 00054 static void dnullprint(char *wp) { 00055 if ( ! wp ) return; 00056 for ( int t=0; true; t++ ) { 00057 if ( wp[t] == '\0' && wp[t+1] == '\0' ) { 00058 printf("\\0\\0"); 00059 fflush(stdout); 00060 return; 00061 } else if ( wp[t] == '\0' ) { 00062 printf("\\0"); 00063 } else { 00064 printf("%c",wp[t]); 00065 } 00066 } 00067 } 00068 #endif 00069 00070 // RETURN LENGTH OF DOUBLENULL STRING 00071 // Includes single nulls in count, excludes trailing doublenull. 00072 // 00073 // 1234 567 00074 // |||/\||| 00075 // IN: "one\0two\0\0" 00076 // OUT: 7 00077 // 00078 static int dnulllen(const char *wp) { 00079 int len = 0; 00080 while ( ! ( *(wp+0) == 0 && *(wp+1) == 0 ) ) { 00081 ++wp; 00082 ++len; 00083 } 00084 return(len); 00085 } 00086 00087 // STATIC: Append a string to another, leaving terminated with DOUBLE NULL. 00088 // Automatically handles extending length of string. 00089 // wp can be NULL (a new wp will be allocated and initialized). 00090 // string must be NULL terminated. 00091 // The pointer wp may be modified on return. 00092 // 00093 static void dnullcat(char*&wp, const char *string, int n = -1 ) { 00094 //DEBUG printf("DEBUG: dnullcat IN: <"); dnullprint(wp); printf(">\n"); 00095 int inlen = ( n < 0 ) ? strlen(string) : n; 00096 if ( ! wp ) { 00097 wp = new char[inlen + 4]; 00098 *(wp+0) = '\0'; 00099 *(wp+1) = '\0'; 00100 } else { 00101 int wplen = dnulllen(wp); 00102 // Make copy of wp into larger buffer 00103 char *tmp = new char[wplen + inlen + 4]; 00104 memcpy(tmp, wp, wplen+2); // copy of wp plus doublenull 00105 delete [] wp; // delete old wp 00106 wp = tmp; // use new copy 00107 //DEBUG printf("DEBUG: dnullcat COPY: <"); dnullprint(wp); printf("> (wplen=%d)\n", wplen); 00108 } 00109 00110 // Find end of double null string 00111 // *wp2 is left pointing at second null. 00112 // 00113 char *wp2 = wp; 00114 if ( *(wp2+0) != '\0' && *(wp2+1) != '\0' ) { 00115 for ( ; 1; wp2++ ) { 00116 if ( *(wp2+0) == '\0' && *(wp2+1) == '\0' ) { 00117 wp2++; 00118 break; 00119 } 00120 } 00121 } 00122 00123 if ( n == -1 ) n = strlen(string); 00124 strncpy(wp2, string, n); 00125 00126 // Leave string double-null terminated 00127 *(wp2+n+0) = '\0'; 00128 *(wp2+n+1) = '\0'; 00129 //DEBUG printf("DEBUG: dnullcat OUT: <"); dnullprint(wp); printf(">\n\n"); 00130 } 00131 00132 // CTOR 00133 Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { 00134 _btype = val; 00135 _options = NO_OPTIONS; 00136 memset((void*)&_ofn, 0, sizeof(OPENFILENAMEW)); 00137 _ofn.lStructSize = sizeof(OPENFILENAMEW); 00138 _ofn.hwndOwner = NULL; 00139 memset((void*)&_binf, 0, sizeof(BROWSEINFO)); 00140 _pathnames = NULL; 00141 _tpathnames = 0; 00142 _directory = NULL; 00143 _title = NULL; 00144 _filter = NULL; 00145 _parsedfilt = NULL; 00146 _nfilters = 0; 00147 _preset_file = NULL; 00148 _errmsg = NULL; 00149 } 00150 00151 // DTOR 00152 Fl_Native_File_Chooser::~Fl_Native_File_Chooser() { 00153 //_pathnames // managed by clear_pathnames() 00154 //_tpathnames // managed by clear_pathnames() 00155 _directory = strfree(_directory); 00156 _title = strfree(_title); 00157 _filter = strfree(_filter); 00158 //_parsedfilt // managed by clear_filters() 00159 //_nfilters // managed by clear_filters() 00160 _preset_file = strfree(_preset_file); 00161 _errmsg = strfree(_errmsg); 00162 clear_filters(); 00163 clear_pathnames(); 00164 ClearOFN(); 00165 ClearBINF(); 00166 } 00167 00168 // SET TYPE OF BROWSER 00169 void Fl_Native_File_Chooser::type(int val) { 00170 _btype = val; 00171 } 00172 00173 // GET TYPE OF BROWSER 00174 int Fl_Native_File_Chooser::type() const { 00175 return( _btype ); 00176 } 00177 00178 // SET OPTIONS 00179 void Fl_Native_File_Chooser::options(int val) { 00180 _options = val; 00181 } 00182 00183 // GET OPTIONS 00184 int Fl_Native_File_Chooser::options() const { 00185 return(_options); 00186 } 00187 00188 // PRIVATE: SET ERROR MESSAGE 00189 void Fl_Native_File_Chooser::errmsg(const char *val) { 00190 _errmsg = strfree(_errmsg); 00191 _errmsg = strnew(val); 00192 } 00193 00194 // FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS 00195 void Fl_Native_File_Chooser::clear_pathnames() { 00196 if ( _pathnames ) { 00197 while ( --_tpathnames >= 0 ) { 00198 _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]); 00199 } 00200 delete [] _pathnames; 00201 _pathnames = NULL; 00202 } 00203 _tpathnames = 0; 00204 } 00205 00206 // SET A SINGLE PATHNAME 00207 void Fl_Native_File_Chooser::set_single_pathname(const char *s) { 00208 clear_pathnames(); 00209 _pathnames = new char*[1]; 00210 _pathnames[0] = strnew(s); 00211 _tpathnames = 1; 00212 } 00213 00214 // ADD PATHNAME TO EXISTING ARRAY 00215 void Fl_Native_File_Chooser::add_pathname(const char *s) { 00216 if ( ! _pathnames ) { 00217 // Create first element in array 00218 ++_tpathnames; 00219 _pathnames = new char*[_tpathnames]; 00220 } else { 00221 // Grow array by 1 00222 char **tmp = new char*[_tpathnames+1]; // create new buffer 00223 memcpy((void*)tmp, (void*)_pathnames, 00224 sizeof(char*)*_tpathnames); // copy old 00225 delete [] _pathnames; // delete old 00226 _pathnames = tmp; // use new 00227 ++_tpathnames; 00228 } 00229 _pathnames[_tpathnames-1] = strnew(s); 00230 } 00231 00232 // FREE A PIDL (Pointer to IDentity List) 00233 void Fl_Native_File_Chooser::FreePIDL(ITEMIDLIST *pidl) { 00234 IMalloc *imalloc = NULL; 00235 if ( SUCCEEDED(SHGetMalloc(&imalloc)) ) { 00236 imalloc->Free(pidl); 00237 imalloc->Release(); 00238 imalloc = NULL; 00239 } 00240 } 00241 00242 // CLEAR MICROSOFT OFN (OPEN FILE NAME) CLASS 00243 void Fl_Native_File_Chooser::ClearOFN() { 00244 // Free any previously allocated lpstrFile before zeroing out _ofn 00245 if ( _ofn.lpstrFile ) { 00246 delete [] _ofn.lpstrFile; 00247 _ofn.lpstrFile = NULL; 00248 } 00249 if ( _ofn.lpstrInitialDir ) { 00250 delete [] (TCHAR*) _ofn.lpstrInitialDir; //msvc6 compilation fix 00251 _ofn.lpstrInitialDir = NULL; 00252 } 00253 _ofn.lpstrFilter = NULL; // (deleted elsewhere) 00254 int temp = _ofn.nFilterIndex; // keep the filter_value 00255 memset((void*)&_ofn, 0, sizeof(_ofn)); 00256 _ofn.lStructSize = sizeof(OPENFILENAMEW); 00257 _ofn.nFilterIndex = temp; 00258 } 00259 00260 // CLEAR MICROSOFT BINF (BROWSER INFO) CLASS 00261 void Fl_Native_File_Chooser::ClearBINF() { 00262 if ( _binf.pidlRoot ) { 00263 FreePIDL((ITEMIDLIST*)_binf.pidlRoot); 00264 _binf.pidlRoot = NULL; 00265 } 00266 memset((void*)&_binf, 0, sizeof(_binf)); 00267 } 00268 00269 // CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES 00270 void Fl_Native_File_Chooser::Win2Unix(char *s) { 00271 for ( ; *s; s++ ) 00272 if ( *s == '\\' ) *s = '/'; 00273 } 00274 00275 // CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES 00276 void Fl_Native_File_Chooser::Unix2Win(char *s) { 00277 for ( ; *s; s++ ) 00278 if ( *s == '/' ) *s = '\\'; 00279 } 00280 00281 // SHOW FILE BROWSER 00282 int Fl_Native_File_Chooser::showfile() { 00283 ClearOFN(); 00284 clear_pathnames(); 00285 size_t fsize = MAX_PATH; 00286 _ofn.Flags |= OFN_NOVALIDATE; // prevent disabling of front slashes 00287 _ofn.Flags |= OFN_HIDEREADONLY; // hide goofy readonly flag 00288 // USE NEW BROWSER 00289 _ofn.Flags |= OFN_EXPLORER; // use newer explorer windows 00290 _ofn.Flags |= OFN_ENABLESIZING; // allow window to be resized (hey, why not?) 00291 00292 // XXX: The docs for OFN_NOCHANGEDIR says the flag is 'ineffective' on XP/2K/NT! 00293 // But let's set it anyway.. 00294 // 00295 _ofn.Flags |= OFN_NOCHANGEDIR; // prevent dialog for messing up the cwd 00296 00297 switch ( _btype ) { 00298 case BROWSE_DIRECTORY: 00299 case BROWSE_MULTI_DIRECTORY: 00300 case BROWSE_SAVE_DIRECTORY: 00301 abort(); // never happens: handled by showdir() 00302 case BROWSE_FILE: 00303 fsize = 65536; // XXX: there must be a better way 00304 break; 00305 case BROWSE_MULTI_FILE: 00306 _ofn.Flags |= OFN_ALLOWMULTISELECT; 00307 fsize = 65536; // XXX: there must be a better way 00308 break; 00309 case BROWSE_SAVE_FILE: 00310 if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) { 00311 _ofn.Flags |= OFN_OVERWRITEPROMPT; 00312 } 00313 break; 00314 } 00315 // SPACE FOR RETURNED FILENAME 00316 _ofn.lpstrFile = new WCHAR[fsize]; 00317 _ofn.nMaxFile = fsize-1; 00318 _ofn.lpstrFile[0] = 0; 00319 _ofn.lpstrFile[1] = 0; // dnull 00320 // PARENT WINDOW 00321 _ofn.hwndOwner = GetForegroundWindow(); 00322 // DIALOG TITLE 00323 if (_title) { 00324 static WCHAR wtitle[200]; 00325 wcscpy(wtitle, utf8towchar(_title)); 00326 _ofn.lpstrTitle = wtitle; 00327 } else { 00328 _ofn.lpstrTitle = NULL; 00329 } 00330 // FILTER 00331 if (_parsedfilt != NULL) { // to convert a null-containing char string into a widechar string 00332 static WCHAR wpattern[MAX_PATH]; 00333 const char *p = _parsedfilt; 00334 while(*(p + strlen(p) + 1) != 0) p += strlen(p) + 1; 00335 p += strlen(p) + 2; 00336 MultiByteToWideChar(CP_UTF8, 0, _parsedfilt, p - _parsedfilt, wpattern, MAX_PATH); 00337 _ofn.lpstrFilter = wpattern; 00338 } else { 00339 _ofn.lpstrFilter = NULL; 00340 } 00341 // PRESET FILE 00342 // If set, supercedes _directory. See KB Q86920 for details 00343 // 00344 if ( _preset_file ) { 00345 size_t len = strlen(_preset_file); 00346 if ( len >= _ofn.nMaxFile ) { 00347 char msg[80]; 00348 sprintf(msg, "preset_file() filename is too long: %ld is >=%ld", (long)len, (long)fsize); 00349 return(-1); 00350 } 00351 wcscpy(_ofn.lpstrFile, utf8towchar(_preset_file)); 00352 // Unix2Win(_ofn.lpstrFile); 00353 len = wcslen(_ofn.lpstrFile); 00354 _ofn.lpstrFile[len+0] = 0; // multiselect needs dnull 00355 _ofn.lpstrFile[len+1] = 0; 00356 } 00357 if ( _directory ) { 00358 // PRESET DIR 00359 // XXX: See KB Q86920 for doc bug: 00360 // http://support.microsoft.com/default.aspx?scid=kb;en-us;86920 00361 // 00362 _ofn.lpstrInitialDir = new WCHAR[MAX_PATH]; 00363 wcscpy((WCHAR *)_ofn.lpstrInitialDir, utf8towchar(_directory)); 00364 // Unix2Win((char*)_ofn.lpstrInitialDir); 00365 } 00366 // SAVE THE CURRENT DIRECTORY 00367 // XXX: Save the cwd because GetOpenFileName() is probably going to 00368 // change it, in spite of the OFN_NOCHANGEDIR flag, due to its docs 00369 // saying the flag is 'ineffective'. %^( 00370 // 00371 char oldcwd[MAX_PATH]; 00372 GetCurrentDirectory(MAX_PATH, oldcwd); 00373 oldcwd[MAX_PATH-1] = '\0'; 00374 // OPEN THE DIALOG WINDOW 00375 int err; 00376 if ( _btype == BROWSE_SAVE_FILE ) { 00377 err = GetSaveFileNameW(&_ofn); 00378 } else { 00379 err = GetOpenFileNameW(&_ofn); 00380 } 00381 if ( err == 0 ) { 00382 // EXTENDED ERROR CHECK 00383 int err = CommDlgExtendedError(); 00384 // CANCEL? 00385 if ( err == 0 ) return(1); // user hit 'cancel' 00386 // AN ERROR OCCURRED 00387 char msg[80]; 00388 sprintf(msg, "CommDlgExtendedError() code=%d", err); 00389 errmsg(msg); 00390 // XXX: RESTORE CWD 00391 if ( oldcwd[0] ) SetCurrentDirectory(oldcwd); 00392 return(-1); 00393 } 00394 // XXX: RESTORE CWD 00395 if ( oldcwd[0] ) { 00396 SetCurrentDirectory(oldcwd); 00397 } 00398 // PREPARE PATHNAMES FOR RETURN 00399 switch ( _btype ) { 00400 case BROWSE_FILE: 00401 case BROWSE_SAVE_FILE: 00402 set_single_pathname(wchartoutf8(_ofn.lpstrFile)); 00403 // Win2Unix(_pathnames[_tpathnames-1]); 00404 break; 00405 case BROWSE_MULTI_FILE: { 00406 // EXTRACT MULTIPLE FILENAMES 00407 const WCHAR *dirname = _ofn.lpstrFile; 00408 int dirlen = wcslen(dirname); 00409 if ( dirlen > 0 ) { 00410 // WALK STRING SEARCHING FOR 'DOUBLE-NULL' 00411 // eg. "/dir/name\0foo1\0foo2\0foo3\0\0" 00412 // 00413 char pathname[MAX_PATH]; 00414 for ( const WCHAR *s = dirname + dirlen + 1; 00415 *s; s+= (wcslen(s)+1)) { 00416 strcpy(pathname, wchartoutf8(dirname)); 00417 strcat(pathname, "\\"); 00418 strcat(pathname, wchartoutf8(s)); 00419 add_pathname(pathname); 00420 } 00421 } 00422 // XXX 00423 // Work around problem where pasted forward-slash pathname 00424 // into the file browser causes new "Explorer" interface 00425 // not to grok forward slashes, passing back as a 'filename'..! 00426 // 00427 if ( _tpathnames == 0 ) { 00428 add_pathname(wchartoutf8(dirname)); 00429 // Win2Unix(_pathnames[_tpathnames-1]); 00430 } 00431 break; 00432 } 00433 case BROWSE_DIRECTORY: 00434 case BROWSE_MULTI_DIRECTORY: 00435 case BROWSE_SAVE_DIRECTORY: 00436 abort(); // never happens: handled by showdir() 00437 } 00438 return(0); 00439 } 00440 00441 // Used by SHBrowseForFolder(), sets initial selected dir. 00442 // Ref: Usenet: microsoft.public.vc.mfc, Dec 8 2000, 1:38p David Lowndes 00443 // Subject: How to specify to select an initial folder .." 00444 // 00445 int CALLBACK Fl_Native_File_Chooser::Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data) { 00446 switch (msg) { 00447 case BFFM_INITIALIZED: 00448 if (data) ::SendMessage(win, BFFM_SETSELECTION, TRUE, data); 00449 break; 00450 case BFFM_SELCHANGED: 00451 TCHAR path[MAX_PATH]; 00452 if ( SHGetPathFromIDList((ITEMIDLIST*)param, path) ) { 00453 ::SendMessage(win, BFFM_ENABLEOK, 0, 1); 00454 } else { 00455 // disable ok button if not a path 00456 ::SendMessage(win, BFFM_ENABLEOK, 0, 0); 00457 } 00458 break; 00459 case BFFM_VALIDATEFAILED: 00460 // we could pop up an annoying message here. 00461 // also needs set ulFlags |= BIF_VALIDATE 00462 break; 00463 default: 00464 break; 00465 } 00466 return(0); 00467 } 00468 00469 // SHOW DIRECTORY BROWSER 00470 int Fl_Native_File_Chooser::showdir() { 00471 // initialize OLE only once 00472 fl_OleInitialize(); // init needed by BIF_USENEWUI 00473 ClearBINF(); 00474 clear_pathnames(); 00475 // PARENT WINDOW 00476 _binf.hwndOwner = GetForegroundWindow(); 00477 // DIALOG TITLE 00478 _binf.lpszTitle = _title ? _title : NULL; 00479 // FLAGS 00480 _binf.ulFlags = 0; // initialize 00481 00482 // TBD: make sure matches to runtime system, if need be. 00483 //(what if _WIN32_IE doesn't match system? does the program not run?) 00484 // 00485 // TBD: match all 3 types of directories 00486 // 00487 // NOTE: *Don't* use BIF_SHAREABLE. It /disables/ mapped network shares 00488 // from being visible in BROWSE_DIRECTORY mode. 00489 // See Walter Garm's comments in ./TODO. 00490 00491 #if defined(BIF_NONEWFOLDERBUTTON) // Version 6.0 00492 if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_NONEWFOLDERBUTTON; 00493 _binf.ulFlags |= BIF_USENEWUI | BIF_RETURNONLYFSDIRS; 00494 #elif defined(BIF_USENEWUI) // Version 5.0 00495 if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_EDITBOX; 00496 else if ( _btype == BROWSE_SAVE_DIRECTORY ) _binf.ulFlags |= BIF_USENEWUI; 00497 _binf.ulFlags |= BIF_RETURNONLYFSDIRS; 00498 #elif defined(BIF_EDITBOX) // Version 4.71 00499 _binf.ulFlags |= BIF_RETURNONLYFSDIRS | BIF_EDITBOX; 00500 #else // Version Old 00501 _binf.ulFlags |= BIF_RETURNONLYFSDIRS; 00502 #endif 00503 00504 // BUFFER 00505 char displayname[MAX_PATH]; 00506 _binf.pszDisplayName = displayname; 00507 // PRESET DIR 00508 char presetname[MAX_PATH]; 00509 if ( _directory ) { 00510 strcpy(presetname, _directory); 00511 // Unix2Win(presetname); 00512 _binf.lParam = (LPARAM)presetname; 00513 } 00514 else _binf.lParam = 0; 00515 _binf.lpfn = Dir_CB; 00516 // OPEN BROWSER 00517 ITEMIDLIST *pidl = SHBrowseForFolder(&_binf); 00518 // CANCEL? 00519 if ( pidl == NULL ) return(1); 00520 00521 // GET THE PATHNAME(S) THE USER SELECTED 00522 // TBD: expand NetHood shortcuts from this PIDL?? 00523 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shbrowseforfolder.asp 00524 00525 TCHAR path[MAX_PATH]; 00526 if ( SHGetPathFromIDList(pidl, path) ) { 00527 // Win2Unix(path); 00528 add_pathname(path); 00529 } 00530 FreePIDL(pidl); 00531 if ( !strlen(path) ) return(1); // don't return empty pathnames 00532 return(0); 00533 } 00534 00535 // RETURNS: 00536 // 0 - user picked a file 00537 // 1 - user cancelled 00538 // -1 - failed; errmsg() has reason 00539 // 00540 int Fl_Native_File_Chooser::show() { 00541 if ( _btype == BROWSE_DIRECTORY || 00542 _btype == BROWSE_MULTI_DIRECTORY || 00543 _btype == BROWSE_SAVE_DIRECTORY ) { 00544 return(showdir()); 00545 } else { 00546 return(showfile()); 00547 } 00548 } 00549 00550 // RETURN ERROR MESSAGE 00551 const char *Fl_Native_File_Chooser::errmsg() const { 00552 return(_errmsg ? _errmsg : "No error"); 00553 } 00554 00555 // GET FILENAME 00556 const char* Fl_Native_File_Chooser::filename() const { 00557 if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]); 00558 return(""); 00559 } 00560 00561 // GET FILENAME FROM LIST OF FILENAMES 00562 const char* Fl_Native_File_Chooser::filename(int i) const { 00563 if ( _pathnames && i < _tpathnames ) return(_pathnames[i]); 00564 return(""); 00565 } 00566 00567 // GET TOTAL FILENAMES CHOSEN 00568 int Fl_Native_File_Chooser::count() const { 00569 return(_tpathnames); 00570 } 00571 00572 // PRESET PATHNAME 00573 // Can be NULL if no preset is desired. 00574 // 00575 void Fl_Native_File_Chooser::directory(const char *val) { 00576 _directory = strfree(_directory); 00577 _directory = strnew(val); 00578 } 00579 00580 // GET PRESET PATHNAME 00581 // Can return NULL if none set. 00582 // 00583 const char *Fl_Native_File_Chooser::directory() const { 00584 return(_directory); 00585 } 00586 00587 // SET TITLE 00588 // Can be NULL if no title desired. 00589 // 00590 void Fl_Native_File_Chooser::title(const char *val) { 00591 _title = strfree(_title); 00592 _title = strnew(val); 00593 } 00594 00595 // GET TITLE 00596 // Can return NULL if none set. 00597 // 00598 const char *Fl_Native_File_Chooser::title() const { 00599 return(_title); 00600 } 00601 00602 // SET FILTER 00603 // Can be NULL if no filter needed 00604 // 00605 void Fl_Native_File_Chooser::filter(const char *val) { 00606 _filter = strfree(_filter); 00607 clear_filters(); 00608 if ( val ) { 00609 _filter = strnew(val); 00610 parse_filter(_filter); 00611 } 00612 add_filter("All Files", "*.*"); // always include 'all files' option 00613 00614 #ifdef DEBUG 00615 nullprint(_parsedfilt); 00616 #endif /*DEBUG*/ 00617 } 00618 00619 // GET FILTER 00620 // Can return NULL if none set. 00621 // 00622 const char *Fl_Native_File_Chooser::filter() const { 00623 return(_filter); 00624 } 00625 00626 // CLEAR FILTERS 00627 void Fl_Native_File_Chooser::clear_filters() { 00628 _nfilters = 0; 00629 _parsedfilt = strfree(_parsedfilt); 00630 } 00631 00632 // ADD A FILTER 00633 void Fl_Native_File_Chooser::add_filter(const char *name_in, // name of filter (optional: can be null) 00634 const char *winfilter) { // windows style filter (eg. "*.cxx;*.h") 00635 // No name? Make one.. 00636 char name[1024]; 00637 if ( !name_in || name_in[0] == '\0' ) { 00638 sprintf(name, "%.*s Files", int(sizeof(name)-10), winfilter); 00639 } else { 00640 sprintf(name, "%.*s", int(sizeof(name)-10), name_in); 00641 } 00642 dnullcat(_parsedfilt, name); 00643 dnullcat(_parsedfilt, winfilter); 00644 _nfilters++; 00645 //DEBUG printf("DEBUG: ADD FILTER name=<%s> winfilter=<%s>\n", name, winfilter); 00646 } 00647 00648 // CONVERT FLTK STYLE PATTERN MATCHES TO WINDOWS 'DOUBLENULL' PATTERN 00649 // Handles: 00650 // IN OUT 00651 // ----------- ----------------------------- 00652 // *.{ma,mb} "*.{ma,mb} Files\0*.ma;*.mb\0\0" 00653 // *.[abc] "*.[abc] Files\0*.a;*.b;*.c\0\0" 00654 // *.txt "*.txt Files\0*.txt\0\0" 00655 // C Files\t*.[ch] "C Files\0*.c;*.h\0\0" 00656 // 00657 // Example: 00658 // IN: "*.{ma,mb}" 00659 // OUT: "*.ma;*.mb Files\0*.ma;*.mb\0All Files\0*.*\0\0" 00660 // --------------- --------- --------- --- 00661 // | | | | 00662 // Title Wildcards Title Wildcards 00663 // 00664 // Parsing Mode: 00665 // IN:"C Files\t*.{cxx,h}" 00666 // ||||||| ||||||||| 00667 // mode: nnnnnnn ww{{{{{{{ 00668 // \_____/ \_______/ 00669 // Name Wildcard 00670 // 00671 void Fl_Native_File_Chooser::parse_filter(const char *in) { 00672 clear_filters(); 00673 if ( ! in ) return; 00674 00675 int has_name = strchr(in, '\t') ? 1 : 0; 00676 00677 char mode = has_name ? 'n' : 'w'; // parse mode: n=name, w=wildcard 00678 int nwildcards = 0; 00679 char wildcards[MAXFILTERS][1024]; // parsed wildcards (can be several) 00680 char wildprefix[512] = ""; 00681 char name[512] = ""; 00682 00683 // Init 00684 int t; 00685 for ( t=0; t<MAXFILTERS; t++ ) { 00686 wildcards[t][0] = '\0'; 00687 } 00688 00689 // Parse 00690 for ( ; 1; in++ ) { 00691 00695 00696 switch (*in) { 00697 case ',': 00698 case '|': 00699 if ( mode == LCURLY_CHR ) { 00700 // create new wildcard, copy in prefix 00701 strcat(wildcards[nwildcards++], wildprefix); 00702 continue; 00703 } else { 00704 goto regchar; 00705 } 00706 continue; 00707 00708 // FINISHED PARSING A NAME? 00709 case '\t': 00710 if ( mode != 'n' ) goto regchar; 00711 // finish parsing name? switch to wildcard mode 00712 mode = 'w'; 00713 break; 00714 00715 // ESCAPE NEXT CHAR 00716 case '\\': 00717 ++in; 00718 goto regchar; 00719 00720 // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS? 00721 case '\r': 00722 case '\n': 00723 case '\0': 00724 { 00725 if ( mode == 'w' ) { // finished parsing wildcard? 00726 if ( nwildcards == 0 ) { 00727 strcpy(wildcards[nwildcards++], wildprefix); 00728 } 00729 // Append wildcards in Microsoft's "*.one;*.two" format 00730 char comp[4096] = ""; 00731 for ( t=0; t<nwildcards; t++ ) { 00732 if ( t != 0 ) strcat(comp, ";"); 00733 strcat(comp, wildcards[t]); 00734 } 00735 // Add if not empty 00736 if ( comp[0] ) { 00737 add_filter(name, comp); 00738 } 00739 } 00740 // RESET 00741 for ( t=0; t<MAXFILTERS; t++ ) { 00742 wildcards[t][0] = '\0'; 00743 } 00744 nwildcards = 0; 00745 wildprefix[0] = name[0] = '\0'; 00746 mode = strchr(in,'\t') ? 'n' : 'w'; 00747 // DONE? 00748 if ( *in == '\0' ) return; // done 00749 continue; // not done yet, more filters 00750 } 00751 00752 // STARTING A WILDCARD? 00753 case LBRACKET_CHR: 00754 case LCURLY_CHR: 00755 mode = *in; 00756 if ( *in == LCURLY_CHR ) { 00757 // create new wildcard 00758 strcat(wildcards[nwildcards++], wildprefix); 00759 } 00760 continue; 00761 00762 // ENDING A WILDCARD? 00763 case RBRACKET_CHR: 00764 case RCURLY_CHR: 00765 mode = 'w'; // back to wildcard mode 00766 continue; 00767 00768 // ALL OTHER NON-SPECIAL CHARACTERS 00769 default: 00770 regchar: // handle regular char 00771 switch ( mode ) { 00772 case LBRACKET_CHR: 00773 // create new wildcard 00774 ++nwildcards; 00775 // copy in prefix 00776 strcpy(wildcards[nwildcards-1], wildprefix); 00777 // append search char 00778 chrcat(wildcards[nwildcards-1], *in); 00779 continue; 00780 00781 case LCURLY_CHR: 00782 if ( nwildcards > 0 ) { 00783 chrcat(wildcards[nwildcards-1], *in); 00784 } 00785 continue; 00786 00787 case 'n': 00788 chrcat(name, *in); 00789 continue; 00790 00791 case 'w': 00792 chrcat(wildprefix, *in); 00793 for ( t=0; t<nwildcards; t++ ) { 00794 chrcat(wildcards[t], *in); 00795 } 00796 continue; 00797 } 00798 break; 00799 } 00800 } 00801 } 00802 00803 // SET 'CURRENTLY SELECTED FILTER' 00804 void Fl_Native_File_Chooser::filter_value(int i) { 00805 _ofn.nFilterIndex = i + 1; 00806 } 00807 00808 // RETURN VALUE OF 'CURRENTLY SELECTED FILTER' 00809 int Fl_Native_File_Chooser::filter_value() const { 00810 return(_ofn.nFilterIndex ? _ofn.nFilterIndex-1 : _nfilters+1); 00811 } 00812 00813 // PRESET FILENAME FOR 'SAVE AS' CHOOSER 00814 void Fl_Native_File_Chooser::preset_file(const char* val) { 00815 _preset_file = strfree(_preset_file); 00816 _preset_file = strnew(val); 00817 } 00818 00819 // GET PRESET FILENAME FOR 'SAVE AS' CHOOSER 00820 const char* Fl_Native_File_Chooser::preset_file() const { 00821 return(_preset_file); 00822 } 00823 00824 char *wchartoutf8(LPCWSTR in) 00825 { 00826 static char *out = NULL; 00827 static int lchar = 0; 00828 if (in == NULL)return NULL; 00829 int utf8len = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL); 00830 if (utf8len > lchar) { 00831 lchar = utf8len; 00832 out = (char *)realloc(out, lchar * sizeof(char)); 00833 } 00834 WideCharToMultiByte(CP_UTF8, 0, in, -1, out, utf8len, NULL, NULL); 00835 return out; 00836 } 00837 00838 LPCWSTR utf8towchar(const char *in) 00839 { 00840 static WCHAR *wout = NULL; 00841 static int lwout = 0; 00842 if (in == NULL)return NULL; 00843 int wlen = MultiByteToWideChar(CP_UTF8, 0, in, -1, NULL, 0); 00844 if (wlen > lwout) { 00845 lwout = wlen; 00846 wout = (WCHAR *)realloc(wout, lwout * sizeof(WCHAR)); 00847 } 00848 MultiByteToWideChar(CP_UTF8, 0, in, -1, wout, wlen); 00849 return wout; 00850 } 00851 00852 #endif 00854 // 00855 // End of "$Id: Fl_Native_File_Chooser_WIN32.cxx 7977 2010-12-08 13:16:27Z AlbrechtS $". 00856 //