935 lines
24 KiB
C
935 lines
24 KiB
C
/*
|
||
* tkMacDialog.c --
|
||
*
|
||
* Contains the Mac implementation of the common dialog boxes.
|
||
*
|
||
* Copyright (c) 1996 Sun Microsystems, Inc.
|
||
*
|
||
* See the file "license.terms" for information on usage and redistribution
|
||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||
*
|
||
* SCCS: @(#) tkMacDialog.c 1.10 96/09/05 11:21:16
|
||
*
|
||
*/
|
||
|
||
#include <Gestalt.h>
|
||
#include <Aliases.h>
|
||
#include <Errors.h>
|
||
#include <Strings.h>
|
||
#include <MoreFiles.h>
|
||
#include <MoreFilesExtras.h>
|
||
#include <StandardFile.h>
|
||
#include <ColorPicker.h>
|
||
#include <Lowmem.h>
|
||
#include "tkPort.h"
|
||
#include "tkInt.h"
|
||
#include "tclMacInt.h"
|
||
#include "tkFileFilter.h"
|
||
|
||
/*
|
||
* The following are ID's for resources that are defined in tkMacResource.r
|
||
*/
|
||
#define OPEN_BOX 130
|
||
#define OPEN_POPUP 131
|
||
#define OPEN_MENU 132
|
||
#define OPEN_POPUP_ITEM 10
|
||
|
||
#define SAVE_FILE 0
|
||
#define OPEN_FILE 1
|
||
|
||
#define MATCHED 0
|
||
#define UNMATCHED 1
|
||
|
||
/*
|
||
* The following structure is used in the GetFileName() function. It stored
|
||
* information about the file dialog and the file filters.
|
||
*/
|
||
typedef struct _OpenFileData {
|
||
Tcl_Interp * interp;
|
||
char * initialFile; /* default file to appear in the
|
||
* save dialog */
|
||
char * defExt; /* default extension (not used on the
|
||
* Mac) */
|
||
FileFilterList fl; /* List of file filters. */
|
||
SInt16 curType; /* The filetype currently being
|
||
* listed */
|
||
int isOpen; /* True if this is an Open dialog,
|
||
* false if it is a Save dialog. */
|
||
MenuHandle menu; /* Handle of the menu in the popup*/
|
||
short dialogId; /* resource ID of the dialog */
|
||
int popupId; /* resource ID of the popup */
|
||
short popupItem; /* item number of the popup in the
|
||
* dialog */
|
||
int usePopup; /* True if we show the popup menu (this
|
||
* is an open operation and the
|
||
* -filetypes option is set)
|
||
*/
|
||
} OpenFileData;
|
||
|
||
static pascal Boolean FileFilterProc _ANSI_ARGS_((CInfoPBPtr pb,
|
||
void *myData));
|
||
static int GetFileName _ANSI_ARGS_ ((
|
||
ClientData clientData, Tcl_Interp *interp,
|
||
int argc, char **argv, int isOpen ));
|
||
static Boolean MatchOneType _ANSI_ARGS_((CInfoPBPtr pb,
|
||
OpenFileData * myDataPtr, FileFilter * filterPtr));
|
||
static pascal short OpenHookProc _ANSI_ARGS_((short item,
|
||
DialogPtr theDialog, OpenFileData * myDataPtr));
|
||
static int ParseFileDlgArgs _ANSI_ARGS_ ((Tcl_Interp * interp,
|
||
OpenFileData * myDataPtr, int argc, char ** argv,
|
||
int isOpen));
|
||
|
||
/*
|
||
* Filter and hook functions used by the tk_getOpenFile and tk_getSaveFile
|
||
* commands.
|
||
*/
|
||
|
||
static FileFilterYDUPP openFilter = NULL;
|
||
static DlgHookYDUPP openHook = NULL;
|
||
static DlgHookYDUPP saveHook = NULL;
|
||
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* EvalArgv --
|
||
*
|
||
* Invokes the Tcl procedure with the arguments. argv[0] is set by
|
||
* the caller of this function. It may be different than cmdName.
|
||
* The TCL command will see argv[0], not cmdName, as its name if it
|
||
* invokes [lindex [info level 0] 0]
|
||
*
|
||
* Results:
|
||
* TCL_ERROR if the command does not exist and cannot be autoloaded.
|
||
* Otherwise, return the result of the evaluation of the command.
|
||
*
|
||
* Side effects:
|
||
* The command may be autoloaded.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
static int EvalArgv(
|
||
Tcl_Interp *interp, /* Current interpreter. */
|
||
char * cmdName, /* Name of the TCL command to call */
|
||
int argc, /* Number of arguments. */
|
||
char **argv) /* Argument strings. */
|
||
{
|
||
Tcl_CmdInfo cmdInfo;
|
||
|
||
if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) {
|
||
char * cmdArgv[2];
|
||
|
||
/*
|
||
* This comand is not in the interpreter yet -- looks like we
|
||
* have to auto-load it
|
||
*/
|
||
if (!Tcl_GetCommandInfo(interp, "auto_load", &cmdInfo)) {
|
||
Tcl_ResetResult(interp);
|
||
Tcl_AppendResult(interp, "cannot execute command \"auto_load\"",
|
||
NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
|
||
cmdArgv[0] = "auto_load";
|
||
cmdArgv[1] = cmdName;
|
||
|
||
if ((*cmdInfo.proc)(cmdInfo.clientData, interp, 2, cmdArgv)!= TCL_OK){
|
||
return TCL_ERROR;
|
||
}
|
||
|
||
if (!Tcl_GetCommandInfo(interp, cmdName, &cmdInfo)) {
|
||
Tcl_ResetResult(interp);
|
||
Tcl_AppendResult(interp, "cannot auto-load command \"",
|
||
cmdName, "\"",NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
}
|
||
|
||
return (*cmdInfo.proc)(cmdInfo.clientData, interp, argc, argv);
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* Tk_ChooseColorCmd --
|
||
*
|
||
* This procedure implements the color dialog box for the Mac
|
||
* platform. See the user documentation for details on what it
|
||
* does.
|
||
*
|
||
* Results:
|
||
* A standard Tcl result.
|
||
*
|
||
* Side effects:
|
||
* See the user documentation.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
Tk_ChooseColorCmd(
|
||
ClientData clientData, /* Main window associated with interpreter. */
|
||
Tcl_Interp *interp, /* Current interpreter. */
|
||
int argc, /* Number of arguments. */
|
||
char **argv) /* Argument strings. */
|
||
{
|
||
Tk_Window parent = Tk_MainWindow(interp);
|
||
char * colorStr = NULL;
|
||
XColor * colorPtr = NULL;
|
||
char * title = "Choose a color:";
|
||
int i, version;
|
||
long response = 0;
|
||
OSErr err = noErr;
|
||
char buff[40];
|
||
static RGBColor in;
|
||
static inited = 0;
|
||
|
||
/*
|
||
* Use the gestalt manager to determine how to bring
|
||
* up the color picker. If versin 2.0 isn't available
|
||
* we can assume version 1.0 is available as it comes with
|
||
* Color Quickdraw which Tk requires to run at all.
|
||
*/
|
||
|
||
err = Gestalt(gestaltColorPicker, &response);
|
||
if ((err == noErr) || (response == 0x0200L)) {
|
||
version = 2;
|
||
} else {
|
||
version = 1;
|
||
}
|
||
|
||
for (i=1; i<argc; i+=2) {
|
||
int v = i+1;
|
||
int len = strlen(argv[i]);
|
||
|
||
if (strncmp(argv[i], "-initialcolor", len)==0) {
|
||
if (v==argc) {goto arg_missing;}
|
||
|
||
colorStr = argv[v];
|
||
} else if (strncmp(argv[i], "-parent", len)==0) {
|
||
if (v==argc) {goto arg_missing;}
|
||
|
||
parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp));
|
||
if (parent == NULL) {
|
||
return TCL_ERROR;
|
||
}
|
||
} else if (strncmp(argv[i], "-title", len)==0) {
|
||
if (v==argc) {goto arg_missing;}
|
||
|
||
title = argv[v];
|
||
} else {
|
||
Tcl_AppendResult(interp, "unknown option \"",
|
||
argv[i], "\", must be -initialcolor, -parent or -title",
|
||
NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
}
|
||
|
||
if (colorStr) {
|
||
colorPtr = Tk_GetColor(interp, parent, colorStr);
|
||
if (colorPtr == NULL) {
|
||
return TCL_ERROR;
|
||
}
|
||
}
|
||
|
||
if (!inited) {
|
||
inited = 1;
|
||
in.red = 0xffff;
|
||
in.green = 0xffff;
|
||
in.blue = 0xffff;
|
||
}
|
||
if (colorPtr) {
|
||
in.red = colorPtr->red;
|
||
in.green = colorPtr->green;
|
||
in.blue = colorPtr->blue;
|
||
}
|
||
|
||
if (version == 1) {
|
||
/*
|
||
* Use version 1.0 of the color picker
|
||
*/
|
||
|
||
RGBColor out;
|
||
Str255 prompt;
|
||
Point point = {-1, -1};
|
||
|
||
prompt[0] = strlen(title);
|
||
strncpy((char*) prompt+1, title, 255);
|
||
|
||
if (GetColor(point, prompt, &in, &out)) {
|
||
/*
|
||
* user selected a color
|
||
*/
|
||
sprintf(buff, "#%02x%02x%02x", out.red >> 8, out.green >> 8,
|
||
out.blue >> 8);
|
||
Tcl_SetResult(interp, buff, TCL_VOLATILE);
|
||
|
||
/*
|
||
* Save it for the next time
|
||
*/
|
||
in.red = out.red;
|
||
in.green = out.green;
|
||
in.blue = out.blue;
|
||
} else {
|
||
Tcl_ResetResult(interp);
|
||
}
|
||
} else {
|
||
/*
|
||
* Version 2.0 of the color picker is available. Let's use it
|
||
*/
|
||
ColorPickerInfo cpinfo;
|
||
|
||
cpinfo.theColor.profile = 0L;
|
||
cpinfo.theColor.color.rgb.red = in.red;
|
||
cpinfo.theColor.color.rgb.green = in.green;
|
||
cpinfo.theColor.color.rgb.blue = in.blue;
|
||
cpinfo.dstProfile = 0L;
|
||
cpinfo.flags = CanModifyPalette | CanAnimatePalette;
|
||
cpinfo.placeWhere = kDeepestColorScreen;
|
||
cpinfo.pickerType = 0L;
|
||
cpinfo.eventProc = NULL;
|
||
cpinfo.colorProc = NULL;
|
||
cpinfo.colorProcData = NULL;
|
||
|
||
cpinfo.prompt[0] = strlen(title);
|
||
strncpy((char*)cpinfo.prompt+1, title, 255);
|
||
|
||
if ((PickColor(&cpinfo) == noErr) && cpinfo.newColorChosen) {
|
||
sprintf(buff, "#%02x%02x%02x",
|
||
cpinfo.theColor.color.rgb.red >> 8,
|
||
cpinfo.theColor.color.rgb.green >> 8,
|
||
cpinfo.theColor.color.rgb.blue >> 8);
|
||
Tcl_SetResult(interp, buff, TCL_VOLATILE);
|
||
|
||
in.blue = cpinfo.theColor.color.rgb.red;
|
||
in.green = cpinfo.theColor.color.rgb.green;
|
||
in.blue = cpinfo.theColor.color.rgb.blue;
|
||
} else {
|
||
Tcl_ResetResult(interp);
|
||
}
|
||
}
|
||
|
||
if (colorPtr) {
|
||
Tk_FreeColor(colorPtr);
|
||
}
|
||
|
||
return TCL_OK;
|
||
|
||
arg_missing:
|
||
Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing",
|
||
NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* Tk_GetOpenFileCmd --
|
||
*
|
||
* This procedure implements the "open file" dialog box for the
|
||
* Mac platform. See the user documentation for details on what
|
||
* it does.
|
||
*
|
||
* Results:
|
||
* A standard Tcl result.
|
||
*
|
||
* Side effects:
|
||
* See user documentation.
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
Tk_GetOpenFileCmd(
|
||
ClientData clientData, /* Main window associated with interpreter. */
|
||
Tcl_Interp *interp, /* Current interpreter. */
|
||
int argc, /* Number of arguments. */
|
||
char **argv) /* Argument strings. */
|
||
{
|
||
return GetFileName(clientData, interp, argc, argv, OPEN_FILE);
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* Tk_GetSaveFileCmd --
|
||
*
|
||
* Same as Tk_GetOpenFileCmd but opens a "save file" dialog box
|
||
* instead
|
||
*
|
||
* Results:
|
||
* A standard Tcl result.
|
||
*
|
||
* Side effects:
|
||
* See user documentation.
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
Tk_GetSaveFileCmd(
|
||
ClientData clientData, /* Main window associated with interpreter. */
|
||
Tcl_Interp *interp, /* Current interpreter. */
|
||
int argc, /* Number of arguments. */
|
||
char **argv) /* Argument strings. */
|
||
{
|
||
return GetFileName(clientData, interp, argc, argv, SAVE_FILE);
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* GetFileName --
|
||
*
|
||
* Calls the Mac file dialog functions for the user to choose a
|
||
* file to or save.
|
||
*
|
||
* Results:
|
||
* A standard Tcl result.
|
||
*
|
||
* Side effects:
|
||
* If the user selects a file, the native pathname of the file
|
||
* is returned in interp->result. Otherwise an empty string
|
||
* is returned in interp->result.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
static int GetFileName(
|
||
ClientData clientData, /* Main window associated with interpreter. */
|
||
Tcl_Interp *interp, /* Current interpreter. */
|
||
int argc, /* Number of arguments. */
|
||
char **argv, /* Argument strings. */
|
||
int isOpen) /* true if we should call GetOpenFileName(),
|
||
* false if we should call GetSaveFileName() */
|
||
{
|
||
int code = TCL_OK;
|
||
int i;
|
||
OpenFileData myData, *myDataPtr;
|
||
StandardFileReply reply;
|
||
Point mypoint;
|
||
Str255 str;
|
||
|
||
myDataPtr = &myData;
|
||
|
||
if (openFilter == NULL) {
|
||
openFilter = NewFileFilterYDProc(FileFilterProc);
|
||
openHook = NewDlgHookYDProc(OpenHookProc);
|
||
saveHook = NewDlgHookYDProc(OpenHookProc);
|
||
}
|
||
|
||
/*
|
||
* 1. Parse the arguments.
|
||
*/
|
||
if (ParseFileDlgArgs(interp, myDataPtr, argc, argv, isOpen)
|
||
!= TCL_OK) {
|
||
return TCL_ERROR;
|
||
}
|
||
|
||
/*
|
||
* 2. Set the items in the file types popup.
|
||
*/
|
||
|
||
/*
|
||
* Delete all the entries inside the popup menu, in case there's any
|
||
* left overs from previous invocation of this command
|
||
*/
|
||
|
||
if (myDataPtr->usePopup) {
|
||
FileFilter * filterPtr;
|
||
|
||
for (i=CountMItems(myDataPtr->menu); i>0; i--) {
|
||
/*
|
||
* The item indices are one based. Also, if we delete from
|
||
* the beginning, the items may be re-numbered. So we
|
||
* delete from the end
|
||
*/
|
||
DeleteMenuItem(myDataPtr->menu, i);
|
||
}
|
||
|
||
if (myDataPtr->fl.filters) {
|
||
for (filterPtr=myDataPtr->fl.filters; filterPtr;
|
||
filterPtr=filterPtr->next) {
|
||
strncpy((char*)str+1, filterPtr->name, 254);
|
||
str[0] = strlen(filterPtr->name);
|
||
AppendMenu(myDataPtr->menu, (ConstStr255Param) str);
|
||
}
|
||
} else {
|
||
myDataPtr->usePopup = 0;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 3. Call the toolbox file dialog function.
|
||
*/
|
||
SetPt(&mypoint, -1, -1);
|
||
SetCursor(&qd.arrow);
|
||
|
||
if (myDataPtr->isOpen) {
|
||
if (myDataPtr->usePopup) {
|
||
CustomGetFile(openFilter, (short) -1, NULL, &reply,
|
||
myDataPtr->dialogId,
|
||
mypoint, openHook, NULL, NULL, NULL, (void*)myDataPtr);
|
||
} else {
|
||
StandardGetFile(NULL, -1, NULL, &reply);
|
||
}
|
||
} else {
|
||
Str255 prompt, def;
|
||
|
||
strcpy((char*)prompt+1, "Save as");
|
||
prompt[0] = strlen("Save as");
|
||
if (myDataPtr->initialFile) {
|
||
strncpy((char*)def+1, myDataPtr->initialFile, 254);
|
||
def[0] = strlen(myDataPtr->initialFile);
|
||
} else {
|
||
def[0] = 0;
|
||
}
|
||
if (myDataPtr->usePopup) {
|
||
/*
|
||
* Currently this never gets called because we don't use
|
||
* popup for the save dialog.
|
||
*/
|
||
CustomPutFile(prompt, def, &reply, myDataPtr->dialogId, mypoint,
|
||
saveHook, NULL, NULL, NULL, myDataPtr);
|
||
} else {
|
||
StandardPutFile(prompt, def, &reply);
|
||
}
|
||
}
|
||
|
||
Tcl_ResetResult(interp);
|
||
if (reply.sfGood) {
|
||
int length;
|
||
Handle pathHandle = NULL;
|
||
char * pathName = NULL;
|
||
|
||
FSpPathFromLocation(&reply.sfFile, &length, &pathHandle);
|
||
|
||
if (pathHandle != NULL) {
|
||
HLock(pathHandle);
|
||
pathName = (char *) ckalloc((unsigned) (length + 1));
|
||
strcpy(pathName, *pathHandle);
|
||
HUnlock(pathHandle);
|
||
DisposeHandle(pathHandle);
|
||
|
||
/*
|
||
* Return the full pathname of the selected file
|
||
*/
|
||
|
||
Tcl_SetResult(interp, pathName, TCL_DYNAMIC);
|
||
}
|
||
}
|
||
|
||
done:
|
||
TkFreeFileFilters(&myDataPtr->fl);
|
||
return code;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* ParseFileDlgArgs --
|
||
*
|
||
* Parses the arguments passed to tk_getOpenFile and tk_getSaveFile.
|
||
*
|
||
* Results:
|
||
* A standard TCL return value.
|
||
*
|
||
* Side effects:
|
||
* The OpenFileData structure is initialized and modified according
|
||
* to the arguments.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
static int ParseFileDlgArgs(
|
||
Tcl_Interp * interp, /* Current interpreter. */
|
||
OpenFileData * myDataPtr, /* Information about the file dialog */
|
||
int argc, /* Number of arguments */
|
||
char ** argv, /* Argument strings */
|
||
int isOpen) /* TRUE if this is an "open" dialog */
|
||
{
|
||
int i;
|
||
|
||
myDataPtr->interp = interp;
|
||
myDataPtr->initialFile = NULL;
|
||
myDataPtr->curType = 0;
|
||
|
||
TkInitFileFilters(&myDataPtr->fl);
|
||
|
||
if (isOpen) {
|
||
myDataPtr->isOpen = 1;
|
||
myDataPtr->usePopup = 1;
|
||
myDataPtr->menu = GetMenu(OPEN_MENU);
|
||
myDataPtr->dialogId = OPEN_BOX;
|
||
myDataPtr->popupId = OPEN_POPUP;
|
||
myDataPtr->popupItem = OPEN_POPUP_ITEM;
|
||
if (myDataPtr->menu == NULL) {
|
||
Debugger();
|
||
}
|
||
} else {
|
||
myDataPtr->isOpen = 0;
|
||
myDataPtr->usePopup = 0;
|
||
}
|
||
|
||
for (i=1; i<argc; i+=2) {
|
||
int v = i+1;
|
||
int len = strlen(argv[i]);
|
||
|
||
if (strncmp(argv[i], "-defaultextension", len)==0) {
|
||
if (v==argc) {goto arg_missing;}
|
||
|
||
myDataPtr->defExt = argv[v];
|
||
}
|
||
else if (strncmp(argv[i], "-filetypes", len)==0) {
|
||
if (v==argc) {goto arg_missing;}
|
||
|
||
if (TkGetFileFilters(interp, &myDataPtr->fl,argv[v],0) != TCL_OK) {
|
||
return TCL_ERROR;
|
||
}
|
||
}
|
||
else if (strncmp(argv[i], "-initialdir", len)==0) {
|
||
FSSpec dirSpec;
|
||
char * dirName;
|
||
Tcl_DString dstring;
|
||
long dirID;
|
||
OSErr err;
|
||
Boolean isDirectory;
|
||
|
||
if (v==argc) {goto arg_missing;}
|
||
|
||
if (Tcl_TranslateFileName(interp, argv[v], &dstring) == NULL) {
|
||
return TCL_ERROR;
|
||
}
|
||
dirName = dstring.string;
|
||
if (FSpLocationFromPath(strlen(dirName), dirName, &dirSpec) !=
|
||
noErr) {
|
||
Tcl_AppendResult(interp, "bad directory \"", argv[v],
|
||
"\"", NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
err = FSpGetDirectoryID(&dirSpec, &dirID, &isDirectory);
|
||
if ((err != noErr) || !isDirectory) {
|
||
Tcl_AppendResult(interp, "bad directory \"", argv[v],
|
||
"\"", NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
/*
|
||
* Make sure you negate -dirSpec.vRefNum because the standard file
|
||
* package wants it that way !
|
||
*/
|
||
LMSetSFSaveDisk(-dirSpec.vRefNum);
|
||
LMSetCurDirStore(dirID);
|
||
Tcl_DStringFree(&dstring);
|
||
}
|
||
else if (strncmp(argv[i], "-initialfile", len)==0) {
|
||
if (v==argc) {goto arg_missing;}
|
||
|
||
myDataPtr->initialFile = argv[v];
|
||
}
|
||
else if (strncmp(argv[i], "-parent", len)==0) {
|
||
/*
|
||
* Ignored on the Mac, but make sure that it's a valid window
|
||
* pathname
|
||
*/
|
||
Tk_Window parent;
|
||
|
||
if (v==argc) {goto arg_missing;}
|
||
|
||
parent=Tk_NameToWindow(interp, argv[v], Tk_MainWindow(interp));
|
||
if (parent == NULL) {
|
||
return TCL_ERROR;
|
||
}
|
||
}
|
||
else if (strncmp(argv[i], "-title", len)==0) {
|
||
if (v==argc) {goto arg_missing;}
|
||
|
||
/*
|
||
* This option is ignored on the Mac because the Mac file
|
||
* dialog do not support titles.
|
||
*/
|
||
}
|
||
else {
|
||
Tcl_AppendResult(interp, "unknown option \"",
|
||
argv[i], "\", must be -defaultextension, ",
|
||
"-filetypes, -initialdir, -initialfile, -parent or -title",
|
||
NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
}
|
||
|
||
return TCL_OK;
|
||
|
||
arg_missing:
|
||
Tcl_AppendResult(interp, "value for \"", argv[argc-1], "\" missing",
|
||
NULL);
|
||
return TCL_ERROR;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* OpenHookProc --
|
||
*
|
||
* Gets called for various events that occur in the file dialog box.
|
||
* Initializes the popup menu or rebuild the file list depending on
|
||
* the type of the event.
|
||
*
|
||
* Results:
|
||
* A standard result understood by the Mac file dialog event dispatcher.
|
||
*
|
||
* Side effects:
|
||
* The contents in the file dialog may be changed depending on
|
||
* the type of the event.
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
static pascal short
|
||
OpenHookProc(
|
||
short item, /* Event description. */
|
||
DialogPtr theDialog, /* The dialog where the event occurs. */
|
||
OpenFileData * myDataPtr) /* Information about the file dialog. */
|
||
{
|
||
short ignore;
|
||
Rect rect;
|
||
Handle handle;
|
||
int newType;
|
||
|
||
switch (item) {
|
||
case sfHookFirstCall:
|
||
if (myDataPtr->usePopup) {
|
||
/*
|
||
* Set the popup list to display the selected type.
|
||
*/
|
||
GetDialogItem(theDialog, myDataPtr->popupItem,
|
||
&ignore, &handle, &rect);
|
||
SetControlValue((ControlRef) handle, myDataPtr->curType + 1);
|
||
}
|
||
return sfHookNullEvent;
|
||
|
||
case OPEN_POPUP_ITEM:
|
||
if (myDataPtr->usePopup) {
|
||
GetDialogItem(theDialog, myDataPtr->popupItem,
|
||
&ignore, &handle, &rect);
|
||
newType = GetCtlValue((ControlRef) handle) - 1;
|
||
if (myDataPtr->curType != newType) {
|
||
if (newType<0 || newType>myDataPtr->fl.numFilters) {
|
||
/*
|
||
* Sanity check. Looks like the user selected an
|
||
* non-existent menu item?? Don't do anything.
|
||
*/
|
||
} else {
|
||
myDataPtr->curType = newType;
|
||
}
|
||
return sfHookRebuildList;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
|
||
return item;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* FileFilterProc --
|
||
*
|
||
* Filters files according to file types. Get called whenever the
|
||
* file list needs to be updated inside the dialog box.
|
||
*
|
||
* Results:
|
||
* Returns MATCHED if the file should be shown in the listbox, returns
|
||
* UNMATCHED otherwise.
|
||
*
|
||
* Side effects:
|
||
* If MATCHED is returned, the file is shown in the listbox.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
static pascal Boolean
|
||
FileFilterProc(
|
||
CInfoPBPtr pb, /* Information about the file */
|
||
void *myData) /* Client data for this file dialog */
|
||
{
|
||
int i;
|
||
OpenFileData * myDataPtr = (OpenFileData*)myData;
|
||
FileFilter * filterPtr;
|
||
|
||
if (myDataPtr->fl.numFilters == 0) {
|
||
/*
|
||
* No types have been specified. List all files by default
|
||
*/
|
||
return MATCHED;
|
||
}
|
||
|
||
if (pb->dirInfo.ioFlAttrib & 0x10) {
|
||
/*
|
||
* This is a directory: always show it
|
||
*/
|
||
return MATCHED;
|
||
}
|
||
|
||
if (myDataPtr->usePopup) {
|
||
i = myDataPtr->curType;
|
||
for (filterPtr=myDataPtr->fl.filters; filterPtr && i>0; i--) {
|
||
filterPtr = filterPtr->next;
|
||
}
|
||
if (filterPtr) {
|
||
return MatchOneType(pb, myDataPtr, filterPtr);
|
||
} else {
|
||
return UNMATCHED;
|
||
}
|
||
} else {
|
||
/*
|
||
* We are not using the popup menu. In this case, the file is
|
||
* considered matched if it matches any of the file filters.
|
||
*/
|
||
|
||
for (filterPtr=myDataPtr->fl.filters; filterPtr;
|
||
filterPtr=filterPtr->next) {
|
||
if (MatchOneType(pb, myDataPtr, filterPtr) == MATCHED) {
|
||
return MATCHED;
|
||
}
|
||
}
|
||
return UNMATCHED;
|
||
}
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* MatchOneType --
|
||
*
|
||
* Match a file with one file type in the list of file types.
|
||
*
|
||
* Results:
|
||
* Returns MATCHED if the file matches with the file type; returns
|
||
* UNMATCHED otherwise.
|
||
*
|
||
* Side effects:
|
||
* None
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
static Boolean MatchOneType(
|
||
CInfoPBPtr pb, /* Information about the file */
|
||
OpenFileData * myDataPtr, /* Information about this file dialog */
|
||
FileFilter * filterPtr) /* Match the file described by pb against
|
||
* this filter */
|
||
{
|
||
FileFilterClause * clausePtr;
|
||
|
||
/*
|
||
* A file matches with a file type if it matches with at least one
|
||
* clause of the type.
|
||
*
|
||
* If the clause has both glob patterns and ostypes, the file must
|
||
* match with at least one pattern AND at least one ostype.
|
||
*
|
||
* If the clause has glob patterns only, the file must match with at least
|
||
* one pattern.
|
||
*
|
||
* If the clause has mac types only, the file must match with at least
|
||
* one mac type.
|
||
*
|
||
* If the clause has neither glob patterns nor mac types, it's
|
||
* considered an error.
|
||
*/
|
||
|
||
for (clausePtr=filterPtr->clauses; clausePtr; clausePtr=clausePtr->next) {
|
||
int macMatched = 0;
|
||
int globMatched = 0;
|
||
GlobPattern * globPtr;
|
||
MacFileType * mfPtr;
|
||
|
||
if (clausePtr->patterns == NULL) {
|
||
globMatched = 1;
|
||
}
|
||
if (clausePtr->macTypes == NULL) {
|
||
macMatched = 1;
|
||
}
|
||
|
||
for (globPtr=clausePtr->patterns; globPtr; globPtr=globPtr->next) {
|
||
char filename[256];
|
||
int len;
|
||
char * p, *q, *ext;
|
||
|
||
if (pb->hFileInfo.ioNamePtr == NULL) {
|
||
continue;
|
||
}
|
||
p = (char*)(pb->hFileInfo.ioNamePtr);
|
||
len = p[0];
|
||
strncpy(filename, p+1, len);
|
||
filename[len] = '\0';
|
||
ext = globPtr->pattern;
|
||
|
||
if (ext[0] == '\0') {
|
||
/*
|
||
* We don't want any extensions: OK if the filename doesn't
|
||
* have "." in it
|
||
*/
|
||
for (q=filename; *q; q++) {
|
||
if (*q == '.') {
|
||
goto glob_unmatched;
|
||
}
|
||
}
|
||
goto glob_matched;
|
||
}
|
||
|
||
if (Tcl_StringMatch(filename, ext)) {
|
||
goto glob_matched;
|
||
} else {
|
||
goto glob_unmatched;
|
||
}
|
||
|
||
glob_unmatched:
|
||
continue;
|
||
|
||
glob_matched:
|
||
globMatched = 1;
|
||
break;
|
||
}
|
||
|
||
for (mfPtr=clausePtr->macTypes; mfPtr; mfPtr=mfPtr->next) {
|
||
if (pb->hFileInfo.ioFlFndrInfo.fdType == mfPtr->type) {
|
||
macMatched = 1;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (globMatched && macMatched) {
|
||
return MATCHED;
|
||
}
|
||
}
|
||
|
||
return UNMATCHED;
|
||
}
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* Tk_MessageBoxCmd --
|
||
*
|
||
* This procedure implements the MessageBox window for the
|
||
* Mac platform. See the user documentation for details on what
|
||
* it does.
|
||
*
|
||
* Results:
|
||
* A standard Tcl result.
|
||
*
|
||
* Side effects:
|
||
* See user documentation.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
int
|
||
Tk_MessageBoxCmd(
|
||
ClientData clientData, /* Main window associated with interpreter. */
|
||
Tcl_Interp *interp, /* Current interpreter. */
|
||
int argc, /* Number of arguments. */
|
||
char **argv) /* Argument strings. */
|
||
{
|
||
return EvalArgv(interp, "tkMessageBox", argc, argv);
|
||
}
|