aboutsummaryrefslogtreecommitdiff
path: root/src/lib/FL/Fl_Native_File_Chooser_WIN32.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/FL/Fl_Native_File_Chooser_WIN32.cxx')
-rw-r--r--src/lib/FL/Fl_Native_File_Chooser_WIN32.cxx765
1 files changed, 765 insertions, 0 deletions
diff --git a/src/lib/FL/Fl_Native_File_Chooser_WIN32.cxx b/src/lib/FL/Fl_Native_File_Chooser_WIN32.cxx
new file mode 100644
index 0000000..226cf7b
--- /dev/null
+++ b/src/lib/FL/Fl_Native_File_Chooser_WIN32.cxx
@@ -0,0 +1,765 @@
1//
2// Fl_Native_File_Chooser_WINDOWS.cxx -- FLTK native OS file chooser widget
3//
4// Copyright 2004 by Greg Ercolano.
5// April 2005 - API changes, improved filter processing by Nathan Vander Wilt
6//
7// This library is free software; you can redistribute it and/or
8// modify it under the terms of the GNU Library General Public
9// License as published by the Free Software Foundation; either
10// version 2 of the License, or (at your option) any later version.
11//
12// This library is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// Library General Public License for more details.
16//
17// You should have received a copy of the GNU Library General Public
18// License along with this library; if not, write to the Free Software
19// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20// USA.
21//
22// Please keep code 80 column compliant.
23//
24// 10 20 30 40 50 60 70
25// | | | | | | |
26// 4567890123456789012345678901234567890123456789012345678901234567890123456789
27//
28
29// http://www.codeproject.com/dialog/selectfolder.asp - any application to multi-folder implementation?
30
31#include <FL/Fl_Native_File_Chooser.H>
32#include <stdio.h> // debugging
33#include "common.cxx" // strnew/strfree/strapp/chrcat
34
35#define LCURLY_CHR '{'
36#define RCURLY_CHR '}'
37#define LBRACKET_CHR '['
38#define RBRACKET_CHR ']'
39#ifndef BIF_NONEWFOLDERBUTTON
40#define BIF_NONEWFOLDERBUTTON 0x200
41#endif
42// STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG)
43/*
44static void dnullprint(char *wp) {
45 if ( ! wp ) return;
46 for ( int t=0; true; t++ ) {
47 if ( wp[t] == '\0' && wp[t+1] == '\0' ) {
48 printf("\\0\\0");
49 fflush(stdout);
50 return;
51 } else if ( wp[t] == '\0' ) {
52 printf("\\0");
53 } else {
54 printf("%c",wp[t]);
55 }
56 }
57}
58*/
59// RETURN LENGTH OF DOUBLENULL STRING
60// Includes single nulls in count, excludes trailing doublenull.
61//
62// 1234 567
63// |||/\|||
64// IN: "one\0two\0\0"
65// OUT: 7
66//
67static int dnulllen(const char *wp) {
68 int len = 0;
69 while ( ! ( *(wp+0) == 0 && *(wp+1) == 0 ) )
70 { ++wp; ++len; }
71 return(len);
72}
73
74// STATIC: Append a string to another, leaving terminated with DOUBLE NULL.
75// Automatically handles extending length of string.
76// wp can be NULL (a new wp will be allocated and initialized).
77// string must be NULL terminated.
78// The pointer wp may be modified on return.
79//
80static void dnullcat(char*&wp, const char *string, int n = -1 ) {
81 //DEBUG printf("DEBUG: dnullcat IN: <"); dnullprint(wp); printf(">\n");
82 int inlen = ( n < 0 ) ? strlen(string) : n;
83 if ( ! wp ) {
84 wp = new char[inlen + 4];
85 *(wp+0) = '\0';
86 *(wp+1) = '\0';
87 } else {
88 int wplen = dnulllen(wp);
89 // Make copy of wp into larger buffer
90 char *tmp = new char[wplen + inlen + 4];
91 memcpy(tmp, wp, wplen+2); // copy of wp plus doublenull
92 delete [] wp; // delete old wp
93 wp = tmp; // use new copy
94 //DEBUG printf("DEBUG: dnullcat COPY: <"); dnullprint(wp); printf("> (wplen=%d)\n", wplen);
95 }
96
97 // Find end of double null string
98 // *wp2 is left pointing at second null.
99 //
100 char *wp2 = wp;
101 if ( *(wp2+0) != '\0' && *(wp2+1) != '\0' ) {
102 for ( ; 1; wp2++ )
103 if ( *(wp2+0) == '\0' && *(wp2+1) == '\0' )
104 { wp2++; break; }
105 }
106
107 if ( n == -1 ) n = strlen(string);
108 strncpy(wp2, string, n);
109
110 // Leave string double-null terminated
111 *(wp2+n+0) = '\0';
112 *(wp2+n+1) = '\0';
113 //DEBUG printf("DEBUG: dnullcat OUT: <"); dnullprint(wp); printf(">\n\n");
114}
115
116// CTOR
117Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) {
118 _btype = val;
119 _options = NO_OPTIONS;
120 memset((void*)&_ofn, 0, sizeof(OPENFILENAME));
121 _ofn.lStructSize = sizeof(OPENFILENAME);
122 _ofn.hwndOwner = NULL;
123 memset((void*)&_binf, 0, sizeof(BROWSEINFO));
124 _pathnames = NULL;
125 _tpathnames = 0;
126 _directory = NULL;
127 _title = NULL;
128 _filter = NULL;
129 _parsedfilt = NULL;
130 _nfilters = 0;
131 _preset_file = NULL;
132 _errmsg = NULL;
133}
134
135// DTOR
136Fl_Native_File_Chooser::~Fl_Native_File_Chooser() {
137 //_pathnames // managed by clear_pathnames()
138 //_tpathnames // managed by clear_pathnames()
139 _directory = strfree(_directory);
140 _title = strfree(_title);
141 _filter = strfree(_filter);
142 //_parsedfilt // managed by clear_filters()
143 //_nfilters // managed by clear_filters()
144 _preset_file = strfree(_preset_file);
145 _errmsg = strfree(_errmsg);
146 clear_filters();
147 clear_pathnames();
148 ClearOFN();
149 ClearBINF();
150}
151
152// SET TYPE OF BROWSER
153void Fl_Native_File_Chooser::type(int val) {
154 _btype = val;
155}
156
157// GET TYPE OF BROWSER
158int Fl_Native_File_Chooser::type() const {
159 return( _btype );
160}
161
162// SET OPTIONS
163void Fl_Native_File_Chooser::options(int val) {
164 _options = val;
165}
166
167// GET OPTIONS
168int Fl_Native_File_Chooser::options() const {
169 return(_options);
170}
171
172// PRIVATE: SET ERROR MESSAGE
173void Fl_Native_File_Chooser::errmsg(const char *val) {
174 _errmsg = strfree(_errmsg);
175 _errmsg = strnew(val);
176}
177
178// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS
179void Fl_Native_File_Chooser::clear_pathnames() {
180 if ( _pathnames ) {
181 while ( --_tpathnames >= 0 ) {
182 _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]);
183 }
184 delete [] _pathnames;
185 _pathnames = NULL;
186 }
187 _tpathnames = 0;
188}
189
190// SET A SINGLE PATHNAME
191void Fl_Native_File_Chooser::set_single_pathname(const char *s) {
192 clear_pathnames();
193 _pathnames = new char*[1];
194 _pathnames[0] = strnew(s);
195 _tpathnames = 1;
196}
197
198// ADD PATHNAME TO EXISTING ARRAY
199void Fl_Native_File_Chooser::add_pathname(const char *s) {
200 if ( ! _pathnames ) {
201 // Create first element in array
202 ++_tpathnames;
203 _pathnames = new char*[_tpathnames];
204 } else {
205 // Grow array by 1
206 char **tmp = new char*[_tpathnames+1]; // create new buffer
207 memcpy((void*)tmp, (void*)_pathnames, sizeof(char*)*_tpathnames); // copy old
208 delete [] _pathnames; // delete old
209 _pathnames = tmp; // use new
210 ++_tpathnames;
211 }
212 _pathnames[_tpathnames-1] = strnew(s);
213}
214
215// FREE A PIDL (Pointer to IDentity List)
216void Fl_Native_File_Chooser::FreePIDL(ITEMIDLIST *pidl) {
217 IMalloc *imalloc = NULL;
218 if ( SUCCEEDED(SHGetMalloc(&imalloc)) )
219 { imalloc->Free(pidl); imalloc->Release(); imalloc = NULL; }
220}
221
222// CLEAR MICROSOFT OFN (OPEN FILE NAME) CLASS
223void Fl_Native_File_Chooser::ClearOFN() {
224 int temp;
225 // Free any previously allocated lpstrFile before zeroing out _ofn
226 if ( _ofn.lpstrFile )
227 { _ofn.lpstrFile = strfree((char*)_ofn.lpstrFile); }
228 if ( _ofn.lpstrInitialDir )
229 { _ofn.lpstrInitialDir = (LPCSTR)strfree((char*)_ofn.lpstrInitialDir); }
230 if ( _ofn.lpstrFile )
231 { _ofn.lpstrFile = strfree(_ofn.lpstrFile); }
232 _ofn.lpstrFilter = NULL; // (deleted elsewhere)
233 temp = _ofn.nFilterIndex; // keep the filter_value
234 memset((void*)&_ofn, 0, sizeof(_ofn));
235 _ofn.lStructSize = sizeof(OPENFILENAME);
236 _ofn.nFilterIndex = temp;
237}
238
239// CLEAR MICROSOFT BINF (BROWSER INFO) CLASS
240void Fl_Native_File_Chooser::ClearBINF() {
241 if ( _binf.pidlRoot ) {
242 FreePIDL((ITEMIDLIST*)_binf.pidlRoot);
243 _binf.pidlRoot = NULL;
244 }
245 memset((void*)&_binf, 0, sizeof(_binf));
246}
247
248// CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES
249void Fl_Native_File_Chooser::Win2Unix(char *s) {
250 for ( ; *s; s++ )
251 if ( *s == '\\' ) *s = '/';
252}
253
254// CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES
255void Fl_Native_File_Chooser::Unix2Win(char *s) {
256 for ( ; *s; s++ )
257 if ( *s == '/' ) *s = '\\';
258}
259
260// SHOW FILE BROWSER
261int Fl_Native_File_Chooser::showfile() {
262 ClearOFN();
263 clear_pathnames();
264 size_t fsize = 2048;
265 _ofn.Flags |= OFN_NOVALIDATE; // prevent disabling of front slashes
266 _ofn.Flags |= OFN_HIDEREADONLY; // hide goofy readonly flag
267 // USE NEW BROWSER
268 _ofn.Flags |= OFN_EXPLORER; // use newer explorer windows
269// // USE OLD BROWSER
270// _ofn.lpfnHook = MyHook;
271// _ofn.Flags |= OFN_ENABLEHOOK;
272 _ofn.Flags |= OFN_ENABLESIZING; // allow window to be resized (hey, why not?)
273
274 switch ( _btype ) {
275 case BROWSE_DIRECTORY:
276 case BROWSE_MULTI_DIRECTORY:
277 case BROWSE_SAVE_DIRECTORY:
278 abort(); // never happens: handled by showdir()
279 case BROWSE_FILE:
280 fsize = 65536; // XXX: there must be a better way
281 break;
282 case BROWSE_MULTI_FILE:
283 _ofn.Flags |= OFN_ALLOWMULTISELECT;
284 fsize = 65536; // XXX: there must be a better way
285 break;
286 case BROWSE_SAVE_FILE:
287 if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) {
288 _ofn.Flags |= OFN_OVERWRITEPROMPT;
289 }
290 break;
291 }
292 // SPACE FOR RETURNED FILENAME
293 _ofn.lpstrFile = new char[fsize];
294 _ofn.nMaxFile = fsize-1;
295 _ofn.lpstrFile[0] = '\0';
296 _ofn.lpstrFile[1] = '\0';
297 // PARENT WINDOW
298 _ofn.hwndOwner = GetForegroundWindow();
299 // DIALOG TITLE
300 _ofn.lpstrTitle = _title ? _title : NULL;
301 // FILTER
302 _ofn.lpstrFilter = _parsedfilt ? _parsedfilt : NULL;
303 // PRESET FILE
304 // If set, supercedes _directory. See KB Q86920 for details
305 //
306 if ( _preset_file ) {
307 int len = strlen(_preset_file);
308 char *strfile = new char[MAX_PATH]; // as per KB 222003 >8(
309 strcpy(strfile, _preset_file);
310 strfile[len+0] = '\0'; // (multiselect needs dnull)
311 strfile[len+1] = '\0';
312 Unix2Win(strfile);
313 _ofn.lpstrFile = strfile;
314 _ofn.nMaxFile = MAX_PATH; // as per KB 222003 >8(
315 }
316 if ( _directory ) {
317 // PRESET DIR
318 // XXX: See KB Q86920 for doc bug:
319 // http://support.microsoft.com/default.aspx?scid=kb;en-us;86920
320 //
321 if ( _directory ) {
322 _ofn.lpstrInitialDir = strnew(_directory);
323 Unix2Win((char*)_ofn.lpstrInitialDir);
324 }
325 }
326 // OPEN THE DIALOG WINDOW
327 int err;
328 if ( _btype == BROWSE_SAVE_FILE ) {
329 err = GetSaveFileName(&_ofn);
330 } else {
331 err = GetOpenFileName(&_ofn);
332 }
333 if ( err == 0 ) {
334 // EXTENDED ERROR CHECK
335 int err = CommDlgExtendedError();
336 // CANCEL?
337 if ( err == 0 )
338 return(1); // user hit 'cancel'
339 // AN ERROR OCCURRED
340 char msg[80];
341 sprintf(msg, "CommDlgExtendedError() code=%d", err);
342 errmsg(msg);
343 return(-1);
344 }
345 // PREPARE PATHNAMES FOR RETURN
346 switch ( _btype ) {
347 case BROWSE_FILE:
348 case BROWSE_SAVE_FILE:
349 set_single_pathname(_ofn.lpstrFile);
350 Win2Unix(_pathnames[_tpathnames-1]);
351 break;
352 case BROWSE_MULTI_FILE: {
353 // EXTRACT MULTIPLE FILENAMES
354 const char *dirname = _ofn.lpstrFile;
355 int dirlen = strlen(dirname);
356 if ( dirlen > 0 ) {
357 char pathname[2048];
358
359 // WALK STRING SEARCHING FOR 'DOUBLE-NULL'
360 // eg. "/dir/name\0foo1\0foo2\0foo3\0\0"
361 //
362 for ( const char *s = _ofn.lpstrFile + dirlen + 1;
363 *s; s+= (strlen(s)+1)) {
364 strcpy(pathname, dirname);
365 strcat(pathname, "\\");
366 strcat(pathname, s);
367 add_pathname(pathname);
368 Win2Unix(_pathnames[_tpathnames-1]);
369 }
370 }
371 // XXX
372 // Work around problem where pasted forward-slash pathname
373 // into the file browser causes new "Explorer" interface
374 // not to grok forward slashes, passing back as a 'filename'..!
375 //
376 if ( _tpathnames == 0 ) {
377 add_pathname(dirname);
378 Win2Unix(_pathnames[_tpathnames-1]);
379 }
380 break;
381 }
382 case BROWSE_DIRECTORY:
383 case BROWSE_MULTI_DIRECTORY:
384 case BROWSE_SAVE_DIRECTORY:
385 abort(); // not here
386 }
387 return(0);
388}
389
390// Used by SHBrowseForFolder(), sets initial selected dir.
391// Ref: Usenet: microsoft.public.vc.mfc, Dec 8 2000, 1:38p David Lowndes
392// Subject: How to specify to select an initial folder .."
393//
394int CALLBACK Fl_Native_File_Chooser::Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data) {
395 switch (msg) {
396 case BFFM_INITIALIZED:
397 if (data) ::SendMessage(win, BFFM_SETSELECTION, TRUE, data);
398 break;
399 case BFFM_SELCHANGED:
400 TCHAR path[MAX_PATH];
401 if ( SHGetPathFromIDList((ITEMIDLIST*)param, path) ) {
402 ::SendMessage(win, BFFM_ENABLEOK, 0, 1);
403 } else {
404 //disable ok button if not a path
405 ::SendMessage(win, BFFM_ENABLEOK, 0, 0);
406 }
407 break;
408 case BFFM_VALIDATEFAILED:
409 // we could pop up an annoying message here.
410 // also needs set ulFlags |= BIF_VALIDATE
411 break;
412 default:
413 break;
414 }
415 return(0);
416}
417
418// SHOW DIRECTORY BROWSER
419int Fl_Native_File_Chooser::showdir() {
420 OleInitialize(NULL); // init needed by BIF_USENEWUI
421 ClearBINF();
422 clear_pathnames();
423 // PARENT WINDOW
424 _binf.hwndOwner = GetForegroundWindow();
425 // DIALOG TITLE
426 _binf.lpszTitle = _title ? _title : NULL;
427 // FLAGS
428 _binf.ulFlags =0; // initialize
429
430 // TBD: make sure matches to runtime system, if need be.
431 //( what if _WIN32_IE doesn't match system? does the program not run? )
432 // TBD: match all 3 types of directories
433
434#if defined(BIF_NONEWFOLDERBUTTON) // Version 6.0
435 if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags &= !BIF_NONEWFOLDERBUTTON;
436 _binf.ulFlags |= BIF_USENEWUI | BIF_SHAREABLE | BIF_RETURNONLYFSDIRS;
437#elif defined(BIF_USENEWUI) // Version 5.0
438 if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_EDITBOX;
439 else if ( _btype == BROWSE_SAVE_DIRECTORY ) _binf.ulFlags |= BIF_USENEWUI;
440 _binf.ulFlags |= BIF_SHAREABLE | BIF_RETURNONLYFSDIRS;
441#elif defined(BIF_EDITBOX) // Version 4.71
442 _binf.ulFlags |= BIF_RETURNONLYFSDIRS | BIF_EDITBOX;
443#else // Version Old
444 _binf.ulFlags |= BIF_RETURNONLYFSDIRS;
445#endif
446
447
448 // BUFFER
449 char displayname[MAX_PATH];
450 _binf.pszDisplayName = displayname;
451 // PRESET DIR
452 char presetname[MAX_PATH];
453 if ( _directory ) {
454 strcpy(presetname, _directory);
455 Unix2Win(presetname);
456 _binf.lParam = (LPARAM)presetname;
457 }
458 else _binf.lParam = 0;
459 _binf.lpfn = Dir_CB;
460 // OPEN BROWSER
461 ITEMIDLIST *pidl = SHBrowseForFolder(&_binf);
462 // CANCEL?
463 if ( pidl == NULL ) return(1);
464
465 // GET THE PATHNAME(S) THE USER SELECTED
466 // TBD: expand NetHood shortcuts from this PIDL??
467 // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shbrowseforfolder.asp
468
469 TCHAR path[MAX_PATH];
470 if ( SHGetPathFromIDList(pidl, path) )
471 { Win2Unix(path); add_pathname(path); }
472 FreePIDL(pidl);
473 if ( !strlen(path) ) return(1); // don't return empty pathnames
474 return(0);
475}
476
477// RETURNS:
478// 0 - user picked a file
479// 1 - user cancelled
480// -1 - failed; errmsg() has reason
481//
482int Fl_Native_File_Chooser::show() {
483 if ( _btype == BROWSE_DIRECTORY ||
484 _btype == BROWSE_MULTI_DIRECTORY ||
485 _btype == BROWSE_SAVE_DIRECTORY )
486 return(showdir());
487 else
488 return(showfile());
489}
490
491// RETURN ERROR MESSAGE
492const char *Fl_Native_File_Chooser::errmsg() const {
493 return(_errmsg ? _errmsg : "No error");
494}
495
496// GET FILENAME
497const char* Fl_Native_File_Chooser::filename() const {
498 if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]);
499 return("");
500}
501
502// GET FILENAME FROM LIST OF FILENAMES
503const char* Fl_Native_File_Chooser::filename(int i) const {
504 if ( _pathnames && i < _tpathnames ) return(_pathnames[i]);
505 return("");
506}
507
508// GET TOTAL FILENAMES CHOSEN
509int Fl_Native_File_Chooser::count() const {
510 return(_tpathnames);
511}
512
513// PRESET PATHNAME
514// Can be NULL if no preset is desired.
515//
516void Fl_Native_File_Chooser::directory(const char *val) {
517 _directory = strfree(_directory);
518 _directory = strnew(val);
519}
520
521// GET PRESET PATHNAME
522// Can return NULL if none set.
523//
524const char *Fl_Native_File_Chooser::directory() const {
525 return(_directory);
526}
527
528// SET TITLE
529// Can be NULL if no title desired.
530//
531void Fl_Native_File_Chooser::title(const char *val) {
532 _title = strfree(_title);
533 _title = strnew(val);
534}
535
536// GET TITLE
537// Can return NULL if none set.
538//
539const char *Fl_Native_File_Chooser::title() const {
540 return(_title);
541}
542
543// SET FILTER
544// Can be NULL if no filter needed
545//
546void Fl_Native_File_Chooser::filter(const char *val) {
547 _filter = strfree(_filter);
548 clear_filters();
549 if ( val ) {
550 _filter = strnew(val);
551 parse_filter(_filter);
552 }
553 add_filter("All Files", "*.*"); // always include 'all files' option
554
555#ifdef DEBUG
556 nullprint(_parsedfilt);
557#endif /*DEBUG*/
558}
559
560// GET FILTER
561// Can return NULL if none set.
562//
563const char *Fl_Native_File_Chooser::filter() const {
564 return(_filter);
565}
566
567// CLEAR FILTERS
568void Fl_Native_File_Chooser::clear_filters() {
569 _nfilters = 0;
570 _parsedfilt = strfree(_parsedfilt);
571}
572
573// ADD A FILTER
574void Fl_Native_File_Chooser::add_filter(
575 const char *name_in, // name of filter (optional: can be null)
576 const char *winfilter // windows style filter (eg. "*.cxx;*.h")
577 ) {
578 // No name? Make one..
579 char name[1024];
580 if ( !name_in || name_in[0] == '\0' ) {
581 sprintf(name, "%.*s Files", sizeof(name)-10, winfilter);
582 } else {
583 sprintf(name, "%.*s", sizeof(name)-10, name_in);
584 }
585 dnullcat(_parsedfilt, name);
586 dnullcat(_parsedfilt, winfilter);
587 //DEBUG printf("DEBUG: ADD FILTER name=<%s> winfilter=<%s>\n", name, winfilter);
588}
589
590// CONVERT FLTK STYLE PATTERN MATCHES TO WINDOWS 'DOUBLENULL' PATTERN
591// Handles:
592// IN OUT
593// ----------- -----------------------------
594// *.{ma,mb} "*.{ma,mb} Files\0*.ma;*.mb\0\0"
595// *.[abc] "*.[abc] Files\0*.a;*.b;*.c\0\0"
596// *.txt "*.txt Files\0*.txt\0\0"
597// C Files\t*.[ch] "C Files\0*.c;*.h\0\0"
598//
599// Example:
600// IN: "*.{ma,mb}"
601// OUT: "*.ma;*.mb Files\0*.ma;*.mb\0All Files\0*.*\0\0"
602// --------------- --------- --------- ---
603// | | | |
604// Title Wildcards Title Wildcards
605//
606// Parsing Mode:
607// IN:"C Files\t*.{cxx,h}"
608// ||||||| |||||||||
609// mode: nnnnnnn ww{{{{{{{
610// \_____/ \_______/
611// Name Wildcard
612//
613void Fl_Native_File_Chooser::parse_filter(const char *in) {
614 clear_filters();
615 if ( ! in ) return;
616
617 int has_name = strchr(in, '\t') ? 1 : 0;
618 //const char *savein = in;
619
620 char mode = has_name ? 'n' : 'w'; // parse mode: n=name, w=wildcard
621 int nwildcards = 0;
622 char wildcards[MAXFILTERS][1024]; // parsed wildcards (can be several)
623 char wildprefix[512] = "";
624 char name[512] = "";
625
626 // Init
627 int t;
628 for ( t=0; t<MAXFILTERS; t++ ) {
629 wildcards[t][0] = '\0';
630 }
631
632 // Parse
633 for ( ; 1; in++ ) {
634
635 //// DEBUG
636 //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildprefix=<%s> nwildcards=%d wildcards[n]=<%s>\n",
637 //// *in, mode, name, wildprefix, nwildcards, wildcards[nwildcards]);
638
639 switch (*in) {
640 case ',':
641 case '|':
642 if ( mode == LCURLY_CHR ) {
643 // create new wildcard, copy in prefix
644 strcat(wildcards[nwildcards++], wildprefix);
645 continue;
646 } else {
647 goto regchar;
648 }
649 continue;
650
651 // FINISHED PARSING A NAME?
652 case '\t':
653 if ( mode != 'n' ) goto regchar;
654 // finish parsing name? switch to wildcard mode
655 mode = 'w';
656 break;
657
658 // ESCAPE NEXT CHAR
659 case '\\':
660 ++in;
661 goto regchar;
662
663 // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS?
664 case '\r':
665 case '\n':
666 case '\0':
667 {
668 if ( mode == 'w' ) { // finished parsing wildcard?
669 if ( nwildcards == 0 ) {
670 strcpy(wildcards[nwildcards++], wildprefix);
671 }
672 // Append wildcards in Microsoft's "*.one;*.two" format
673 char comp[4096] = "";
674 for ( t=0; t<nwildcards; t++ ) {
675 if ( t != 0 ) strcat(comp, ";");
676 strcat(comp, wildcards[t]);
677 }
678 // Add if not empty
679 if ( comp[0] ) {
680 add_filter(name, comp);
681 }
682 }
683 // RESET
684 for ( t=0; t<MAXFILTERS; t++ ) {
685 wildcards[t][0] = '\0';
686 }
687 nwildcards = 0;
688 wildprefix[0] = name[0] = '\0';
689 mode = strchr(in,'\t') ? 'n' : 'w';
690 // DONE?
691 if ( *in == '\0' ) return; // done
692 continue; // not done yet, more filters
693 }
694
695 // STARTING A WILDCARD?
696 case LBRACKET_CHR:
697 case LCURLY_CHR:
698 mode = *in;
699 if ( *in == LCURLY_CHR ) {
700 // create new wildcard
701 strcat(wildcards[nwildcards++], wildprefix);
702 }
703 continue;
704
705 // ENDING A WILDCARD?
706 case RBRACKET_CHR:
707 case RCURLY_CHR:
708 mode = 'w'; // back to wildcard mode
709 continue;
710
711 // ALL OTHER NON-SPECIAL CHARACTERS
712 default:
713 regchar: // handle regular char
714 switch ( mode ) {
715 case LBRACKET_CHR:
716 // create new wildcard
717 ++nwildcards;
718 // copy in prefix
719 strcpy(wildcards[nwildcards-1], wildprefix);
720 // append search char
721 chrcat(wildcards[nwildcards-1], *in);
722 continue;
723
724 case LCURLY_CHR:
725 if ( nwildcards > 0 ) {
726 chrcat(wildcards[nwildcards-1], *in);
727 }
728 continue;
729
730 case 'n':
731 chrcat(name, *in);
732 continue;
733
734 case 'w':
735 chrcat(wildprefix, *in);
736 for ( t=0; t<nwildcards; t++ ) {
737 chrcat(wildcards[t], *in);
738 }
739 continue;
740 }
741 break;
742 }
743 }
744}
745
746// SET 'CURRENTLY SELECTED FILTER'
747void Fl_Native_File_Chooser::filter_value(int i) {
748 _ofn.nFilterIndex = i + 1;
749}
750
751// RETURN VALUE OF 'CURRENTLY SELECTED FILTER'
752int Fl_Native_File_Chooser::filter_value() const {
753 return(_ofn.nFilterIndex ? _ofn.nFilterIndex-1 : _nfilters+1);
754}
755
756// PRESET FILENAME FOR 'SAVE AS' CHOOSER
757void Fl_Native_File_Chooser::preset_file(const char* val) {
758 _preset_file = strfree(_preset_file);
759 _preset_file = strnew(val);
760}
761
762// GET PRESET FILENAME FOR 'SAVE AS' CHOOSER
763const char* Fl_Native_File_Chooser::preset_file() const {
764 return(_preset_file);
765}