diff --git a/collects/launcher/doc.txt b/collects/launcher/doc.txt index e9d2b3a4d4..4ff1e43741 100644 --- a/collects/launcher/doc.txt +++ b/collects/launcher/doc.txt @@ -131,10 +131,17 @@ executables. > (mred-launcher-is-directory?) - Returns #t if MrEd launchers for the - current platform correspond to directories (as on Mac OS X). + current platform are directories from the user's perspective. > (mzscheme-launcher-is-directory?) - Returns #t if MzScheme launchers - for the current platform correspond to directories. + for the current platform are directories from the user's perspective. + + +> (mred-launcher-is-actually-directory?) - Returns #t if MrEd + launchers for the current platform are implemented as directories. + +> (mzscheme-launcher-is-actually-directory?) - Returns #t if MzScheme + launchers for the current platform are implemented as directories. > (mred-launcher-add-suffix path) - Returns a path with a suitable @@ -147,10 +154,10 @@ executables. > (mred-launcher-put-file-extension+style+filters) - Returns three values suitable for use as the `extension', `style', and `filters' arguments to `put-file', respectively. If MrEd launchers for this - platform are directories, the `style' result is suitable for use - with `get-directory', and the `extension' result may be a string - indicating a required extension for the directory name (e.g., ".app" - for Mac OS X). + platform are directories from the user perspective, the `style' + result is suitable for use with `get-directory', and the `extension' + result may be a string indicating a required extension for the + directory name (e.g., ".app" for Mac OS X). > (mzscheme-launcher-put-file-extension+style+filters) - Like `mred-launcher-get-file-extension+style+filters', but for MzScheme diff --git a/collects/launcher/launcher-sig.ss b/collects/launcher/launcher-sig.ss index bd643a46bf..37aba83599 100644 --- a/collects/launcher/launcher-sig.ss +++ b/collects/launcher/launcher-sig.ss @@ -23,6 +23,9 @@ mred-launcher-is-directory? mzscheme-launcher-is-directory? + mred-launcher-is-actually-directory? + mzscheme-launcher-is-actually-directory? + mred-launcher-add-suffix mzscheme-launcher-add-suffix diff --git a/collects/launcher/launcher-unit.ss b/collects/launcher/launcher-unit.ss index 3bad13862e..69d307d173 100644 --- a/collects/launcher/launcher-unit.ss +++ b/collects/launcher/launcher-unit.ss @@ -528,16 +528,21 @@ [else (mred-program-launcher-path name)])) (define (mred-launcher-is-directory?) + #f) + (define (mzscheme-launcher-is-directory?) + #f) + + (define (mred-launcher-is-actually-directory?) (and (eq? 'macosx (system-type)) (not (memq (current-launcher-variant) '(script script-3m))))) - (define (mzscheme-launcher-is-directory?) + (define (mzscheme-launcher-is-actually-directory?) #f) ;; Helper: (define (put-file-extension+style+filters type) (case type [(windows) (values ".exe" null '(("Executable" "*.exe")))] - [(macosx) (values ".app" '(enter-packages) #f)] + [(macosx) (values ".app" '(packages) '(("App" "*.app")))] [else (values #f null null)])) (define (mred-launcher-add-suffix path) diff --git a/collects/mred/private/filedialog.ss b/collects/mred/private/filedialog.ss index 34085447d0..ba3667a27d 100644 --- a/collects/mred/private/filedialog.ss +++ b/collects/mred/private/filedialog.ss @@ -47,7 +47,6 @@ (check-top-level-parent/false who parent) (check-path/false who directory) (check-path/false who filename) (check-string/false who extension) (check-style who #f (cond - [put? null] [dir? '(enter-packages)] [else '(packages enter-packages)]) style) (unless (and (list? filters) diff --git a/collects/tests/mzscheme/read.ss b/collects/tests/mzscheme/read.ss index 6cf0839b70..8c136b0634 100644 --- a/collects/tests/mzscheme/read.ss +++ b/collects/tests/mzscheme/read.ss @@ -246,6 +246,8 @@ (err/rt-test (readstr "( . 8 9)") exn:fail:read?) (err/rt-test (readstr "(1 . 2 3 . 4)") exn:fail:read?) (err/rt-test (readstr "(1 . 2 . 3 . 4)") exn:fail:read?) +(err/rt-test (readstr "(1 . 2 .3)") exn:fail:read?) +(err/rt-test (readstr "(1 . 2 .a)") exn:fail:read?) (err/rt-test (readstr "#(8 . )") exn:fail:read?) (err/rt-test (readstr "#( . )") exn:fail:read?) (err/rt-test (readstr "#( . 8)") exn:fail:read?) @@ -284,6 +286,7 @@ (test '(1 2 3) readstr "(2 . 1 . 3)") (test '(1 2 3 4) readstr "(2 . 1 . 3 4)") (test '(1 2 3 4) readstr "(2 3 . 1 . 4)") +(test '(2 . 0.4) readstr "(2 . .4)") (err/rt-test (readstr "#ha") exn:fail:read:eof?) (err/rt-test (readstr "#ham") exn:fail:read?) diff --git a/notes/mred/HISTORY b/notes/mred/HISTORY index 908f086a46..6c64e308a0 100644 --- a/notes/mred/HISTORY +++ b/notes/mred/HISTORY @@ -1,4 +1,11 @@ +Version 299.403 +Changed label->plain-label to strip parenthesized mneumonics +Added 'package and 'enter-package flags to put-file, and + changed Mac OS X put-file to use extension and filters args + +---------------------------------------------------------------------- + Version 299.400, September 2005 No MrEd-specific changes diff --git a/src/mzscheme/src/file.c b/src/mzscheme/src/file.c index 2504ced464..a28735e40a 100644 --- a/src/mzscheme/src/file.c +++ b/src/mzscheme/src/file.c @@ -4326,7 +4326,7 @@ static Scheme_Object *expand_path(int argc, Scheme_Object *argv[]) return scheme_make_sized_path(filename, strlen(filename), 1); } -static Scheme_Object *directory_list(int argc, Scheme_Object *argv[]) +static Scheme_Object *do_directory_list(int break_ok, int argc, Scheme_Object *argv[]) { #if !defined(NO_READDIR) || defined(USE_MAC_FILE_TOOLBOX) || defined(USE_FINDFIRST) char *filename; @@ -4366,9 +4366,11 @@ static Scheme_Object *directory_list(int argc, Scheme_Object *argv[]) while (1) { # endif filename = do_expand_filename(path, NULL, 0, - "directory-list", + break_ok ? "directory-list" : NULL, NULL, 1, 259 - 4 /* leave room for \*.* in Windows */, - SCHEME_GUARD_FILE_READ); + break_ok ? SCHEME_GUARD_FILE_READ : 0); + if (!filename) + return NULL; #ifdef USE_FINDFIRST /* Eliminate "." and "..": */ if (SAME_OBJ(path, argv[0])) { @@ -4383,14 +4385,19 @@ static Scheme_Object *directory_list(int argc, Scheme_Object *argv[]) #endif } else { filename = SCHEME_PATH_VAL(CURRENT_WD()); - scheme_security_check_file("directory-list", NULL, SCHEME_GUARD_FILE_EXISTS); - scheme_security_check_file("directory-list", filename, SCHEME_GUARD_FILE_READ); + if (break_ok) { + scheme_security_check_file("directory-list", NULL, SCHEME_GUARD_FILE_EXISTS); + scheme_security_check_file("directory-list", filename, SCHEME_GUARD_FILE_READ); + } } - if (filename && !scheme_directory_exists(filename)) - scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, - "directory-list: could not open \"%q\"", - filename); + if (filename && !scheme_directory_exists(filename)) { + if (break_ok) + scheme_raise_exn(MZEXN_FAIL_FILESYSTEM, + "directory-list: could not open \"%q\"", + filename); + return NULL; + } #endif #ifdef USE_MAC_FILE_TOOLBOX @@ -4403,9 +4410,11 @@ static Scheme_Object *directory_list(int argc, Scheme_Object *argv[]) raise_null_error("directory-list", argv[0], ""); } else { filename = SCHEME_PATH_VAL(CURRENT_WD()); - scheme_security_check_file("directory-list", NULL, SCHEME_GUARD_FILE_EXISTS); + if (break_ok) + scheme_security_check_file("directory-list", NULL, SCHEME_GUARD_FILE_EXISTS); } - scheme_security_check_file("directory-list", filename, SCHEME_GUARD_FILE_READ); + if (break_ok) + scheme_security_check_file("directory-list", filename, SCHEME_GUARD_FILE_READ); if (!find_mac_file(filename, 0, &dir, 1, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0)) { if (argc) { @@ -4426,7 +4435,7 @@ static Scheme_Object *directory_list(int argc, Scheme_Object *argv[]) find_position++; - if (!(find_position & 0x15)) { + if (break_ok && !(find_position & 0x15)) { scheme_thread_block(0); scheme_current_thread->ran_some = 1; } @@ -4502,7 +4511,7 @@ static Scheme_Object *directory_list(int argc, Scheme_Object *argv[]) last = elem; } counter++; - if (!(counter & 0x15)) { + if (break_ok && !(counter & 0x15)) { BEGIN_ESCAPEABLE(FIND_CLOSE, hfile); scheme_thread_block(0); END_ESCAPEABLE(); @@ -4540,7 +4549,7 @@ static Scheme_Object *directory_list(int argc, Scheme_Object *argv[]) last = elem; counter++; - if (!(counter & 0xF)) { + if (break_ok && !(counter & 0xF)) { BEGIN_ESCAPEABLE(closedir, dir); scheme_thread_block(0); END_ESCAPEABLE(); @@ -4556,6 +4565,104 @@ static Scheme_Object *directory_list(int argc, Scheme_Object *argv[]) #endif } +static Scheme_Object *directory_list(int argc, Scheme_Object *argv[]) +{ + return do_directory_list(1, argc, argv); +} + +char *scheme_find_completion(char *fn) +{ + int len; + Scheme_Object *p, *l, *a[2], *f, *matches, *fst; + int isdir, max_match; + Scheme_Object *base; + + len = strlen(fn); + + if (!len) + return NULL; + + f = scheme_split_path(fn, len, &base, &isdir); + if (isdir) { + /* Look for single file/prefix in directory: */ + base = scheme_make_sized_path(fn, len, 0); + f = scheme_make_sized_path("", 0, 0); + } else { + if (!SCHEME_PATHP(base)) + return NULL; + } + + a[0] = base; + l = do_directory_list(0, 1, a); + if (!l) + return NULL; + + matches = scheme_null; + while (SCHEME_PAIRP(l)) { + p = SCHEME_CAR(l); + if ((SCHEME_PATH_LEN(p) >= SCHEME_PATH_LEN(f)) + && !memcmp(SCHEME_PATH_VAL(f), SCHEME_PATH_VAL(p), SCHEME_PATH_LEN(f))) { + matches = scheme_make_pair(p, matches); + } + l = SCHEME_CDR(l); + } + + if (SCHEME_NULLP(matches)) + return NULL; + + if (SCHEME_NULLP(SCHEME_CDR(matches))) { + /* One match */ + a[0] = base; + a[1] = SCHEME_CAR(matches); + p = scheme_build_path(2, a); + a[0] = p; + if (SCHEME_TRUEP(directory_exists(1, a))) { + /* Add trailing separator if one is not there */ + fn = SCHEME_PATH_VAL(p); + len = SCHEME_PATH_LEN(p); + if (!IS_A_SEP(fn[len-1])) { + char *naya; + naya = (char *)scheme_malloc_atomic(len + 2); + memcpy(naya, fn, len); + naya[len++] = FN_SEP; + naya[len] = 0; + fn = naya; + } + } else + fn = SCHEME_PATH_VAL(p); + return fn; + } + + fst = SCHEME_CAR(matches); + max_match = SCHEME_PATH_LEN(fst); + for (l = SCHEME_CDR(matches); SCHEME_PAIRP(l); l = SCHEME_CDR(l)) { + int i, l2; + p = SCHEME_CAR(l); + l2 = SCHEME_PATH_LEN(p); + if (max_match < l2) + l2 = max_match; + else if (l2 < max_match) + max_match = l2; + for (i = 0; i < l2; i++) { + if (SCHEME_PATH_VAL(fst)[i] != SCHEME_PATH_VAL(p)[i]) { + max_match = i; + break; + } + } + } + + if (max_match <= SCHEME_PATH_LEN(f)) + /* No longer match available: */ + return NULL; + + /* Build match */ + a[0] = base; + a[1] = scheme_make_sized_path(SCHEME_PATH_VAL(fst), max_match, 0); + f = scheme_build_path(2, a); + + return SCHEME_PATH_VAL(f); +} + static Scheme_Object *filesystem_root_list(int argc, Scheme_Object *argv[]) { Scheme_Object *first = scheme_null; diff --git a/src/mzscheme/src/read.c b/src/mzscheme/src/read.c index 26fc56a775..803cacacee 100644 --- a/src/mzscheme/src/read.c +++ b/src/mzscheme/src/read.c @@ -1950,6 +1950,33 @@ static Scheme_Object *attach_shape_property(Scheme_Object *list, ReadParams *params, int closer); +static int next_is_delim(Scheme_Object *port, + ReadParams *params, + int brackets, + int braces) +{ + int next; + next = scheme_peekc_special_ok(port); + return ((next == EOF) + || (next == SCHEME_SPECIAL) + || (!params->table + && (scheme_isspace(next) + || (next == '(') + || (next == ')') + || (next == '"') + || (next == ';') + || (next == '\'') + || (next == '`') + || (next == ',') + || ((next == '[') && brackets) + || ((next == '{') && braces) + || ((next == ']') && brackets) + || ((next == '}') && braces))) + || (params->table + && (readtable_kind(params->table, next, params) + & (READTABLE_WHITESPACE | READTABLE_TERMINATING)))); +} + static Scheme_Object *honu_add_module_wrapper(Scheme_Object *list, Scheme_Object *stxsrc, Scheme_Object *port); @@ -1964,7 +1991,7 @@ read_list(Scheme_Object *port, ReadParams *params) { Scheme_Object *list = NULL, *last = NULL, *car, *cdr, *pair, *infixed = NULL, *prefetched = NULL; - int ch = 0, next, got_ch_already = 0; + int ch = 0, got_ch_already = 0; int brackets = params->square_brackets_are_parens; int braces = params->curly_braces_are_parens; long start, startcol, startline, dotpos, dotcol, dotline, dot2pos, dot2line, dot2col; @@ -2154,25 +2181,7 @@ read_list(Scheme_Object *port, } else if (!params->honu_mode && params->can_read_dot && (ch == '.') - && (next = scheme_peekc_special_ok(port), - ((next == EOF) - || (next == SCHEME_SPECIAL) - || (!params->table - && (scheme_isspace(next) - || (next == '(') - || (next == ')') - || (next == '"') - || (next == ';') - || (next == '\'') - || (next == '`') - || (next == ',') - || ((next == '[') && brackets) - || ((next == '{') && braces) - || ((next == ']') && brackets) - || ((next == '}') && braces))) - || (params->table - && (readtable_kind(params->table, next, params) - & (READTABLE_WHITESPACE | READTABLE_TERMINATING)))))) { + && next_is_delim(port, params, brackets, braces)) { scheme_tell_all(port, &dotline, &dotcol, &dotpos); track_indentation(indentation, dotline, dotcol); @@ -2186,7 +2195,7 @@ read_list(Scheme_Object *port, cdr = read_inner(port, stxsrc, ht, indentation, params, 0); ch = skip_whitespace_comments(port, stxsrc, ht, indentation, params); if (ch != closer) { - if (ch == '.') { + if ((ch == '.') && next_is_delim(port, params, brackets, braces)) { /* Parse as infix: */ if (shape == mz_shape_hash_elem) { diff --git a/src/wxmac/src/mac/wx_dialg.cc b/src/wxmac/src/mac/wx_dialg.cc index 9f8db5f275..82b1dfe4e4 100644 --- a/src/wxmac/src/mac/wx_dialg.cc +++ b/src/wxmac/src/mac/wx_dialg.cc @@ -244,6 +244,10 @@ int wxMessageBox(char* message, char* caption, long style, return wxsMessageBox(message, caption, style, parent); } +//**************************************************************************** +// File selector +//**************************************************************************** + #ifndef OS_X extern "C" { #endif @@ -252,8 +256,11 @@ extern "C" { #ifndef OS_X } #endif - -//= T.P. ============================================================================== +extern "C" { + extern char *scheme_expand_filename(char* filename, int ilen, const char *errorin, int *ex, int guards); + extern int scheme_is_complete_path(const char *s, long len); + extern char *scheme_find_completion(char *fn); +} static int navinited = 0; @@ -275,17 +282,290 @@ static int log_base_10(int i) class wxCallbackInfo { public: + NavDialogRef dialog; + int has_parent; char *initial_directory; - char *force_extension; }; +//----------------------------------------------------------------------------- +// Text path dialog +//----------------------------------------------------------------------------- +/* Cocoa's navigation dialog let's the user type "/" to get a dialog + for entering an aboslute path in text, and tab implements path + completion. Carbon's navigation dialog doesn't do that, so we roll + our own. */ + +class wxCallbackCallbackInfo { + public: + WindowRef dialog; + ControlRef txt; + NavCBRecPtr callBackParms; + wxCallbackInfo *cbi; +}; + +static char *extract_string(wxCallbackCallbackInfo *ccbi) +{ + int len; + char *result; + CFStringRef str; + Size sz; + + ::GetControlData(ccbi->txt, kControlEntireControl, + kControlEditTextCFStringTag, sizeof(CFStringRef), &str, &sz); + + len = ::CFStringGetLength(str); + result = new WXGC_ATOMIC char[len * 6 + 1]; + ::CFStringGetCString(str, result, len * 6 + 1, kCFStringEncodingUTF8); + ::CFRelease(str); + + return result; +} + +static OSStatus ok_evt_handler(EventHandlerCallRef inHandlerCallRef, + EventRef inEvent, + void *inUserData) +{ + char *result; + FSSpec spec; + wxCallbackCallbackInfo *ccbi = (wxCallbackCallbackInfo *)GET_SAFEREF(inUserData); + WindowRef dialog = ccbi->dialog; + + result = extract_string(ccbi); + + result = scheme_expand_filename(result, -1, NULL, NULL, 0); + + if (result && scheme_mac_path_to_spec(result, &spec)) { + AEDesc desc; + NavCBRecPtr callBackParms; + callBackParms = ccbi->callBackParms; + AECreateDesc (typeFSS, &spec, sizeof(FSSpec), &desc); + NavCustomControl(callBackParms->context, kNavCtlSetLocation, &desc); + AEDisposeDesc(&desc); + if (!ccbi->cbi->has_parent) { + ::HideSheetWindow(dialog); + } else { + ::HideWindow(dialog); + } + ::QuitAppModalLoopForWindow(dialog); + } else + wxBell(); + + return noErr; +} + +static OSStatus cancel_evt_handler(EventHandlerCallRef inHandlerCallRef, + EventRef inEvent, + void *inUserData) +{ + wxCallbackCallbackInfo *cbbi = (wxCallbackCallbackInfo *)GET_SAFEREF(inUserData); + WindowRef dialog = cbbi->dialog; + + ::HideWindow(dialog); + ::QuitAppModalLoopForWindow(dialog); + + return noErr; +} + +static OSStatus key_evt_handler(EventHandlerCallRef inHandlerCallRef, + EventRef inEvent, + void *inUserData) +{ + char c; + + GetEventParameter(inEvent, kEventParamKeyMacCharCodes, typeChar, + NULL, sizeof(c), NULL, &c); + + if (c == 13) { + return ok_evt_handler(inHandlerCallRef, NULL, inUserData); + } else if (c == 27) { + return cancel_evt_handler(inHandlerCallRef, NULL, inUserData); + } else + return eventNotHandledErr; +} + +static OSStatus tab_evt_handler(EventHandlerCallRef inHandlerCallRef, + EventRef inEvent, + void *inUserData) +{ + char c; + + GetEventParameter(inEvent, kEventParamKeyMacCharCodes, typeChar, + NULL, sizeof(c), NULL, &c); + + if (c == 9) { + char *result; + int len; + wxCallbackCallbackInfo *ccbi = (wxCallbackCallbackInfo *)GET_SAFEREF(inUserData); + + result = extract_string(ccbi); + len = strlen(result); + + if (scheme_is_complete_path(result, len)) { + result = scheme_find_completion(result); + } else + result = NULL; + + if (result) { + CFStringRef str; + str = wxCFString(result); + ::SetControlData(ccbi->txt, kControlEntireControl, + kControlEditTextCFStringTag, sizeof(CFStringRef), &str); + ::CFRelease(str); + ::Draw1Control(ccbi->txt); + } else + wxBell(); + return noErr; + } else + return eventNotHandledErr; +} + +static char *extract_current_dir(NavCBRecPtr callBackParms) +{ + AEDesc here, there; + FSRef fsref; + OSErr err; + char *dir = NULL; + + NavCustomControl(callBackParms->context, kNavCtlGetLocation, &here); + + err = AECoerceDesc(&here, typeFSRef, &there); + if (err != noErr) { + if (err == errAECoercionFail) { + /* Try FSSpec: */ + FSSpec spec; + + err = AECoerceDesc(&here, typeFSRef, &there); + if (err == noErr) { + err = AEGetDescData(&there, &spec, sizeof(FSSpec)); + if (err == noErr) + dir = scheme_mac_spec_to_path(&spec); + AEDisposeDesc(&there); + } + } + } else { + err = AEGetDescData(&there, &fsref, sizeof(fsref)); + if (err == noErr) + dir = wxFSRefToPath(fsref); + AEDisposeDesc(&there); + } + + return dir; +} + +static void do_text_path_dialog(wxCallbackInfo *cbi, + NavCBRecPtr callBackParms) +{ + int width = 500; + WindowRef parent, dialog; + ControlRef ok, lbl, txt, cancel; + EventTypeSpec spec[1]; + Rect r, pr; + char byteFlag = 1, *init; + ControlFontStyleRec style; + ControlEditTextSelectionRec sel; + wxCallbackCallbackInfo *info; + CFStringRef str; + void *info_sr; + + info = new wxCallbackCallbackInfo; + info_sr = WRAP_SAFEREF(info); + + init = extract_current_dir(callBackParms); + if (!init) + init = "/"; + + parent = ::NavDialogGetWindow(cbi->dialog); + GetWindowBounds(parent, kWindowContentRgn, &pr); + + ::SetRect(&r, 0, 0, width, 90); + r.top += ((pr.top + pr.bottom) - r.bottom) / 2; + r.bottom += r.top; + r.left = ((pr.left + pr.right) - r.right) / 2; + r.right += r.left; + + ::CreateNewWindow(cbi->has_parent ? kMovableModalWindowClass : kSheetWindowClass, + kWindowCompositingAttribute, &r, &dialog); + ::InstallStandardEventHandler(GetWindowEventTarget(dialog)); + spec[0].eventClass = kEventClassKeyboard; + spec[0].eventKind = kEventRawKeyDown; + info->dialog = dialog; + info->cbi = cbi; + ::InstallEventHandler(GetWindowEventTarget(dialog), key_evt_handler, 1, spec, info_sr, NULL); + + style.flags = kControlUseFontMask; + style.font = kControlFontBigSystemFont; + + ::SetRect(&r, 10, 10, width - 10, 26); + ::CreateStaticTextControl(dialog, &r, CFSTR("Go to the folder:"), &style, &lbl); + ::ShowControl(lbl); + + ::SetRect(&r, 10, 32, width - 10, 48); + str = wxCFString(init); + ::CreateEditTextControl(dialog, &r, str, 0, 0, &style, &txt); + :: CFRelease(str); + spec[0].eventClass = kEventClassKeyboard; + spec[0].eventKind = kEventRawKeyDown; + ::InstallEventHandler(GetControlEventTarget(txt), tab_evt_handler, 1, spec, info_sr, NULL); + ::ShowControl(txt); + + info->txt = txt; + info->callBackParms = callBackParms; + + ::SetRect(&r, width - 75, 60, width - 10, 80); + ::CreatePushButtonControl(dialog, &r, CFSTR("Goto"), &ok); + ::ShowControl(ok); + spec[0].eventClass = kEventClassControl; + spec[0].eventKind = kEventControlHit; + ::InstallEventHandler(GetControlEventTarget(ok), ok_evt_handler, 1, spec, info_sr, NULL); + ::SetControlData(ok, kControlEntireControl, kControlPushButtonDefaultTag, 1, &byteFlag); + + ::SetRect(&r, width - 150, 60, width - 85, 80); + ::CreatePushButtonControl(dialog, &r, CFSTR("Cancel"), &cancel); + ::ShowControl(cancel); + ::InstallEventHandler(GetControlEventTarget(cancel), cancel_evt_handler, 1, spec, info_sr, NULL); + + ::SetKeyboardFocus(dialog, txt, kControlFocusNextPart); + sel.selStart = 1; + sel.selEnd = 1000; + ::SetControlData(txt, kControlEntireControl, kControlEditTextSelectionTag, sizeof(sel), &sel); + + if (!cbi->has_parent) { + ::ShowSheetWindow(dialog, parent); + } else { + ::ShowWindow(dialog); + } + + ::RunAppModalLoopForWindow(dialog); + + ::DisposeControl(lbl); + ::DisposeControl(txt); + ::DisposeControl(ok); + ::DisposeControl(cancel); + ::DisposeWindow(dialog); + + FREE_SAFEREF(info_sr); + info_sr = NULL; +} + +//----------------------------------------------------------------------------- +// File-selector callback +//----------------------------------------------------------------------------- +/* Sets the right initial directory, if one is supplied, and + redirects '/' to open the text path dialog. */ + static void ExtensionCallback(NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, void *callBackUD) { - wxCallbackInfo *cbi = (wxCallbackInfo *)callBackUD; + wxCallbackInfo *cbi = (wxCallbackInfo *)GET_SAFEREF(callBackUD); switch (callBackSelector) { + case kNavCBEvent: + if ((callBackParms->eventData.eventDataParms.event->what == keyUp) + && ((callBackParms->eventData.eventDataParms.event->message & charCodeMask) == '/')) { + do_text_path_dialog(cbi, callBackParms); + } + break; case kNavCBStart: if (cbi->initial_directory) { FSSpec spec; @@ -298,93 +578,6 @@ static void ExtensionCallback(NavEventCallbackMessage callBackSelector, } break; case kNavCBAccept: - if (cbi->force_extension) { - Str255 sv; - StringPtr s; - char *c, *suffix = cbi->force_extension; - int i, sl; - - s = sv; - NavCustomControl(callBackParms->context, kNavCtlGetEditFileName, s); - - c = wxP2C(s); - for (i = s[0]; i--; ) { - if (c[i] == '.') - break; - } - if (i < 0) - i = 0; - if (strcmp(c + i, suffix)) { - unsigned char *s2; - sl = strlen(suffix); - s2 = (unsigned char *)(new WXGC_ATOMIC char[s[0] + sl + 1]); - memcpy(s2 + 1, s + 1, s[0]); - memcpy(s2 + 1 + s[0], suffix, sl); - s2[0] = s[0] + sl; - NavCustomControl(callBackParms->context, kNavCtlSetEditFileName, s2); - s = s2; - } - - { - AEDesc here, there; - FSRef fsref; - OSErr err; - char *dir = NULL; - - NavCustomControl(callBackParms->context, kNavCtlGetLocation, &here); - - err = AECoerceDesc(&here, typeFSRef, &there); - if (err != noErr) { - if (err == errAECoercionFail) { - /* Try FSSpec: */ - FSSpec spec; - - err = AECoerceDesc(&here, typeFSRef, &there); - if (err == noErr) { - err = AEGetDescData(&there, &spec, sizeof(FSSpec)); - if (err == noErr) - dir = scheme_mac_spec_to_path(&spec); - AEDisposeDesc(&there); - } - } - } else { - err = AEGetDescData(&there, &fsref, sizeof(fsref)); - if (err == noErr) - dir = wxFSRefToPath(fsref); - AEDisposeDesc(&there); - } - - if (!dir) - printf("NoDir! %d\n", err); - - if (dir) { - AlertStdAlertParamRec rec; - SInt16 which; - - rec.movable = FALSE; - rec.helpButton = FALSE; - rec.filterProc = NULL; - rec.defaultText = "\pReplace"; - rec.cancelText = (ConstStringPtr)kAlertDefaultCancelText; - rec.otherText = NULL; - rec.defaultButton = kAlertStdAlertCancelButton; - rec.cancelButton = 0; - rec.position = kWindowAlertPositionParentWindowScreen; - - which = kAlertStdAlertCancelButton; - - err = StandardAlert(kAlertCautionAlert, - "\pReally replace?", - NULL, - &rec, - &which); - - if (which == kAlertStdAlertCancelButton) { - /* ??????? */ - } - } - } - } case kNavCBCancel: /* ^^^^^^^^^^ FALLTHROUGH ^^^^^^^^^^^^ */ QuitAppModalLoopForWindow(callBackParms->window); break; @@ -431,6 +624,7 @@ char *wxFileSelector(char *message, char *default_path, OSErr derr; NavDialogCreationOptions dialogOptions; wxCallbackInfo *cbi; + void *cbi_sr; NavUserAction action; NavReplyRecord *reply; char *temp; @@ -448,14 +642,10 @@ char *wxFileSelector(char *message, char *default_path, cbi = new wxCallbackInfo(); cbi->initial_directory = default_path; - cbi->force_extension = NULL; NavGetDefaultDialogCreationOptions(&dialogOptions); - if (default_filename) { - dialogOptions.saveFileName = CFStringCreateWithCString(NULL,default_filename,CFStringGetSystemEncoding()); - } if (message) { - dialogOptions.message = CFStringCreateWithCString(NULL,message,CFStringGetSystemEncoding()); + dialogOptions.message = wxCFString(message); } dialogOptions.modality = kWindowModalityAppModal; @@ -466,10 +656,48 @@ char *wxFileSelector(char *message, char *default_path, if (!(flags & wxMULTIOPEN)) dialogOptions.optionFlags -= (dialogOptions.optionFlags & kNavAllowMultipleFiles); - if (cbi->force_extension) - dialogOptions.optionFlags |= kNavDontConfirmReplacement; + /* Check whether to enforce a particular suffix */ + if (default_extension && wildcard && flags && !(flags & (wxOPEN | wxMULTIOPEN | wxGETDIR))) { + GC_CAN_IGNORE char *s1, *s2; + + s1 = strchr(wildcard, '|'); + if (s1) { + s1++; + s2 = strchr(s1, '|'); + if (s2) { + int len, flen; + len = strlen(default_extension); + if ((s1[0] == '*') + && (s1[1] == '.') + && ((s2 - s1) == (len + 2)) + && !strncmp(default_extension, s1+2, len)) { + dialogOptions.optionFlags |= kNavPreserveSaveFileExtension; + /* Make sure initial name has specified extension: */ + if (!default_filename) + default_filename = "?"; + flen = strlen(default_filename); + if ((flen < len + 1) + || (default_filename[flen -len - 1] != '.') + || strcmp(default_extension, default_filename + flen - len)) { + /* Need to add extension */ + char *naya; + naya = new WXGC_ATOMIC char[flen + len +2]; + memcpy(naya, default_filename, flen); + memcpy(naya + flen + 1, default_extension, len + 1); + naya[flen] = '.'; + default_filename = naya; + } + } + } + } + } + + if (default_filename) { + dialogOptions.saveFileName = wxCFString(default_filename); + } + + cbi->has_parent = 1; -#ifdef OS_X if (parent) { wxFrame *f; @@ -490,25 +718,29 @@ char *wxFileSelector(char *message, char *default_path, graf = mdc->macGrafPort(); dialogOptions.parentWindow = GetWindowFromPort(graf); dialogOptions.modality = kWindowModalityWindowModal; + cbi->has_parent = 1; } } -#endif + + cbi_sr = WRAP_SAFEREF(cbi); // create the dialog: if (flags & wxGETDIR) { derr = NavCreateChooseFolderDialog(&dialogOptions, - extProc, NULL, cbi, + extProc, NULL, cbi_sr, &outDialog); } else if ((flags == 0) || (flags & wxOPEN) || (flags & wxMULTIOPEN)) { derr = NavCreateGetFileDialog(&dialogOptions, NULL, - extProc, NULL, NULL, cbi, + extProc, NULL, NULL, cbi_sr, &outDialog); } else { derr = NavCreatePutFileDialog(&dialogOptions, 'TEXT', 'mReD', - extProc, cbi, + extProc, cbi_sr, &outDialog); } + cbi->dialog = outDialog; + if (derr != noErr) { if (default_filename) CFRelease(dialogOptions.saveFileName); @@ -527,6 +759,8 @@ char *wxFileSelector(char *message, char *default_path, CFRelease(dialogOptions.message); NavDialogDispose(outDialog); wxTheApp->AdjustCursor(); + FREE_SAFEREF(cbi_sr); + cbi_sr = NULL; return NULL; } @@ -536,6 +770,9 @@ char *wxFileSelector(char *message, char *default_path, wxPrimDialogCleanUp(); + FREE_SAFEREF(cbi_sr); + cbi_sr = NULL; + // dump those strings: if (default_filename) CFRelease(dialogOptions.saveFileName); diff --git a/src/wxmac/src/mac/wx_util.cc b/src/wxmac/src/mac/wx_util.cc index 7eb78be286..5130e9f3ec 100644 --- a/src/wxmac/src/mac/wx_util.cc +++ b/src/wxmac/src/mac/wx_util.cc @@ -145,29 +145,6 @@ extern "C" { CFStringRef wxCFString(const char *s) { - int l, ul, i; - unsigned int *us; - - /* Look for a character that is beyond the official Unicode - range, which ends at 0x10FFFDL. */ - l = strlen(s); - us = new WXGC_ATOMIC unsigned[l + 1]; - ul = scheme_utf8_decode_all((unsigned char *)s, l, us, 0); - for (i = 0; i < ul; i++) { - if (us[i] > 0x10FFFD) { - us[i] = '?'; - s = NULL; - } - } - - if (!s) { - /* Found a too-large char. Convert back to utf-8. - (The result will be smaller than the old l.) */ - s = new WXGC_ATOMIC char[l + 1]; - l = scheme_utf8_encode_all(us, ul, (unsigned char *)s); - ((char *)s)[l] = 0; - } - return CFStringCreateWithCString(NULL, s, kCFStringEncodingUTF8); }