From 79d185c0687cb4844ce51417a9a18a09492ad27f Mon Sep 17 00:00:00 2001 From: Manolo Gouy Date: Wed, 15 Dec 2010 20:06:56 +0000 Subject: Renamed Fl_Native_File_Chooser_MAC.cxx to Fl_Native_File_Chooser_MAC.mm because this is an objective-c++ file. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@8041 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- src/Fl_Native_File_Chooser.cxx | 2 +- src/Fl_Native_File_Chooser_MAC.cxx | 584 ------------------------------------- src/Fl_Native_File_Chooser_MAC.mm | 584 +++++++++++++++++++++++++++++++++++++ 3 files changed, 585 insertions(+), 585 deletions(-) delete mode 100644 src/Fl_Native_File_Chooser_MAC.cxx create mode 100644 src/Fl_Native_File_Chooser_MAC.mm (limited to 'src') diff --git a/src/Fl_Native_File_Chooser.cxx b/src/Fl_Native_File_Chooser.cxx index 7e5b383b1..2941c9b62 100644 --- a/src/Fl_Native_File_Chooser.cxx +++ b/src/Fl_Native_File_Chooser.cxx @@ -32,7 +32,7 @@ // Use Apple's chooser #ifdef __APPLE__ -#include "Fl_Native_File_Chooser_MAC.cxx" +#include "Fl_Native_File_Chooser_MAC.mm" #endif // All else falls back to FLTK's own chooser diff --git a/src/Fl_Native_File_Chooser_MAC.cxx b/src/Fl_Native_File_Chooser_MAC.cxx deleted file mode 100644 index f3b8d6f2b..000000000 --- a/src/Fl_Native_File_Chooser_MAC.cxx +++ /dev/null @@ -1,584 +0,0 @@ -// "$Id$" -// -// FLTK native OS file chooser widget -// -// Copyright 1998-2010 by Bill Spitzak and others. -// Copyright 2004 Greg Ercolano. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Library General Public -// License as published by the Free Software Foundation; either -// version 2 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Library General Public License for more details. -// -// You should have received a copy of the GNU Library General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -// USA. -// -// Please report all bugs and problems to: -// -// http://www.fltk.org/str.php -// - -// TODO: -// o When doing 'open file', only dir is preset, not filename. -// Possibly 'preset_file' could be used to select the filename. -// - -#ifndef FL_DOXYGEN // PREVENT DOXYGEN'S USE OF THIS FILE - -#include "Fl_Native_File_Chooser_common.cxx" // strnew/strfree/strapp/chrcat -#include // dirname(3) -#include // stat(2) -#include // stat(2) - - -#include -#include -#include - -// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS -void Fl_Native_File_Chooser::clear_pathnames() { - if ( _pathnames ) { - while ( --_tpathnames >= 0 ) { - _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]); - } - delete [] _pathnames; - _pathnames = NULL; - } - _tpathnames = 0; -} - -// SET A SINGLE PATHNAME -void Fl_Native_File_Chooser::set_single_pathname(const char *s) { - clear_pathnames(); - _pathnames = new char*[1]; - _pathnames[0] = strnew(s); - _tpathnames = 1; -} - -// CONSTRUCTOR -Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { - _btype = val; - _panel = NULL; - _options = NO_OPTIONS; - _pathnames = NULL; - _tpathnames = 0; - _title = NULL; - _filter = NULL; - _filt_names = NULL; - memset(_filt_patt, 0, sizeof(char*) * MAXFILTERS); - _filt_total = 0; - _filt_value = 0; - _directory = NULL; - _preset_file = NULL; - _errmsg = NULL; -} - -// DESTRUCTOR -Fl_Native_File_Chooser::~Fl_Native_File_Chooser() { - // _opts // nothing to manage - // _options // nothing to manage - // _keepstate // nothing to manage - // _tempitem // nothing to manage - clear_pathnames(); - _directory = strfree(_directory); - _title = strfree(_title); - _preset_file = strfree(_preset_file); - _filter = strfree(_filter); - //_filt_names // managed by clear_filters() - //_filt_patt[i] // managed by clear_filters() - //_filt_total // managed by clear_filters() - clear_filters(); - //_filt_value // nothing to manage - _errmsg = strfree(_errmsg); -} - -// GET TYPE OF BROWSER -int Fl_Native_File_Chooser::type() const { - return(_btype); -} - -// SET OPTIONS -void Fl_Native_File_Chooser::options(int val) { - _options = val; -} - -// GET OPTIONS -int Fl_Native_File_Chooser::options() const { - return(_options); -} - -// SHOW THE BROWSER WINDOW -// Returns: -// 0 - user picked a file -// 1 - user cancelled -// -1 - failed; errmsg() has reason -// -int Fl_Native_File_Chooser::show() { - - // Make sure fltk interface updates before posting our dialog - Fl::flush(); - - // POST BROWSER - int err = post(); - - _filt_total = 0; - - return(err); -} - -// SET ERROR MESSAGE -// Internal use only. -// -void Fl_Native_File_Chooser::errmsg(const char *msg) { - _errmsg = strfree(_errmsg); - _errmsg = strnew(msg); -} - -// RETURN ERROR MESSAGE -const char *Fl_Native_File_Chooser::errmsg() const { - return(_errmsg ? _errmsg : "No error"); -} - -// GET FILENAME -const char* Fl_Native_File_Chooser::filename() const { - if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]); - return(""); -} - -// GET FILENAME FROM LIST OF FILENAMES -const char* Fl_Native_File_Chooser::filename(int i) const { - if ( _pathnames && i < _tpathnames ) return(_pathnames[i]); - return(""); -} - -// GET TOTAL FILENAMES CHOSEN -int Fl_Native_File_Chooser::count() const { - return(_tpathnames); -} - -// PRESET PATHNAME -// Value can be NULL for none. -// -void Fl_Native_File_Chooser::directory(const char *val) { - _directory = strfree(_directory); - _directory = strnew(val); -} - -// GET PRESET PATHNAME -// Returned value can be NULL if none set. -// -const char* Fl_Native_File_Chooser::directory() const { - return(_directory); -} - -// SET TITLE -// Value can be NULL if no title desired. -// -void Fl_Native_File_Chooser::title(const char *val) { - _title = strfree(_title); - _title = strnew(val); -} - -// GET TITLE -// Returned value can be NULL if none set. -// -const char *Fl_Native_File_Chooser::title() const { - return(_title); -} - -// SET FILTER -// Can be NULL if no filter needed -// -void Fl_Native_File_Chooser::filter(const char *val) { - _filter = strfree(_filter); - _filter = strnew(val); - - // Parse filter user specified - // IN: _filter = "C Files\t*.{cxx,h}\nText Files\t*.txt" - // OUT: _filt_names = "C Files\tText Files" - // _filt_patt[0] = "*.{cxx,h}" - // _filt_patt[1] = "*.txt" - // _filt_total = 2 - // - parse_filter(_filter); -} - -// GET FILTER -// Returned value can be NULL if none set. -// -const char *Fl_Native_File_Chooser::filter() const { - return(_filter); -} - -// CLEAR ALL FILTERS -// Internal use only. -// -void Fl_Native_File_Chooser::clear_filters() { - _filt_names = strfree(_filt_names); - for (int i=0; i<_filt_total; i++) { - _filt_patt[i] = strfree(_filt_patt[i]); - } - _filt_total = 0; -} - -// PARSE USER'S FILTER SPEC -// Parses user specified filter ('in'), -// breaks out into _filt_patt[], _filt_names, and _filt_total. -// -// Handles: -// IN: OUT:_filt_names OUT: _filt_patt -// ------------------------------------ ------------------ --------------- -// "*.{ma,mb}" "*.{ma,mb} Files" "*.{ma,mb}" -// "*.[abc]" "*.[abc] Files" "*.[abc]" -// "*.txt" "*.txt Files" "*.c" -// "C Files\t*.[ch]" "C Files" "*.[ch]" -// "C Files\t*.[ch]\nText Files\t*.cxx" "C Files" "*.[ch]" -// -// Parsing Mode: -// IN:"C Files\t*.{cxx,h}" -// ||||||| ||||||||| -// mode: nnnnnnn wwwwwwwww -// \_____/ \_______/ -// Name Wildcard -// -void Fl_Native_File_Chooser::parse_filter(const char *in) { - clear_filters(); - if ( ! in ) return; - int has_name = strchr(in, '\t') ? 1 : 0; - - char mode = has_name ? 'n' : 'w'; // parse mode: n=title, w=wildcard - char wildcard[1024] = ""; // parsed wildcard - char name[1024] = ""; - - // Parse filter user specified - for ( ; 1; in++ ) { - - //// DEBUG - //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n", - //// *in, mode, name, wildcard); - - switch (*in) { - // FINISHED PARSING NAME? - case '\t': - if ( mode != 'n' ) goto regchar; - mode = 'w'; - break; - - // ESCAPE NEXT CHAR - case '\\': - ++in; - goto regchar; - - // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS? - case '\r': - case '\n': - case '\0': - // TITLE - // If user didn't specify a name, make one - // - if ( name[0] == '\0' ) { - sprintf(name, "%.*s Files", (int)sizeof(name)-10, wildcard); - } - // APPEND NEW FILTER TO LIST - if ( wildcard[0] ) { - // Add to filtername list - // Tab delimit if more than one. We later break - // tab delimited string into CFArray with - // CFStringCreateArrayBySeparatingStrings() - // - if ( _filt_total ) { - _filt_names = strapp(_filt_names, "\t"); - } - _filt_names = strapp(_filt_names, name); - - // Add filter to the pattern array - _filt_patt[_filt_total++] = strnew(wildcard); - } - // RESET - wildcard[0] = name[0] = '\0'; - mode = strchr(in, '\t') ? 'n' : 'w'; - // DONE? - if ( *in == '\0' ) return; // done - else continue; // not done yet, more filters - - // Parse all other chars - default: // handle all non-special chars - regchar: // handle regular char - switch ( mode ) { - case 'n': chrcat(name, *in); continue; - case 'w': chrcat(wildcard, *in); continue; - } - break; - } - } - //NOTREACHED -} - -// SET PRESET FILE -// Value can be NULL for none. -// -void Fl_Native_File_Chooser::preset_file(const char* val) { - _preset_file = strfree(_preset_file); - _preset_file = strnew(val); -} - -// PRESET FILE -// Returned value can be NULL if none set. -// -const char* Fl_Native_File_Chooser::preset_file() { - return(_preset_file); -} - -#import -#define UNLIKELYPREFIX "___fl_very_unlikely_prefix_" -#ifndef MAC_OS_X_VERSION_10_6 -#define MAC_OS_X_VERSION_10_6 1060 -#endif - -int Fl_Native_File_Chooser::get_saveas_basename(void) { - char *q = strdup( [[(NSSavePanel*)_panel filename] fileSystemRepresentation] ); - id delegate = [(NSSavePanel*)_panel delegate]; - if (delegate != nil) { - const char *d = [[(NSSavePanel*)_panel directory] fileSystemRepresentation]; - int l = strlen(d) + 1; - int lu = strlen(UNLIKELYPREFIX); - // Remove UNLIKELYPREFIX between directory and filename parts - memmove(q + l, q + l + lu, strlen(q + l + lu) + 1); - } - set_single_pathname( q ); - free(q); - return 0; -} - -// SET THE TYPE OF BROWSER -void Fl_Native_File_Chooser::type(int val) { - _btype = val; - switch (_btype) { - case BROWSE_FILE: - case BROWSE_MULTI_FILE: - case BROWSE_DIRECTORY: - case BROWSE_MULTI_DIRECTORY: - _panel = [NSOpenPanel openPanel]; - break; - case BROWSE_SAVE_DIRECTORY: - case BROWSE_SAVE_FILE: - _panel = [NSSavePanel savePanel]; - break; - } -} - -@interface FLopenDelegate : NSObject -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - -#endif -{ - NSPopUpButton *nspopup; - char **filter_pattern; -} -- (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern; -- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename; -@end -@implementation FLopenDelegate -- (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern -{ - nspopup = popup; - filter_pattern = pattern; - return self; -} -- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename -{ - if ( [nspopup indexOfSelectedItem] == [nspopup numberOfItems] - 1) return YES; - const char *pathname = [filename fileSystemRepresentation]; - if ( fl_filename_isdir(pathname) ) return YES; - if ( fl_filename_match(pathname, filter_pattern[ [nspopup indexOfSelectedItem] ]) ) return YES; - return NO; -} -@end - -@interface FLsaveDelegate : NSObject -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 - -#endif -{ -} -- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag; -@end -@implementation FLsaveDelegate -- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag -{ - if (! okFlag) return filename; - // User has clicked save, and no overwrite confirmation should occur. - // To get the latter, we need to change the name we return (hence the prefix): - return [@ UNLIKELYPREFIX stringByAppendingString:filename]; -} -@end - -static NSPopUpButton *createPopupAccessory(NSSavePanel *panel, const char *filter, const char *title, int rank) -{ - NSPopUpButton *popup; - NSRect rectview = NSMakeRect(5, 5, 350, 30 ); - NSView *view = [[[NSView alloc] initWithFrame:rectview] autorelease]; - NSRect rectbox = NSMakeRect(0, 3, 50, 1 ); - NSBox *box = [[[NSBox alloc] initWithFrame:rectbox] autorelease]; - NSRect rectpop = NSMakeRect(60, 0, 250, 30 ); - popup = [[[NSPopUpButton alloc ] initWithFrame:rectpop pullsDown:NO] autorelease]; - [view addSubview:box]; - [view addSubview:popup]; - [box setBorderType:NSNoBorder]; - NSString *nstitle = [[NSString alloc] initWithUTF8String:title]; - [box setTitle:nstitle]; - [nstitle release]; - NSFont *font = [NSFont controlContentFontOfSize:NSRegularControlSize]; - [box setTitleFont:font]; - [box sizeToFit]; - CFStringRef tab = CFSTR("\n"); - CFStringRef tmp_cfs; - tmp_cfs = CFStringCreateWithCString(NULL, filter, kCFStringEncodingASCII); - CFArrayRef array = CFStringCreateArrayBySeparatingStrings(NULL, tmp_cfs, tab); - CFRelease(tmp_cfs); - CFRelease(tab); - [popup addItemsWithTitles:(NSArray*)array]; - NSMenuItem *item = [popup itemWithTitle:@""]; - if (item) [popup removeItemWithTitle:@""]; - CFRelease(array); - [popup selectItemAtIndex:rank]; - [panel setAccessoryView:view]; - return popup; -} - -// POST BROWSER -// Internal use only. -// Assumes '_opts' has been initialized. -// -// Returns: -// 0 - user picked a file -// 1 - user cancelled -// -1 - failed; errmsg() has reason -// -int Fl_Native_File_Chooser::post() { - // INITIALIZE BROWSER - if ( _filt_total == 0 ) { // Make sure they match - _filt_value = 0; // TBD: move to someplace more logical? - } - NSAutoreleasePool *localPool; - localPool = [[NSAutoreleasePool alloc] init]; - int retval; - NSString *nstitle = [NSString stringWithUTF8String: (_title ? _title : "No Title")]; - [(NSSavePanel*)_panel setTitle:nstitle]; - switch (_btype) { - case BROWSE_MULTI_FILE: - [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES]; - break; - case BROWSE_MULTI_DIRECTORY: - [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES]; - case BROWSE_DIRECTORY: - [(NSOpenPanel*)_panel setCanChooseDirectories:YES]; - break; - case BROWSE_SAVE_DIRECTORY: - [(NSSavePanel*)_panel setCanCreateDirectories:YES]; - break; - } - - // SHOW THE DIALOG - if ( [(NSSavePanel*)_panel isKindOfClass:[NSOpenPanel class]] ) { - NSPopUpButton *popup = nil; - if (_filt_total) { - char *p; p = _filter; - char *q; q = new char[strlen(p) + 1]; - char *r, *s, *t; - t = q; - do { // copy to t what is in _filter removing what is between \t and \n, if any - r = strchr(p, '\n'); - if (!r) r = p + strlen(p) - 1; - s = strchr(p, '\t'); - if (s && s < r) { memcpy(q, p, s - p); q += s - p; *(q++) = '\n'; } - else { memcpy(q, p, r - p + 1); q += r - p + 1; } - *q = 0; - p = r + 1; - } while(*p); - popup = createPopupAccessory((NSSavePanel*)_panel, t, "Enable:", 0); - delete t; - [[popup menu] addItem:[NSMenuItem separatorItem]]; - [popup addItemWithTitle:@"All Documents"]; - [popup setAction:@selector(validateVisibleColumns)]; - [popup setTarget:(NSObject*)_panel]; - static FLopenDelegate *openDelegate = nil; - if (openDelegate == nil) { - // not to be ever freed - openDelegate = [[FLopenDelegate alloc] init]; - } - [openDelegate setPopup:popup filter_pattern:_filt_patt]; - [(NSOpenPanel*)_panel setDelegate:openDelegate]; - } - NSString *dir = nil; - NSString *fname = nil; - NSString *preset = nil; - if (_preset_file) { - preset = [[NSString alloc] initWithUTF8String:_preset_file]; - if (strchr(_preset_file, '/') != NULL) - dir = [[NSString alloc] initWithString:[preset stringByDeletingLastPathComponent]]; - fname = [preset lastPathComponent]; - } - if (_directory && !dir) dir = [[NSString alloc] initWithUTF8String:_directory]; - retval = [(NSOpenPanel*)_panel runModalForDirectory:dir file:fname types:nil]; - [dir release]; - [preset release]; - if (_filt_total) { - _filt_value = [popup indexOfSelectedItem]; - } - if ( retval == NSOKButton ) { - clear_pathnames(); - NSArray *array = [(NSOpenPanel*)_panel filenames]; - _tpathnames = [array count]; - _pathnames = new char*[_tpathnames]; - for(int i = 0; i < _tpathnames; i++) { - _pathnames[i] = strnew([(NSString*)[array objectAtIndex:i] fileSystemRepresentation]); - } - } - } - else { - NSString *dir = nil; - NSString *fname = nil; - NSString *preset = nil; - NSPopUpButton *popup = nil; - [(NSSavePanel*)_panel setAllowsOtherFileTypes:YES]; - if ( !(_options & SAVEAS_CONFIRM) ) { - static FLsaveDelegate *saveDelegate = nil; - if (saveDelegate == nil)saveDelegate = [[FLsaveDelegate alloc] init]; // not to be ever freed - [(NSSavePanel*)_panel setDelegate:saveDelegate]; - } - if (_preset_file) { - preset = [[NSString alloc] initWithUTF8String:_preset_file]; - if (strchr(_preset_file, '/') != NULL) { - dir = [[NSString alloc] initWithString:[preset stringByDeletingLastPathComponent]]; - } - fname = [preset lastPathComponent]; - } - if (_directory && !dir) dir = [[NSString alloc] initWithUTF8String:_directory]; - if (_filt_total) { - popup = createPopupAccessory((NSSavePanel*)_panel, _filter, "Format:", _filt_value); - } - retval = [(NSSavePanel*)_panel runModalForDirectory:dir file:fname]; - if (_filt_total) { - _filt_value = [popup indexOfSelectedItem]; - } - [dir release]; - [preset release]; - if ( retval == NSOKButton ) get_saveas_basename(); - } - [localPool release]; - return (retval == NSOKButton ? 0 : 1); -} - -#endif /*!FL_DOXYGEN*/ - -// -// End of "$Id$". -// diff --git a/src/Fl_Native_File_Chooser_MAC.mm b/src/Fl_Native_File_Chooser_MAC.mm new file mode 100644 index 000000000..f3b8d6f2b --- /dev/null +++ b/src/Fl_Native_File_Chooser_MAC.mm @@ -0,0 +1,584 @@ +// "$Id$" +// +// FLTK native OS file chooser widget +// +// Copyright 1998-2010 by Bill Spitzak and others. +// Copyright 2004 Greg Ercolano. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to: +// +// http://www.fltk.org/str.php +// + +// TODO: +// o When doing 'open file', only dir is preset, not filename. +// Possibly 'preset_file' could be used to select the filename. +// + +#ifndef FL_DOXYGEN // PREVENT DOXYGEN'S USE OF THIS FILE + +#include "Fl_Native_File_Chooser_common.cxx" // strnew/strfree/strapp/chrcat +#include // dirname(3) +#include // stat(2) +#include // stat(2) + + +#include +#include +#include + +// FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS +void Fl_Native_File_Chooser::clear_pathnames() { + if ( _pathnames ) { + while ( --_tpathnames >= 0 ) { + _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]); + } + delete [] _pathnames; + _pathnames = NULL; + } + _tpathnames = 0; +} + +// SET A SINGLE PATHNAME +void Fl_Native_File_Chooser::set_single_pathname(const char *s) { + clear_pathnames(); + _pathnames = new char*[1]; + _pathnames[0] = strnew(s); + _tpathnames = 1; +} + +// CONSTRUCTOR +Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { + _btype = val; + _panel = NULL; + _options = NO_OPTIONS; + _pathnames = NULL; + _tpathnames = 0; + _title = NULL; + _filter = NULL; + _filt_names = NULL; + memset(_filt_patt, 0, sizeof(char*) * MAXFILTERS); + _filt_total = 0; + _filt_value = 0; + _directory = NULL; + _preset_file = NULL; + _errmsg = NULL; +} + +// DESTRUCTOR +Fl_Native_File_Chooser::~Fl_Native_File_Chooser() { + // _opts // nothing to manage + // _options // nothing to manage + // _keepstate // nothing to manage + // _tempitem // nothing to manage + clear_pathnames(); + _directory = strfree(_directory); + _title = strfree(_title); + _preset_file = strfree(_preset_file); + _filter = strfree(_filter); + //_filt_names // managed by clear_filters() + //_filt_patt[i] // managed by clear_filters() + //_filt_total // managed by clear_filters() + clear_filters(); + //_filt_value // nothing to manage + _errmsg = strfree(_errmsg); +} + +// GET TYPE OF BROWSER +int Fl_Native_File_Chooser::type() const { + return(_btype); +} + +// SET OPTIONS +void Fl_Native_File_Chooser::options(int val) { + _options = val; +} + +// GET OPTIONS +int Fl_Native_File_Chooser::options() const { + return(_options); +} + +// SHOW THE BROWSER WINDOW +// Returns: +// 0 - user picked a file +// 1 - user cancelled +// -1 - failed; errmsg() has reason +// +int Fl_Native_File_Chooser::show() { + + // Make sure fltk interface updates before posting our dialog + Fl::flush(); + + // POST BROWSER + int err = post(); + + _filt_total = 0; + + return(err); +} + +// SET ERROR MESSAGE +// Internal use only. +// +void Fl_Native_File_Chooser::errmsg(const char *msg) { + _errmsg = strfree(_errmsg); + _errmsg = strnew(msg); +} + +// RETURN ERROR MESSAGE +const char *Fl_Native_File_Chooser::errmsg() const { + return(_errmsg ? _errmsg : "No error"); +} + +// GET FILENAME +const char* Fl_Native_File_Chooser::filename() const { + if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]); + return(""); +} + +// GET FILENAME FROM LIST OF FILENAMES +const char* Fl_Native_File_Chooser::filename(int i) const { + if ( _pathnames && i < _tpathnames ) return(_pathnames[i]); + return(""); +} + +// GET TOTAL FILENAMES CHOSEN +int Fl_Native_File_Chooser::count() const { + return(_tpathnames); +} + +// PRESET PATHNAME +// Value can be NULL for none. +// +void Fl_Native_File_Chooser::directory(const char *val) { + _directory = strfree(_directory); + _directory = strnew(val); +} + +// GET PRESET PATHNAME +// Returned value can be NULL if none set. +// +const char* Fl_Native_File_Chooser::directory() const { + return(_directory); +} + +// SET TITLE +// Value can be NULL if no title desired. +// +void Fl_Native_File_Chooser::title(const char *val) { + _title = strfree(_title); + _title = strnew(val); +} + +// GET TITLE +// Returned value can be NULL if none set. +// +const char *Fl_Native_File_Chooser::title() const { + return(_title); +} + +// SET FILTER +// Can be NULL if no filter needed +// +void Fl_Native_File_Chooser::filter(const char *val) { + _filter = strfree(_filter); + _filter = strnew(val); + + // Parse filter user specified + // IN: _filter = "C Files\t*.{cxx,h}\nText Files\t*.txt" + // OUT: _filt_names = "C Files\tText Files" + // _filt_patt[0] = "*.{cxx,h}" + // _filt_patt[1] = "*.txt" + // _filt_total = 2 + // + parse_filter(_filter); +} + +// GET FILTER +// Returned value can be NULL if none set. +// +const char *Fl_Native_File_Chooser::filter() const { + return(_filter); +} + +// CLEAR ALL FILTERS +// Internal use only. +// +void Fl_Native_File_Chooser::clear_filters() { + _filt_names = strfree(_filt_names); + for (int i=0; i<_filt_total; i++) { + _filt_patt[i] = strfree(_filt_patt[i]); + } + _filt_total = 0; +} + +// PARSE USER'S FILTER SPEC +// Parses user specified filter ('in'), +// breaks out into _filt_patt[], _filt_names, and _filt_total. +// +// Handles: +// IN: OUT:_filt_names OUT: _filt_patt +// ------------------------------------ ------------------ --------------- +// "*.{ma,mb}" "*.{ma,mb} Files" "*.{ma,mb}" +// "*.[abc]" "*.[abc] Files" "*.[abc]" +// "*.txt" "*.txt Files" "*.c" +// "C Files\t*.[ch]" "C Files" "*.[ch]" +// "C Files\t*.[ch]\nText Files\t*.cxx" "C Files" "*.[ch]" +// +// Parsing Mode: +// IN:"C Files\t*.{cxx,h}" +// ||||||| ||||||||| +// mode: nnnnnnn wwwwwwwww +// \_____/ \_______/ +// Name Wildcard +// +void Fl_Native_File_Chooser::parse_filter(const char *in) { + clear_filters(); + if ( ! in ) return; + int has_name = strchr(in, '\t') ? 1 : 0; + + char mode = has_name ? 'n' : 'w'; // parse mode: n=title, w=wildcard + char wildcard[1024] = ""; // parsed wildcard + char name[1024] = ""; + + // Parse filter user specified + for ( ; 1; in++ ) { + + //// DEBUG + //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n", + //// *in, mode, name, wildcard); + + switch (*in) { + // FINISHED PARSING NAME? + case '\t': + if ( mode != 'n' ) goto regchar; + mode = 'w'; + break; + + // ESCAPE NEXT CHAR + case '\\': + ++in; + goto regchar; + + // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS? + case '\r': + case '\n': + case '\0': + // TITLE + // If user didn't specify a name, make one + // + if ( name[0] == '\0' ) { + sprintf(name, "%.*s Files", (int)sizeof(name)-10, wildcard); + } + // APPEND NEW FILTER TO LIST + if ( wildcard[0] ) { + // Add to filtername list + // Tab delimit if more than one. We later break + // tab delimited string into CFArray with + // CFStringCreateArrayBySeparatingStrings() + // + if ( _filt_total ) { + _filt_names = strapp(_filt_names, "\t"); + } + _filt_names = strapp(_filt_names, name); + + // Add filter to the pattern array + _filt_patt[_filt_total++] = strnew(wildcard); + } + // RESET + wildcard[0] = name[0] = '\0'; + mode = strchr(in, '\t') ? 'n' : 'w'; + // DONE? + if ( *in == '\0' ) return; // done + else continue; // not done yet, more filters + + // Parse all other chars + default: // handle all non-special chars + regchar: // handle regular char + switch ( mode ) { + case 'n': chrcat(name, *in); continue; + case 'w': chrcat(wildcard, *in); continue; + } + break; + } + } + //NOTREACHED +} + +// SET PRESET FILE +// Value can be NULL for none. +// +void Fl_Native_File_Chooser::preset_file(const char* val) { + _preset_file = strfree(_preset_file); + _preset_file = strnew(val); +} + +// PRESET FILE +// Returned value can be NULL if none set. +// +const char* Fl_Native_File_Chooser::preset_file() { + return(_preset_file); +} + +#import +#define UNLIKELYPREFIX "___fl_very_unlikely_prefix_" +#ifndef MAC_OS_X_VERSION_10_6 +#define MAC_OS_X_VERSION_10_6 1060 +#endif + +int Fl_Native_File_Chooser::get_saveas_basename(void) { + char *q = strdup( [[(NSSavePanel*)_panel filename] fileSystemRepresentation] ); + id delegate = [(NSSavePanel*)_panel delegate]; + if (delegate != nil) { + const char *d = [[(NSSavePanel*)_panel directory] fileSystemRepresentation]; + int l = strlen(d) + 1; + int lu = strlen(UNLIKELYPREFIX); + // Remove UNLIKELYPREFIX between directory and filename parts + memmove(q + l, q + l + lu, strlen(q + l + lu) + 1); + } + set_single_pathname( q ); + free(q); + return 0; +} + +// SET THE TYPE OF BROWSER +void Fl_Native_File_Chooser::type(int val) { + _btype = val; + switch (_btype) { + case BROWSE_FILE: + case BROWSE_MULTI_FILE: + case BROWSE_DIRECTORY: + case BROWSE_MULTI_DIRECTORY: + _panel = [NSOpenPanel openPanel]; + break; + case BROWSE_SAVE_DIRECTORY: + case BROWSE_SAVE_FILE: + _panel = [NSSavePanel savePanel]; + break; + } +} + +@interface FLopenDelegate : NSObject +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + +#endif +{ + NSPopUpButton *nspopup; + char **filter_pattern; +} +- (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern; +- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename; +@end +@implementation FLopenDelegate +- (FLopenDelegate*)setPopup:(NSPopUpButton*)popup filter_pattern:(char**)pattern +{ + nspopup = popup; + filter_pattern = pattern; + return self; +} +- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename +{ + if ( [nspopup indexOfSelectedItem] == [nspopup numberOfItems] - 1) return YES; + const char *pathname = [filename fileSystemRepresentation]; + if ( fl_filename_isdir(pathname) ) return YES; + if ( fl_filename_match(pathname, filter_pattern[ [nspopup indexOfSelectedItem] ]) ) return YES; + return NO; +} +@end + +@interface FLsaveDelegate : NSObject +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 + +#endif +{ +} +- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag; +@end +@implementation FLsaveDelegate +- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag +{ + if (! okFlag) return filename; + // User has clicked save, and no overwrite confirmation should occur. + // To get the latter, we need to change the name we return (hence the prefix): + return [@ UNLIKELYPREFIX stringByAppendingString:filename]; +} +@end + +static NSPopUpButton *createPopupAccessory(NSSavePanel *panel, const char *filter, const char *title, int rank) +{ + NSPopUpButton *popup; + NSRect rectview = NSMakeRect(5, 5, 350, 30 ); + NSView *view = [[[NSView alloc] initWithFrame:rectview] autorelease]; + NSRect rectbox = NSMakeRect(0, 3, 50, 1 ); + NSBox *box = [[[NSBox alloc] initWithFrame:rectbox] autorelease]; + NSRect rectpop = NSMakeRect(60, 0, 250, 30 ); + popup = [[[NSPopUpButton alloc ] initWithFrame:rectpop pullsDown:NO] autorelease]; + [view addSubview:box]; + [view addSubview:popup]; + [box setBorderType:NSNoBorder]; + NSString *nstitle = [[NSString alloc] initWithUTF8String:title]; + [box setTitle:nstitle]; + [nstitle release]; + NSFont *font = [NSFont controlContentFontOfSize:NSRegularControlSize]; + [box setTitleFont:font]; + [box sizeToFit]; + CFStringRef tab = CFSTR("\n"); + CFStringRef tmp_cfs; + tmp_cfs = CFStringCreateWithCString(NULL, filter, kCFStringEncodingASCII); + CFArrayRef array = CFStringCreateArrayBySeparatingStrings(NULL, tmp_cfs, tab); + CFRelease(tmp_cfs); + CFRelease(tab); + [popup addItemsWithTitles:(NSArray*)array]; + NSMenuItem *item = [popup itemWithTitle:@""]; + if (item) [popup removeItemWithTitle:@""]; + CFRelease(array); + [popup selectItemAtIndex:rank]; + [panel setAccessoryView:view]; + return popup; +} + +// POST BROWSER +// Internal use only. +// Assumes '_opts' has been initialized. +// +// Returns: +// 0 - user picked a file +// 1 - user cancelled +// -1 - failed; errmsg() has reason +// +int Fl_Native_File_Chooser::post() { + // INITIALIZE BROWSER + if ( _filt_total == 0 ) { // Make sure they match + _filt_value = 0; // TBD: move to someplace more logical? + } + NSAutoreleasePool *localPool; + localPool = [[NSAutoreleasePool alloc] init]; + int retval; + NSString *nstitle = [NSString stringWithUTF8String: (_title ? _title : "No Title")]; + [(NSSavePanel*)_panel setTitle:nstitle]; + switch (_btype) { + case BROWSE_MULTI_FILE: + [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES]; + break; + case BROWSE_MULTI_DIRECTORY: + [(NSOpenPanel*)_panel setAllowsMultipleSelection:YES]; + case BROWSE_DIRECTORY: + [(NSOpenPanel*)_panel setCanChooseDirectories:YES]; + break; + case BROWSE_SAVE_DIRECTORY: + [(NSSavePanel*)_panel setCanCreateDirectories:YES]; + break; + } + + // SHOW THE DIALOG + if ( [(NSSavePanel*)_panel isKindOfClass:[NSOpenPanel class]] ) { + NSPopUpButton *popup = nil; + if (_filt_total) { + char *p; p = _filter; + char *q; q = new char[strlen(p) + 1]; + char *r, *s, *t; + t = q; + do { // copy to t what is in _filter removing what is between \t and \n, if any + r = strchr(p, '\n'); + if (!r) r = p + strlen(p) - 1; + s = strchr(p, '\t'); + if (s && s < r) { memcpy(q, p, s - p); q += s - p; *(q++) = '\n'; } + else { memcpy(q, p, r - p + 1); q += r - p + 1; } + *q = 0; + p = r + 1; + } while(*p); + popup = createPopupAccessory((NSSavePanel*)_panel, t, "Enable:", 0); + delete t; + [[popup menu] addItem:[NSMenuItem separatorItem]]; + [popup addItemWithTitle:@"All Documents"]; + [popup setAction:@selector(validateVisibleColumns)]; + [popup setTarget:(NSObject*)_panel]; + static FLopenDelegate *openDelegate = nil; + if (openDelegate == nil) { + // not to be ever freed + openDelegate = [[FLopenDelegate alloc] init]; + } + [openDelegate setPopup:popup filter_pattern:_filt_patt]; + [(NSOpenPanel*)_panel setDelegate:openDelegate]; + } + NSString *dir = nil; + NSString *fname = nil; + NSString *preset = nil; + if (_preset_file) { + preset = [[NSString alloc] initWithUTF8String:_preset_file]; + if (strchr(_preset_file, '/') != NULL) + dir = [[NSString alloc] initWithString:[preset stringByDeletingLastPathComponent]]; + fname = [preset lastPathComponent]; + } + if (_directory && !dir) dir = [[NSString alloc] initWithUTF8String:_directory]; + retval = [(NSOpenPanel*)_panel runModalForDirectory:dir file:fname types:nil]; + [dir release]; + [preset release]; + if (_filt_total) { + _filt_value = [popup indexOfSelectedItem]; + } + if ( retval == NSOKButton ) { + clear_pathnames(); + NSArray *array = [(NSOpenPanel*)_panel filenames]; + _tpathnames = [array count]; + _pathnames = new char*[_tpathnames]; + for(int i = 0; i < _tpathnames; i++) { + _pathnames[i] = strnew([(NSString*)[array objectAtIndex:i] fileSystemRepresentation]); + } + } + } + else { + NSString *dir = nil; + NSString *fname = nil; + NSString *preset = nil; + NSPopUpButton *popup = nil; + [(NSSavePanel*)_panel setAllowsOtherFileTypes:YES]; + if ( !(_options & SAVEAS_CONFIRM) ) { + static FLsaveDelegate *saveDelegate = nil; + if (saveDelegate == nil)saveDelegate = [[FLsaveDelegate alloc] init]; // not to be ever freed + [(NSSavePanel*)_panel setDelegate:saveDelegate]; + } + if (_preset_file) { + preset = [[NSString alloc] initWithUTF8String:_preset_file]; + if (strchr(_preset_file, '/') != NULL) { + dir = [[NSString alloc] initWithString:[preset stringByDeletingLastPathComponent]]; + } + fname = [preset lastPathComponent]; + } + if (_directory && !dir) dir = [[NSString alloc] initWithUTF8String:_directory]; + if (_filt_total) { + popup = createPopupAccessory((NSSavePanel*)_panel, _filter, "Format:", _filt_value); + } + retval = [(NSSavePanel*)_panel runModalForDirectory:dir file:fname]; + if (_filt_total) { + _filt_value = [popup indexOfSelectedItem]; + } + [dir release]; + [preset release]; + if ( retval == NSOKButton ) get_saveas_basename(); + } + [localPool release]; + return (retval == NSOKButton ? 0 : 1); +} + +#endif /*!FL_DOXYGEN*/ + +// +// End of "$Id$". +// -- cgit v1.2.3