1 line
40 KiB
C
Executable File
1 line
40 KiB
C
Executable File
/* Copyright (c) 2017, Computer History Museum
|
|
All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
|
|
the limitations in the disclaimer below) provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
|
disclaimer in the documentation and/or other materials provided with the distribution.
|
|
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
|
|
derived from this software without specific prior written permission.
|
|
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
|
|
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
DAMAGE. */
|
|
|
|
#include "navUtils.h"
|
|
#define FILE_NUM 118
|
|
|
|
#pragma segment navUtils
|
|
|
|
extern Boolean DoUpdate(WindowPtr topWin,EventRecord *event);
|
|
extern OSErr InsertGraphicFile(MyWindowPtr win,FSSpecPtr spec);
|
|
extern OSErr InsertTextFile(MyWindowPtr win, FSSpecPtr spec, Boolean rich, Boolean delSP);
|
|
|
|
typedef struct {
|
|
ZoneAndResFileRec zoneAndResFile;
|
|
// DialogPtr theDialog;
|
|
// short defaultItem;
|
|
Boolean customControlsCreated; // Safety for Nav 1.0
|
|
Boolean insertDefault; // Insert button is the default
|
|
// Boolean insertHit; // The insert button was hit
|
|
// Boolean defaultButtonIsInsert;
|
|
} attachInsertRec, *attachInsertRecPtr, **attachInsertRecHandle;
|
|
|
|
|
|
pascal void attachNavProc (NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, attachInsertRecPtr attachInsertPtr);
|
|
pascal void updateNavProc (NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, ZoneAndResFilePtr zoneAndResFile);
|
|
// OSErr HandleNavEvent (DialogPtr navDialog, EventRecord *event, NavDialogRef context, attachInsertRecPtr attachInsertPtr);
|
|
void NegotiateCustomRectSize (Rect *customRect, short minWidth, short minHeight);
|
|
OSErr SelectNavEntry (DialogPtr navDialog, NavDialogRef context, AEDescList *fileList, attachInsertRecPtr attachInsertPtr);
|
|
OSErr AddDialogItemsToNav (short ditlResID, NavDialogRef context);
|
|
short GetCustomNavItem (NavDialogRef context, short customNavItem);
|
|
pascal Boolean InsertNavFilterProc ( AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode );
|
|
|
|
void SeeIfWeShouldPreloadNav (void)
|
|
|
|
{
|
|
OSErr theError;
|
|
|
|
if (UseNavServices () && PrefIsSet (PREF_PRELOAD_NAV))
|
|
if (theError = NavLoad ())
|
|
DieWithError (NAV_COULD_NOT_LOAD_ERR, theError);
|
|
}
|
|
|
|
|
|
Boolean UseNavServices (void)
|
|
|
|
{
|
|
UInt32 version;
|
|
Boolean useNav;
|
|
|
|
if (HaveOSX ())
|
|
return (true);
|
|
|
|
if (useNav = NavServicesAvailable ()) {
|
|
version = NavLibraryVersion ();
|
|
useNav = (version >= 0x01100000);
|
|
}
|
|
|
|
return (useNav && version);
|
|
}
|
|
|
|
|
|
void GetZoneAndResFile (ZoneAndResFilePtr zoneAndResFile)
|
|
|
|
{
|
|
zoneAndResFile->resFile = CurResFile ();
|
|
}
|
|
|
|
|
|
void SetZoneAndResFile (ZoneAndResFilePtr zoneAndResFile)
|
|
|
|
{
|
|
UseResFile (zoneAndResFile->resFile);
|
|
}
|
|
|
|
|
|
pascal Boolean InsertNavFilterProc ( AEDesc *theItem, void *info, void *callBackUD, NavFilterModes filterMode ) {
|
|
OSErr err = noErr;
|
|
NavFileOrFolderInfo *theInfo;
|
|
FSSpec spec;
|
|
Boolean wasAlias;
|
|
FInfo fInfo;
|
|
|
|
// if it's not a file/folder, we don't want to know about it
|
|
if ( theItem->descriptorType != 'fss ' )
|
|
return false;
|
|
|
|
theInfo = (NavFileOrFolderInfo *) info;
|
|
|
|
if ( theInfo->isFolder )
|
|
return true;
|
|
fInfo.fdType = 0;
|
|
|
|
err = AEGetDescData ( theItem, &spec, sizeof ( spec ));
|
|
if ( noErr == err )
|
|
err = ResolveAliasNoMount ( &spec, &spec, &wasAlias );
|
|
if ( noErr == err )
|
|
err = AFSpGetFInfo ( &spec, &spec, &fInfo );
|
|
|
|
if ( err != noErr )
|
|
return false;
|
|
|
|
// We can always insert text
|
|
if ( fInfo.fdType == 'TEXT' || fInfo.fdType == 'ttro' )
|
|
return true;
|
|
|
|
if ( HasFeature (featureStyleGraphics) && !PrefIsSet ( PREF_SEND_ENRICHED_NEW ) && IsGraphicFile ( &spec ))
|
|
return true;
|
|
|
|
return false; // don't show the file
|
|
}
|
|
|
|
|
|
void CompAttachNav (MyWindowPtr win, Boolean insertDefault)
|
|
|
|
{
|
|
attachInsertRec attachInsert;
|
|
NavReplyRecord theReply;
|
|
NavDialogOptions dialogOptions;
|
|
NavEventUPP eventUPP;
|
|
NavObjectFilterUPP filterUPP;
|
|
FSSpec spec;
|
|
OSErr theError,
|
|
disposeError;
|
|
long count,
|
|
i;
|
|
|
|
Zero (theReply);
|
|
Zero (attachInsert);
|
|
|
|
attachInsert.insertDefault = insertDefault;
|
|
|
|
eventUPP = NewNavEventUPP (attachNavProc);
|
|
filterUPP = NewNavObjectFilterUPP ( InsertNavFilterProc );
|
|
theError = NavGetDefaultDialogOptions (&dialogOptions);
|
|
if (theError)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
|
|
if (!theError) {
|
|
if (HaveOSX ())
|
|
dialogOptions.dialogOptionFlags |= kNavSupportPackages;
|
|
GetRString (dialogOptions.windowTitle, insertDefault ? INSERT_DOCUMENT_NAV_TITLE : ATTACH_DOCUMENT_NAV_TITLE);
|
|
GetRString (dialogOptions.actionButtonLabel, insertDefault ? INSERT_DOCUMENT_ACTION_BUTTON : ATTACH_DOCUMENT_ACTION_BUTTON);
|
|
GetRString (dialogOptions.message, insertDefault ? INSERT_DOCUMENT_INSTRUCTIONS : ATTACH_DOCUMENT_INSTRUCTIONS);
|
|
}
|
|
if (!theError) {
|
|
GetZoneAndResFile (&attachInsert.zoneAndResFile);
|
|
PushCursor(arrowCursor); // Have to do this to clear the watch cursor for OS X
|
|
theError = NavChooseFile (nil, &theReply, &dialogOptions, eventUPP, nil, insertDefault ? filterUPP : nil, nil, &attachInsert);
|
|
PopCursor();
|
|
SetZoneAndResFile (&attachInsert.zoneAndResFile);
|
|
if (theError)
|
|
if (theError == fnfErr)
|
|
WarnUser (ALIAS_TO_NOWHERE, theError);
|
|
else if (theError != userCanceledErr)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
if (!theError && theReply.validRecord) {
|
|
theError = AECountItems (&theReply.selection, &count);
|
|
for (i = 1; !theError && i <= count; ++i) {
|
|
theError = GetSpecFromNthDesc (&theReply.selection, i, &spec);
|
|
if (!theError) {
|
|
// if (attachInsert.insertHit || attachInsert.defaultButtonIsInsert)
|
|
if ( insertDefault )
|
|
{
|
|
if (IsGraphicFile (&spec))
|
|
InsertGraphicFile (win, &spec);
|
|
else
|
|
InsertTextFile (win, &spec, false, false);
|
|
}
|
|
else
|
|
CompAttachSpec (win, &spec);
|
|
}
|
|
}
|
|
}
|
|
disposeError = NavDisposeReply (&theReply);
|
|
if (!theError)
|
|
theError = disposeError;
|
|
}
|
|
|
|
if (filterUPP)
|
|
DisposeNavObjectFilterUPP (filterUPP);
|
|
if (eventUPP)
|
|
DisposeNavEventUPP (eventUPP);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Very annoying note...
|
|
//
|
|
// Selectors are passed in the following order:
|
|
// 1. kNavCBCustomize
|
|
// 2. kNavCBCustomize
|
|
// 3. kNavCBCustomize
|
|
// 4. kNavCBSelectEntry
|
|
// 5. kNavCBSelectEntry
|
|
// 6. kNavCBStart
|
|
//
|
|
// This is not helpful because our custom control is not created until kNavCBStart. Therefore, we
|
|
// can't activate our custom controls when we get the initial kNavCBSelectEntry selectors. (grr... grr...)
|
|
//
|
|
// On top of this, the kNavCBSelectEntry passes a nil dialog pointer!! Yikes! C'mon Nav Service guys...
|
|
//
|
|
|
|
pascal void attachNavProc (NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, attachInsertRecPtr attachInsertPtr)
|
|
|
|
{
|
|
AEDescList fileList;
|
|
ZoneAndResFileRec navZoneAndResFile;
|
|
DialogPtr theDialog;
|
|
OSErr theError;
|
|
|
|
theError = noErr;
|
|
GetZoneAndResFile (&navZoneAndResFile);
|
|
SetZoneAndResFile (&attachInsertPtr->zoneAndResFile);
|
|
theDialog = callBackParms->window ? GetDialogFromWindow (callBackParms->window) : nil;
|
|
switch (callBackSelector) {
|
|
case kNavCBEvent:
|
|
// theError = HandleNavEvent (theDialog, callBackParms->eventData.eventDataParms.event, callBackParms->context, attachInsertPtr);
|
|
break;
|
|
|
|
case kNavCBCustomize :
|
|
// NegotiateCustomRectSize (&callBackParms->customRect, 400, 40);
|
|
break;
|
|
|
|
case kNavCBStart :
|
|
// attachInsertPtr->defaultItem = GetDialogDefaultItem (theDialog);
|
|
// theError = AddDialogItemsToNav (ATTACH_NAV_DITL, callBackParms->context);
|
|
// Hack!! - kNavCBSelectEntry selector comes in before we start and Nav 1.0 is really unfriendly about this
|
|
// if (!theError) {
|
|
attachInsertPtr->customControlsCreated = true;
|
|
theError = NavCustomControl (callBackParms->context, kNavCtlGetSelection, &fileList);
|
|
if (!theError)
|
|
theError = SelectNavEntry (theDialog, callBackParms->context, &fileList, attachInsertPtr);
|
|
// }
|
|
break;
|
|
|
|
case kNavCBSelectEntry:
|
|
// !@#$%^ Nav Services... The window field of the NavCBRecPtr is nil!!!
|
|
// theError = SelectNavEntry (callBackParms->window, callBackParms->context, (AEDescList *) callBackParms->eventData.eventDataParms.param, attachInsertPtr);
|
|
if (attachInsertPtr->customControlsCreated)
|
|
theError = SelectNavEntry (GetDialogFromWindow(FrontWindow()), callBackParms->context, (AEDescList *) callBackParms->eventData.eventDataParms.param, attachInsertPtr);
|
|
break;
|
|
}
|
|
SetZoneAndResFile (&navZoneAndResFile);
|
|
}
|
|
|
|
|
|
pascal void updateNavProc (NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, ZoneAndResFilePtr zoneAndResFile)
|
|
|
|
{
|
|
ZoneAndResFileRec navZoneAndResFile;
|
|
WindowPtr win;
|
|
|
|
GetZoneAndResFile (&navZoneAndResFile);
|
|
SetZoneAndResFile (zoneAndResFile);
|
|
switch (callBackSelector) {
|
|
case kNavCBEvent:
|
|
switch (callBackParms->eventData.eventDataParms.event->what) {
|
|
case updateEvt:
|
|
win = (WindowPtr)callBackParms->eventData.eventDataParms.event->message;
|
|
if (IsMyWindow(win) && (GetWindowKind(win)==dialogKind))
|
|
// Nav Services attempts to udpate dialogs itself by redrawing all the
|
|
// controls which zaps the udpate rgn. Not good enough. We need to
|
|
// do some drawing ourself. This is a problem mainly with the
|
|
// Settings dialog.
|
|
InvalContent(GetWindowMyWindowPtr(win));
|
|
DoUpdate (win, (EventRecord *) callBackParms->eventData.eventDataParms.event);
|
|
break;
|
|
case nullEvent:
|
|
//#ifdef THREADING_ON
|
|
// if (NEED_YIELD)
|
|
// MyYieldToAnyThread();
|
|
//#endif
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
SetZoneAndResFile (&navZoneAndResFile);
|
|
}
|
|
|
|
|
|
#if 0
|
|
OSErr HandleNavEvent (DialogPtr navDialog, EventRecord *event, NavDialogRef context, attachInsertRecPtr attachInsertPtr)
|
|
|
|
{
|
|
DialogItemIndexZeroBased foundItem,
|
|
firstItem;
|
|
GrafPtr savedPort;
|
|
WindowPtr win;
|
|
ControlHandle theControl;
|
|
Point mouseLoc;
|
|
OSErr theError;
|
|
short partCode;
|
|
|
|
theError = noErr;
|
|
switch (event->what) {
|
|
case mouseDown:
|
|
partCode = FindWindow (event->where, &win);
|
|
if (partCode == inContent && navDialog == GetDialogFromWindow (win)) {
|
|
GetPort (&savedPort);
|
|
SetPort (GetDialogPort(navDialog)); // Hack for Nav Services 1.0
|
|
GetMouse (&mouseLoc);
|
|
SetPort (savedPort);
|
|
|
|
foundItem = FindDialogItem (navDialog, mouseLoc);
|
|
if (foundItem >= 0)
|
|
if ((theControl = GetDItemCtl (navDialog, foundItem + 1)) && !GetControlHilite(theControl))
|
|
if (!NavCustomControl (context, kNavCtlGetFirstControlID, &firstItem))
|
|
if (foundItem >= firstItem) {
|
|
attachInsertPtr->insertHit = true;
|
|
NavCustomControl (context, kNavCtlAccept, nil);
|
|
}
|
|
}
|
|
break;
|
|
case updateEvt:
|
|
DoUpdate ((WindowPtr) event->message, event);
|
|
break;
|
|
}
|
|
return (theError);
|
|
}
|
|
#endif
|
|
|
|
void NegotiateCustomRectSize (Rect *customRect, short minWidth, short minHeight)
|
|
|
|
{
|
|
if (!customRect->bottom)
|
|
customRect->bottom = customRect->top + minHeight;
|
|
if (!customRect->right)
|
|
customRect->right = customRect->left + minWidth;
|
|
}
|
|
|
|
|
|
OSErr SelectNavEntry (DialogPtr navDialog, NavDialogRef context, AEDescList *fileList, attachInsertRecPtr attachInsertPtr)
|
|
|
|
{
|
|
// ControlHandle theControl;
|
|
AEKeyword keyword;
|
|
DescType typeCode;
|
|
FInfo info;
|
|
FSSpec spec;
|
|
OSErr theError;
|
|
long actualSize,
|
|
count,
|
|
i;
|
|
Boolean dimInsertButton,
|
|
wasAlias;
|
|
|
|
dimInsertButton = false;
|
|
theError = AECountItems (fileList, &count);
|
|
for (i = 1; !theError && !dimInsertButton && i <= count; ++i) {
|
|
theError = AEGetNthPtr (fileList, i, typeFSS, &keyword, &typeCode,(Ptr) &spec, sizeof(FSSpec), &actualSize);
|
|
if (!theError)
|
|
theError = ResolveAliasNoMount (&spec, &spec, &wasAlias);
|
|
if (!theError)
|
|
theError = AFSpGetFInfo (&spec, &spec, &info);
|
|
if (!theError)
|
|
if (!(info.fdType == 'TEXT' || info.fdType == 'ttro' || (HasFeature (featureStyleGraphics) && !PrefIsSet(PREF_SEND_ENRICHED_NEW) && IsGraphicFile (&spec))))
|
|
dimInsertButton = true;
|
|
}
|
|
if (theError)
|
|
dimInsertButton = true;
|
|
|
|
// if (theControl = GetDItemCtl (navDialog, GetCustomNavItem (context, 1))) {
|
|
// attachInsertPtr->defaultButtonIsInsert = attachInsertPtr->insertDefault && !dimInsertButton;
|
|
// HiliteControl (theControl, dimInsertButton ? 255 : 0);
|
|
// SetDialogDefaultItem (navDialog, attachInsertPtr->defaultButtonIsInsert ? GetCustomNavItem (context, 1) : attachInsertPtr->defaultItem);
|
|
// }
|
|
return (theError);
|
|
}
|
|
|
|
|
|
OSErr AddDialogItemsToNav (short ditlResID, NavDialogRef context)
|
|
|
|
{
|
|
Handle ditl;
|
|
OSErr theError;
|
|
|
|
theError = noErr;
|
|
ditl = GetResource ('DITL', ditlResID);
|
|
|
|
if (!ditl) {
|
|
if (!(theError = ResError ()))
|
|
theError = resNotFound;
|
|
}
|
|
else {
|
|
theError = NavCustomControl (context, kNavCtlAddControlList, ditl);
|
|
ReleaseResource (ditl);
|
|
}
|
|
|
|
return (theError);
|
|
}
|
|
|
|
|
|
short GetCustomNavItem (NavDialogRef context, short customNavItem)
|
|
|
|
{
|
|
DialogItemIndexZeroBased item;
|
|
|
|
item = 0;
|
|
if (!NavCustomControl (context, kNavCtlGetFirstControlID, &item))
|
|
item += customNavItem;
|
|
return (item);
|
|
}
|
|
|
|
|
|
void DoSFOpenNav (short modifiers)
|
|
|
|
{
|
|
static OSType types[] = {kContainerFolderAliasType,'TEXT','ttro',kFakeAppType,STATIONERY_TYPE,'ttro','PREF','eAp1','eAp2','eAp3','eAp4','eAp5','eAp6','eAp7','eAp8','eAp9','eApA','eApB','eApC','eApD','eApE','eApF',SEARCH_FILE_TYPE,REG_FILE_TYPE,0};
|
|
ZoneAndResFileRec zoneAndResFile;
|
|
ProcessSerialNumber psn;
|
|
NavTypeListHandle typeList;
|
|
NavReplyRecord theReply;
|
|
NavDialogOptions dialogOptions;
|
|
NavEventUPP eventUPP;
|
|
AEDescList fileList;
|
|
FSSpec spec;
|
|
FInfo info;
|
|
OSErr theError,
|
|
disposeError;
|
|
short numTypes;
|
|
|
|
Zero (theReply);
|
|
|
|
theError = noErr;
|
|
|
|
NullADList (&fileList, nil);
|
|
|
|
numTypes = CountOSTypes (types, 0);
|
|
|
|
typeList = NewNavTypeList (CREATOR, numTypes, types);
|
|
|
|
eventUPP = NewNavEventUPP (updateNavProc);
|
|
theError = NavGetDefaultDialogOptions (&dialogOptions);
|
|
if (theError)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
|
|
if (!theError) {
|
|
// We get one hell of a nasty popup... let's not, for now.
|
|
dialogOptions.dialogOptionFlags |= kNavNoTypePopup;
|
|
dialogOptions.dialogOptionFlags &= ~kNavAllowMultipleFiles;
|
|
dialogOptions.dialogOptionFlags |= kNavSelectAllReadableItem;
|
|
BlockMoveData (LMGetCurApName(), dialogOptions.clientName, LMGetCurApName()[0] + 1);
|
|
}
|
|
if (!theError) {
|
|
GetZoneAndResFile (&zoneAndResFile);
|
|
PushCursor(arrowCursor); // Have to do this to clear the watch cursor for OS X
|
|
theError = NavGetFile (nil, &theReply, &dialogOptions, eventUPP, nil, nil, typeList, &zoneAndResFile);
|
|
PopCursor();
|
|
SetZoneAndResFile (&zoneAndResFile);
|
|
if (theError && theError != userCanceledErr)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
if (!theError && theReply.validRecord) {
|
|
theError = GetSpecFromNthDesc (&theReply.selection, 1, &spec);
|
|
if (!theError)
|
|
theError = AFSpGetFInfo (&spec, &spec, &info);
|
|
if (!theError)
|
|
if (info.fdType == SETTINGS_TYPE)
|
|
OpenNewSettings (&spec, false, GetNagState());
|
|
else
|
|
SimpleAESend (CurrentPSN (&psn),
|
|
kCoreEventClass,kAEOpenDocuments,nil,kEAEWhenever,
|
|
keyDirectObject,keyEuDesc,SimpleAEList (&fileList, typeFSS, &spec, sizeof (spec), nil),
|
|
nil,nil);
|
|
}
|
|
disposeError = NavDisposeReply (&theReply);
|
|
if (!theError)
|
|
theError = disposeError;
|
|
}
|
|
if (eventUPP)
|
|
DisposeNavEventUPP (eventUPP);
|
|
ZapHandle (typeList);
|
|
DisposeADList (&fileList, nil);
|
|
}
|
|
|
|
|
|
NavTypeListHandle NewNavTypeList (OSType applicationSignature, short numTypes, OSType typeList[])
|
|
|
|
{
|
|
NavTypeListHandle navTypeList;
|
|
|
|
navTypeList = nil;
|
|
|
|
if (numTypes > 0) {
|
|
navTypeList = (NavTypeListHandle) NuHandle (sizeof (NavTypeList) + numTypes * sizeof (OSType));
|
|
if (navTypeList) {
|
|
(*navTypeList)->componentSignature = applicationSignature;
|
|
(*navTypeList)->osTypeCount = numTypes;
|
|
BlockMoveData (typeList, (*navTypeList)->osType, numTypes * sizeof(OSType));
|
|
}
|
|
}
|
|
return (navTypeList);
|
|
}
|
|
|
|
|
|
OSErr GetSpecFromNthDesc (AEDescList *list, short n, FSSpec *spec)
|
|
|
|
{
|
|
AEDesc firstDesc;
|
|
AEKeyword ignoreKeyword;
|
|
OSErr theError,
|
|
disposeError;
|
|
|
|
theError = AEGetNthDesc (list, n, typeFSS, &ignoreKeyword, &firstDesc);
|
|
if (!theError)
|
|
AEGetDescData(&firstDesc,spec,sizeof(*spec));
|
|
disposeError = AEDisposeDesc (&firstDesc);
|
|
return (theError ? theError : disposeError);
|
|
}
|
|
|
|
|
|
Boolean GetFolderNav (char *name, short *volume, long *folder)
|
|
|
|
{
|
|
ZoneAndResFileRec zoneAndResFile;
|
|
NavReplyRecord theReply;
|
|
NavDialogOptions dialogOptions;
|
|
NavEventUPP eventUPP;
|
|
NavObjectFilterUPP objectFilterUPP;
|
|
AEDesc defaultFolderDesc,
|
|
*defaultFolderDescPtr;
|
|
FSSpec spec;
|
|
OSErr theError,
|
|
disposeError;
|
|
Boolean result = false;
|
|
|
|
Zero (theReply);
|
|
|
|
eventUPP = NewNavEventUPP (updateNavProc);
|
|
objectFilterUPP = NewNavObjectFilterUPP (getFolderObjectFilterProc);
|
|
theError = NavGetDefaultDialogOptions (&dialogOptions);
|
|
if (theError)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
|
|
if (!theError) {
|
|
dialogOptions.dialogOptionFlags |= kNavSelectDefaultLocation;
|
|
dialogOptions.dialogOptionFlags |= kNavAllowInvisibleFiles;
|
|
GetRString (dialogOptions.message, NAV_CHOOSE_FOLDER_MESSAGE);
|
|
// Try to make a spec... some routines pass us bogus vRef's though, so we'll try to
|
|
// make a daring (and, probably, temporary) recovery.
|
|
if (theError = FSMakeFSSpec (*volume, *folder, "\p", &spec)) {
|
|
HGetVol (name, volume, folder);
|
|
theError = FSMakeFSSpec (*volume, *folder, "\p", &spec);
|
|
}
|
|
if (!theError)
|
|
theError = AECreateDesc (typeFSS, &spec, sizeof (spec), &defaultFolderDesc);
|
|
defaultFolderDescPtr = theError ? nil : &defaultFolderDesc;
|
|
theError = noErr;
|
|
}
|
|
if (!theError) {
|
|
GetZoneAndResFile (&zoneAndResFile);
|
|
PushCursor(arrowCursor); // Have to do this to clear the watch cursor for OS X
|
|
theError = NavChooseFolder (defaultFolderDescPtr, &theReply, &dialogOptions, eventUPP, objectFilterUPP, &zoneAndResFile);
|
|
PopCursor(); // Have to do this to clear the watch cursor for OS X
|
|
SetZoneAndResFile (&zoneAndResFile);
|
|
if (theError && theError != userCanceledErr)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
if (!theError && theReply.validRecord) {
|
|
theError = GetSpecFromNthDesc (&theReply.selection, 1, &spec);
|
|
if (!theError) {
|
|
*volume = spec.vRefNum;
|
|
*folder = spec.parID;
|
|
GetMyVolName (*volume, name);
|
|
}
|
|
result = true;
|
|
}
|
|
disposeError = NavDisposeReply (&theReply);
|
|
if (!theError)
|
|
theError = disposeError;
|
|
AEDisposeDesc (&defaultFolderDesc);
|
|
}
|
|
if (eventUPP)
|
|
DisposeNavEventUPP (eventUPP);
|
|
if (objectFilterUPP)
|
|
DisposeNavObjectFilterUPP (objectFilterUPP);
|
|
return (result);
|
|
}
|
|
|
|
pascal Boolean getFolderObjectFilterProc (AEDesc *theItem, void *info, ZoneAndResFilePtr zoneAndResFile, NavFilterModes filterMode)
|
|
|
|
{
|
|
AEDesc specDescriptor;
|
|
FSSpec spec;
|
|
CInfoPBRec hfi;
|
|
ZoneAndResFileRec navZoneAndResFile;
|
|
NavFileOrFolderInfo *theInfo;
|
|
long trashDirID;
|
|
short trashVRefNum;
|
|
Boolean display;
|
|
|
|
GetZoneAndResFile (&navZoneAndResFile);
|
|
SetZoneAndResFile (zoneAndResFile);
|
|
|
|
display = false;
|
|
theInfo = (NavFileOrFolderInfo*) info;
|
|
if (theItem->descriptorType == typeFSS)
|
|
if (display = theInfo->isFolder)
|
|
if (!theInfo->visible)
|
|
if (!AECoerceDesc (theItem, typeFSS, &specDescriptor)) {
|
|
AEGetDescData(&specDescriptor, &spec, sizeof(FSSpec));
|
|
if (!FindFolder (spec.vRefNum, kTrashFolderType, false, &trashVRefNum, &trashDirID)) {
|
|
hfi.hFileInfo.ioCompletion = nil;
|
|
hfi.hFileInfo.ioNamePtr = spec.name;
|
|
hfi.hFileInfo.ioVRefNum = spec.vRefNum;
|
|
hfi.hFileInfo.ioDirID = spec.parID;
|
|
hfi.hFileInfo.ioFDirIndex = 0;
|
|
if (!PBGetCatInfoSync ((CInfoPBPtr) &hfi))
|
|
display = (hfi.dirInfo.ioDrDirID == trashDirID);
|
|
}
|
|
}
|
|
SetZoneAndResFile (&navZoneAndResFile);
|
|
return (display);
|
|
}
|
|
|
|
|
|
Boolean MakeUserFindSettingsNav (FSSpecPtr theSpec)
|
|
|
|
{
|
|
static OSType types[] = {'PREF',0};
|
|
ZoneAndResFileRec zoneAndResFile;
|
|
NavTypeListHandle typeList;
|
|
NavReplyRecord theReply;
|
|
NavDialogOptions dialogOptions;
|
|
NavEventUPP eventUPP;
|
|
FSSpec spec;
|
|
OSErr theError,
|
|
disposeError;
|
|
short numTypes;
|
|
Boolean result = true;
|
|
|
|
Zero (theReply);
|
|
|
|
numTypes = CountOSTypes (types, 0);
|
|
|
|
typeList = NewNavTypeList (CREATOR, numTypes, types);
|
|
|
|
eventUPP = NewNavEventUPP (updateNavProc);
|
|
theError = NavGetDefaultDialogOptions (&dialogOptions);
|
|
if (theError)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
|
|
if (!theError) {
|
|
dialogOptions.dialogOptionFlags &= ~kNavAllowMultipleFiles;
|
|
GetRString (dialogOptions.message, NAV_CHOOSE_SETTINGS);
|
|
BlockMoveData (LMGetCurApName(), dialogOptions.clientName, LMGetCurApName()[0] + 1);
|
|
}
|
|
if (!theError) {
|
|
GetZoneAndResFile (&zoneAndResFile);
|
|
PushCursor(arrowCursor); // Have to do this to clear the watch cursor for OS X
|
|
theError = NavChooseFile (nil, &theReply, &dialogOptions, eventUPP, nil, nil, typeList, &zoneAndResFile);
|
|
PopCursor(); // Have to do this to clear the watch cursor for OS X
|
|
SetZoneAndResFile (&zoneAndResFile);
|
|
if (theError && theError != userCanceledErr)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
if (!theError && theReply.validRecord) {
|
|
theError = GetSpecFromNthDesc (&theReply.selection, 1, &spec);
|
|
if (!theError) {
|
|
Root.vRef = spec.vRefNum;
|
|
Root.dirId = spec.parID;
|
|
*theSpec = spec;
|
|
result = false;
|
|
}
|
|
}
|
|
disposeError = NavDisposeReply (&theReply);
|
|
if (!theError)
|
|
theError = disposeError;
|
|
}
|
|
if (eventUPP)
|
|
DisposeNavEventUPP (eventUPP);
|
|
ZapHandle (typeList);
|
|
return (result);
|
|
}
|
|
|
|
|
|
OSErr SFPutOpenNav (FSSpecPtr spec, long creator, long type, short *refN, short ditlID, ScriptCode *script, FSSpecPtr defaultSpec,PStr windowTitle, PStr message)
|
|
|
|
{
|
|
ZoneAndResFileRec zoneAndResFile;
|
|
NavReplyRecord theReply;
|
|
NavDialogOptions dialogOptions;
|
|
NavEventUPP eventUPP;
|
|
OSErr theError,
|
|
disposeError;
|
|
AEDesc defaultFolderDesc,
|
|
*defaultFolderDescPtr;
|
|
|
|
Zero (theReply);
|
|
|
|
switch (ditlID) {
|
|
case SAVEAS_NAV_DITL:
|
|
eventUPP = NewNavEventUPP (saveAsNavProc);
|
|
break;
|
|
default:
|
|
eventUPP = NewNavEventUPP (updateNavProc);
|
|
break;
|
|
}
|
|
|
|
theError = NavGetDefaultDialogOptions (&dialogOptions);
|
|
if (theError)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
if (!theError) {
|
|
dialogOptions.dialogOptionFlags = kNavNoTypePopup | kNavDontAddTranslateItems;
|
|
PCopy (dialogOptions.savedFileName, spec->name);
|
|
if (windowTitle)
|
|
PCopy (dialogOptions.windowTitle, windowTitle);
|
|
if (message)
|
|
PCopy (dialogOptions.message, message);
|
|
GetZoneAndResFile (&zoneAndResFile);
|
|
// Set up default folder (if any)
|
|
if (defaultSpec)
|
|
defaultFolderDescPtr = AECreateDesc (typeFSS, defaultSpec, sizeof (FSSpec), &defaultFolderDesc) ? nil : &defaultFolderDesc;
|
|
else
|
|
defaultFolderDescPtr = nil;
|
|
PushCursor(arrowCursor); // Have to do this to clear the watch cursor for OS X
|
|
theError = NavPutFile (defaultFolderDescPtr, &theReply, &dialogOptions, eventUPP, type, creator, &zoneAndResFile);
|
|
PopCursor(); // Have to do this to clear the watch cursor for OS X
|
|
if (defaultFolderDescPtr)
|
|
AEDisposeDesc(defaultFolderDescPtr);
|
|
SetZoneAndResFile (&zoneAndResFile);
|
|
if (theError && theError != userCanceledErr)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
else {
|
|
if (theReply.validRecord) {
|
|
*script = GetScriptManagerVariable (smKeyScript);
|
|
theError = GetSpecFromNthDesc (&theReply.selection, 1, spec);
|
|
}
|
|
else
|
|
theError = 1;
|
|
}
|
|
disposeError = NavDisposeReply (&theReply);
|
|
if (!theError)
|
|
theError = disposeError;
|
|
}
|
|
if (eventUPP)
|
|
DisposeNavEventUPP (eventUPP);
|
|
return (theError);
|
|
}
|
|
|
|
|
|
pascal void saveAsNavProc (NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, ZoneAndResFilePtr zoneAndResFile)
|
|
|
|
{
|
|
ZoneAndResFileRec navZoneAndResFile;
|
|
DialogPtr theDialog;
|
|
OSErr theError;
|
|
|
|
GetZoneAndResFile (&navZoneAndResFile);
|
|
SetZoneAndResFile (zoneAndResFile);
|
|
theDialog = callBackParms->window ? GetDialogFromWindow (callBackParms->window) : nil;
|
|
|
|
theError = noErr;
|
|
switch (callBackSelector) {
|
|
case kNavCBEvent:
|
|
theError = HandleSaveAsNavEvent (theDialog, callBackParms->eventData.eventDataParms.event, callBackParms->context);
|
|
break;
|
|
case kNavCBCustomize :
|
|
NegotiateCustomRectSize (&callBackParms->customRect, 400, 50);
|
|
break;
|
|
case kNavCBStart :
|
|
theError = AddDialogItemsToNav (SAVEAS_NAV_DITL, callBackParms->context);
|
|
if (!theError) {
|
|
SetDItemState (theDialog, GetCustomNavItem (callBackParms->context, rNavSaveAsGuessParagraphsItem), PrefIsSet(PREF_PARAGRAPHS));
|
|
SetDItemState (theDialog, GetCustomNavItem (callBackParms->context, rNavSaveAsIncludeHeadersItem), !PrefIsSet(PREF_EXCLUDE_HEADERS));
|
|
#ifdef TWO
|
|
if (Stationery == 2) {
|
|
HideDialogItem (theDialog, GetCustomNavItem (callBackParms->context, rNavSaveAsStationeryItem));
|
|
HideDialogItem (theDialog, GetCustomNavItem (callBackParms->context, rNavSaveAsGoToStationeryItem));
|
|
Stationery = 0; // (jp) Since we're hiding the items, we better make sure we don't save as stationery
|
|
}
|
|
else
|
|
SetDItemState (theDialog, GetCustomNavItem (callBackParms->context, rNavSaveAsStationeryItem), Stationery);
|
|
|
|
saveAsCustomHilite (theDialog, callBackParms->context);
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
SetZoneAndResFile (&navZoneAndResFile);
|
|
}
|
|
|
|
void saveAsCustomHilite (DialogPtr navDialog, NavDialogRef context)
|
|
|
|
{
|
|
HiliteControl (GetDItemCtl (navDialog, GetCustomNavItem (context, rNavSaveAsIncludeHeadersItem)), Stationery == 1 ? 255 : 0);
|
|
HiliteControl (GetDItemCtl (navDialog, GetCustomNavItem (context, rNavSaveAsGuessParagraphsItem)), Stationery == 1 ? 255 : 0);
|
|
HiliteControl (GetDItemCtl (navDialog, GetCustomNavItem (context, rNavSaveAsGoToStationeryItem)), Stationery == 1 ? 0 : 255);
|
|
}
|
|
|
|
|
|
OSErr HandleSaveAsNavEvent (DialogPtr navDialog, EventRecord *event, NavDialogRef context)
|
|
|
|
{
|
|
GrafPtr savedPort;
|
|
WindowPtr win;
|
|
AEDesc location;
|
|
FSSpec spec;
|
|
Point mouseLoc;
|
|
OSErr theError;
|
|
short partCode,
|
|
firstItem,
|
|
foundItem;
|
|
|
|
switch (event->what) {
|
|
case mouseDown:
|
|
partCode = FindWindow (event->where, &win);
|
|
if (partCode == inContent && navDialog == GetDialogFromWindow (win)) {
|
|
GetPort (&savedPort);
|
|
SetPort (GetDialogPort(navDialog)); // Hack for Nav Services 1.0
|
|
GetMouse (&mouseLoc);
|
|
SetPort (savedPort);
|
|
|
|
foundItem = FindDialogItem (navDialog, mouseLoc);
|
|
if (foundItem >= 0) {
|
|
firstItem = GetCustomNavItem (context, 1);
|
|
switch (foundItem - firstItem + 2) {
|
|
case rNavSaveAsGuessParagraphsItem:
|
|
SetDItemState (navDialog, foundItem + 1, !GetDItemState (navDialog, foundItem + 1));
|
|
TogglePref(PREF_PARAGRAPHS);
|
|
break;
|
|
case rNavSaveAsIncludeHeadersItem:
|
|
SetDItemState (navDialog, foundItem + 1, !GetDItemState (navDialog, foundItem + 1));
|
|
TogglePref(PREF_EXCLUDE_HEADERS);
|
|
break;
|
|
case rNavSaveAsStationeryItem:
|
|
Stationery = !GetDItemState (navDialog, foundItem + 1);
|
|
SetDItemState (navDialog, foundItem + 1, Stationery);
|
|
saveAsCustomHilite (navDialog, context);
|
|
break;
|
|
case rNavSaveAsGoToStationeryItem:
|
|
theError = FSMakeFSSpec (StationVRef, StationDirId, "\p", &spec);
|
|
if (!theError)
|
|
theError = AECreateDesc (typeFSS, &spec, sizeof (spec), &location);
|
|
if (!theError) {
|
|
theError = NavCustomControl (context, kNavCtlSetLocation, &location);
|
|
AEDisposeDesc (&location);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case updateEvt:
|
|
DoUpdate ((WindowPtr) event->message, event);
|
|
break;
|
|
}
|
|
return (theError);
|
|
}
|
|
|
|
short CountOSTypes (OSType *types, short limit)
|
|
|
|
{
|
|
OSType *tPtr;
|
|
short numTypes;
|
|
|
|
tPtr = types;
|
|
numTypes = 0;
|
|
while (*tPtr++)
|
|
if (++numTypes == limit)
|
|
return (limit);
|
|
return (numTypes);
|
|
}
|
|
|
|
|
|
OSErr GetFileNav (OSType *types, short titleResID, Str255 prompt, short actionButtonLabelResID, Boolean allowPackages, FSSpec *spec, Boolean *good, ProcPtr objectFilterProc)
|
|
|
|
{
|
|
ZoneAndResFileRec zoneAndResFile;
|
|
NavReplyRecord theReply;
|
|
NavDialogOptions dialogOptions;
|
|
NavTypeListHandle typeList;
|
|
NavEventUPP eventUPP;
|
|
NavObjectFilterUPP objectFilterUPP;
|
|
OSErr theError,
|
|
disposeError;
|
|
short numTypes;
|
|
|
|
*good = false;
|
|
Zero (theReply);
|
|
|
|
numTypes = 0;
|
|
typeList = nil;
|
|
if (types) {
|
|
numTypes = CountOSTypes (types, 0);
|
|
typeList = NewNavTypeList (CREATOR, numTypes, types);
|
|
}
|
|
|
|
eventUPP = NewNavEventUPP (updateNavProc);
|
|
objectFilterUPP = objectFilterProc ? NewNavObjectFilterUPP (objectFilterProc) : nil;
|
|
|
|
theError = NavGetDefaultDialogOptions (&dialogOptions);
|
|
if (theError)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
|
|
if (!theError) {
|
|
if (titleResID)
|
|
GetRString (dialogOptions.windowTitle, titleResID);
|
|
if (actionButtonLabelResID)
|
|
GetRString (dialogOptions.actionButtonLabel, actionButtonLabelResID);
|
|
if (allowPackages && HaveOSX ())
|
|
dialogOptions.dialogOptionFlags |= kNavSupportPackages;
|
|
PCopy (dialogOptions.message, prompt);
|
|
GetZoneAndResFile (&zoneAndResFile);
|
|
PushCursor(arrowCursor); // Have to do this to clear the watch cursor for OS X
|
|
theError = NavChooseFile (nil, &theReply, &dialogOptions, eventUPP, nil, objectFilterUPP, typeList, &zoneAndResFile);
|
|
PopCursor(); // Have to do this to clear the watch cursor for OS X
|
|
SetZoneAndResFile (&zoneAndResFile);
|
|
if (theError && theError != userCanceledErr)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
if (!theError) {
|
|
if (*good = theReply.validRecord)
|
|
theError = GetSpecFromNthDesc (&theReply.selection, 1, spec);
|
|
}
|
|
disposeError = NavDisposeReply (&theReply);
|
|
if (!theError)
|
|
theError = disposeError;
|
|
}
|
|
if (eventUPP)
|
|
DisposeNavEventUPP (eventUPP);
|
|
if (objectFilterUPP)
|
|
DisposeNavObjectFilterUPP (objectFilterUPP);
|
|
ZapHandle (typeList);
|
|
return (theError);
|
|
}
|
|
|
|
|
|
pascal Boolean mailboxFileFilterNavProc (AEDesc *theItem, void *info, ZoneAndResFilePtr zoneAndResFile, NavFilterModes filterMode)
|
|
|
|
{
|
|
ZoneAndResFileRec navZoneAndResFile;
|
|
NavFileOrFolderInfo *theInfo;
|
|
FSSpec spec;
|
|
Boolean display;
|
|
|
|
GetZoneAndResFile (&navZoneAndResFile);
|
|
SetZoneAndResFile (zoneAndResFile);
|
|
|
|
display = true;
|
|
theInfo = (NavFileOrFolderInfo*) info;
|
|
if (theItem->descriptorType == typeFSS)
|
|
if (!theInfo->isFolder) {
|
|
AEGetDescData(theItem, &spec, sizeof(FSSpec));
|
|
display = IsMailbox (&spec);
|
|
}
|
|
SetZoneAndResFile (&navZoneAndResFile);
|
|
return (display);
|
|
}
|
|
|
|
|
|
OSErr SFODocNav (FSSpecPtr doc, SFTypeList types, Str255 prompt, FSSpec *spec, SFODocPtr optionsPtr, Boolean *good)
|
|
|
|
{
|
|
NavReplyRecord theReply;
|
|
NavDialogOptions dialogOptions;
|
|
NavTypeListHandle typeList;
|
|
NavEventUPP eventUPP;
|
|
NavObjectFilterUPP objectFilterUPP;
|
|
OSErr theError,
|
|
disposeError;
|
|
short numTypes;
|
|
|
|
*good = false;
|
|
Zero (theReply);
|
|
|
|
numTypes = CountOSTypes (types, 0);
|
|
typeList = NewNavTypeList (CREATOR, numTypes, types);
|
|
|
|
eventUPP = NewNavEventUPP (sfODocNavProc);
|
|
objectFilterUPP = NewNavObjectFilterUPP (sfOdocObjectFilterProc);
|
|
theError = NavGetDefaultDialogOptions (&dialogOptions);
|
|
if (theError)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
|
|
if (!theError) {
|
|
if (HaveOSX ())
|
|
dialogOptions.dialogOptionFlags |= kNavSupportPackages;
|
|
PCopy (dialogOptions.message, prompt);
|
|
GetZoneAndResFile (&optionsPtr->zoneAndResFile);
|
|
PushCursor(arrowCursor); // Have to do this to clear the watch cursor for OS X
|
|
theError = NavChooseFile (nil, &theReply, &dialogOptions, eventUPP, nil, objectFilterUPP, typeList, optionsPtr);
|
|
PopCursor(); // Have to do this to clear the watch cursor for OS X
|
|
SetZoneAndResFile (&optionsPtr->zoneAndResFile);
|
|
if (theError && theError != userCanceledErr)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
if (!theError) {
|
|
if (*good = theReply.validRecord)
|
|
theError = GetSpecFromNthDesc (&theReply.selection, 1, spec);
|
|
}
|
|
disposeError = NavDisposeReply (&theReply);
|
|
if (!theError)
|
|
theError = disposeError;
|
|
}
|
|
if (eventUPP)
|
|
DisposeNavEventUPP (eventUPP);
|
|
if (objectFilterUPP)
|
|
DisposeNavObjectFilterUPP (objectFilterUPP);
|
|
ZapHandle (typeList);
|
|
return (theError);
|
|
}
|
|
|
|
pascal void sfODocNavProc (NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, SFODocPtr optionsPtr)
|
|
|
|
{
|
|
ZoneAndResFileRec navZoneAndResFile;
|
|
DialogPtr theDialog;
|
|
OSErr theError;
|
|
|
|
GetZoneAndResFile (&navZoneAndResFile);
|
|
SetZoneAndResFile (&optionsPtr->zoneAndResFile);
|
|
|
|
theDialog = callBackParms->window ? GetDialogFromWindow (callBackParms->window) : nil;
|
|
theError = noErr;
|
|
switch (callBackSelector) {
|
|
case kNavCBEvent:
|
|
theError = HandleODocNavEvent (theDialog, callBackParms->eventData.eventDataParms.event, callBackParms->context, optionsPtr);
|
|
break;
|
|
|
|
case kNavCBCustomize :
|
|
NegotiateCustomRectSize (&callBackParms->customRect, 400, 40);
|
|
break;
|
|
|
|
case kNavCBStart :
|
|
theError = AddDialogItemsToNav (SFODOC_DITL, callBackParms->context);
|
|
if (!theError)
|
|
if (TypeIsOnList (optionsPtr->type, FINDER_LIST_TYPE) == kTOLOther) {
|
|
optionsPtr->permanently = False;
|
|
SetDItemState (theDialog, GetCustomNavItem (callBackParms->context, rNavOdocAlwaysUseThisApp), false);
|
|
HiliteControl (GetDItemCtl (theDialog, GetCustomNavItem (callBackParms->context, rNavOdocAlwaysUseThisApp)), 255);
|
|
}
|
|
else
|
|
SetDItemState (theDialog, GetCustomNavItem (callBackParms->context, rNavOdocAlwaysUseThisApp), optionsPtr->permanently);
|
|
break;
|
|
}
|
|
SetZoneAndResFile (&navZoneAndResFile);
|
|
}
|
|
|
|
|
|
OSErr HandleODocNavEvent (DialogPtr navDialog, EventRecord *event, NavDialogRef context, SFODocPtr optionsPtr)
|
|
|
|
{
|
|
GrafPtr savedPort;
|
|
WindowPtr win;
|
|
Point mouseLoc;
|
|
OSErr theError;
|
|
short partCode,
|
|
firstItem,
|
|
foundItem;
|
|
|
|
theError = noErr;
|
|
switch (event->what) {
|
|
case mouseDown:
|
|
partCode = FindWindow (event->where, &win);
|
|
if (partCode == inContent && navDialog == GetDialogFromWindow (win)) {
|
|
GetPort (&savedPort);
|
|
SetPort (GetDialogPort(navDialog)); // Hack for Nav Services 1.0
|
|
GetMouse (&mouseLoc);
|
|
SetPort (savedPort);
|
|
|
|
foundItem = FindDialogItem (navDialog, mouseLoc);
|
|
if (foundItem >= 0) {
|
|
firstItem = GetCustomNavItem (context, 1);
|
|
switch (foundItem - firstItem + 2) {
|
|
case rNavOdocUseFinder:
|
|
optionsPtr->finder = True;
|
|
NavCustomControl (context, kNavCtlCancel, nil); // Can't return 'accept' since 'Choose' might be inactive
|
|
break;
|
|
case rNavOdocAlwaysUseThisApp:
|
|
SetDItemState (navDialog, GetCustomNavItem (context, rNavOdocAlwaysUseThisApp), optionsPtr->permanently = !optionsPtr->permanently);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case updateEvt:
|
|
DoUpdate ((WindowPtr) event->message, event);
|
|
break;
|
|
}
|
|
return (theError);
|
|
}
|
|
|
|
|
|
pascal Boolean sfOdocObjectFilterProc (AEDesc *theItem, void *info, SFODocPtr optionsPtr, NavFilterModes filterMode)
|
|
|
|
{
|
|
ZoneAndResFileRec navZoneAndResFile;
|
|
NavFileOrFolderInfo *theInfo;
|
|
FSSpec spec;
|
|
Str31 name;
|
|
OSErr theError;
|
|
long dirId;
|
|
short vRef;
|
|
Boolean display;
|
|
|
|
|
|
GetZoneAndResFile (&navZoneAndResFile);
|
|
SetZoneAndResFile (&optionsPtr->zoneAndResFile);
|
|
|
|
display = true;
|
|
theInfo = (NavFileOrFolderInfo*) info;
|
|
if (theItem->descriptorType == typeFSS)
|
|
if (!theInfo->isFolder) {
|
|
AEGetDescData(theItem, &spec, sizeof(FSSpec));
|
|
if (theInfo->fileAndFolder.fileInfo.finderInfo.fdType == 'adrp') {
|
|
PCopy (name, spec.name);
|
|
vRef = spec.vRefNum;
|
|
dirId = spec.parID;
|
|
if (theError = MyResolveAlias (&vRef, &dirId, name, nil))
|
|
return (false);
|
|
return (CanOpen (TypeToOpen, vRef, dirId, name));
|
|
}
|
|
return (CanOpen (TypeToOpen, spec.vRefNum, spec.parID, spec.name));
|
|
}
|
|
SetZoneAndResFile (&navZoneAndResFile);
|
|
return (display);
|
|
}
|
|
|
|
|
|
OSErr SFURLAppNav (PStr proto, AliasHandle *alias, SFTypeList types, Str255 prompt, FSSpec *spec, URLHookOptionsPtr optionsPtr, Boolean *good)
|
|
|
|
{
|
|
NavReplyRecord theReply;
|
|
NavDialogOptions dialogOptions;
|
|
NavTypeListHandle typeList;
|
|
NavEventUPP eventUPP;
|
|
OSErr theError,
|
|
disposeError;
|
|
short numTypes;
|
|
|
|
*good = false;
|
|
Zero (theReply);
|
|
|
|
numTypes = CountOSTypes (types, 0);
|
|
typeList = NewNavTypeList (CREATOR, numTypes, types);
|
|
|
|
eventUPP = NewNavEventUPP (SFURLAppNavProc);
|
|
theError = NavGetDefaultDialogOptions (&dialogOptions);
|
|
if (theError)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
|
|
if (!theError) {
|
|
if (HaveOSX ())
|
|
dialogOptions.dialogOptionFlags |= kNavSupportPackages;
|
|
PCopy (dialogOptions.message, prompt);
|
|
GetZoneAndResFile (&optionsPtr->zoneAndResFile);
|
|
PushCursor(arrowCursor); // Have to do this to clear the watch cursor for OS X
|
|
theError = NavChooseFile (nil, &theReply, &dialogOptions, eventUPP, nil, nil, typeList, optionsPtr);
|
|
PopCursor(); // Have to do this to clear the watch cursor for OS X
|
|
SetZoneAndResFile (&optionsPtr->zoneAndResFile);
|
|
if (theError && theError != userCanceledErr)
|
|
WarnUser (NAV_GENERAL_ERR, theError);
|
|
if (!theError) {
|
|
if (*good = theReply.validRecord)
|
|
theError = GetSpecFromNthDesc (&theReply.selection, 1, spec);
|
|
}
|
|
disposeError = NavDisposeReply (&theReply);
|
|
if (!theError)
|
|
theError = disposeError;
|
|
}
|
|
if (eventUPP)
|
|
DisposeNavEventUPP (eventUPP);
|
|
ZapHandle (typeList);
|
|
return (theError);
|
|
}
|
|
|
|
|
|
pascal void SFURLAppNavProc (NavEventCallbackMessage callBackSelector, NavCBRecPtr callBackParms, URLHookOptionsPtr optionsPtr)
|
|
|
|
{
|
|
ZoneAndResFileRec navZoneAndResFile;
|
|
DialogPtr theDialog;
|
|
OSErr theError;
|
|
|
|
GetZoneAndResFile (&navZoneAndResFile);
|
|
SetZoneAndResFile (&optionsPtr->zoneAndResFile);
|
|
theDialog = callBackParms->window ? GetDialogFromWindow (callBackParms->window) : nil;
|
|
|
|
theError = noErr;
|
|
switch (callBackSelector) {
|
|
case kNavCBEvent:
|
|
theError = HandleURLAppNavEvent (theDialog, callBackParms->eventData.eventDataParms.event, callBackParms->context, optionsPtr);
|
|
break;
|
|
|
|
case kNavCBCustomize :
|
|
NegotiateCustomRectSize (&callBackParms->customRect, 400, 40);
|
|
break;
|
|
|
|
case kNavCBStart :
|
|
theError = AddDialogItemsToNav (URL_DITL, callBackParms->context);
|
|
if (!theError)
|
|
if (optionsPtr->protocol) {
|
|
optionsPtr->permanently = False;
|
|
SetDItemState (theDialog, GetCustomNavItem (callBackParms->context, rNavURLAppAlwaysUseThisApp), false);
|
|
HiliteControl (GetDItemCtl (theDialog, GetCustomNavItem (callBackParms->context, rNavURLAppAlwaysUseThisApp)), 255);
|
|
}
|
|
else
|
|
SetDItemState (theDialog, GetCustomNavItem (callBackParms->context, rNavURLAppAlwaysUseThisApp), optionsPtr->permanently);
|
|
break;
|
|
}
|
|
SetZoneAndResFile (&navZoneAndResFile);
|
|
}
|
|
|
|
|
|
OSErr HandleURLAppNavEvent (DialogPtr navDialog, EventRecord *event, NavDialogRef context, URLHookOptionsPtr optionsPtr)
|
|
|
|
{
|
|
GrafPtr savedPort;
|
|
WindowPtr win;
|
|
Point mouseLoc;
|
|
OSErr theError;
|
|
short partCode,
|
|
firstItem,
|
|
foundItem;
|
|
|
|
theError = noErr;
|
|
switch (event->what) {
|
|
case mouseDown:
|
|
partCode = FindWindow (event->where, &win);
|
|
if (partCode == inContent && navDialog == GetDialogFromWindow (win)) {
|
|
GetPort (&savedPort);
|
|
SetPort (GetDialogPort(navDialog)); // Hack for Nav Services 1.0
|
|
GetMouse (&mouseLoc);
|
|
SetPort (savedPort);
|
|
|
|
foundItem = FindDialogItem (navDialog, mouseLoc);
|
|
if (foundItem >= 0) {
|
|
firstItem = GetCustomNavItem (context, 1);
|
|
if (foundItem - firstItem + 2 == rNavURLAppAlwaysUseThisApp)
|
|
SetDItemState (navDialog, GetCustomNavItem (context, rNavURLAppAlwaysUseThisApp), optionsPtr->permanently = !optionsPtr->permanently);
|
|
}
|
|
}
|
|
break;
|
|
case updateEvt:
|
|
DoUpdate ((WindowPtr) event->message, event);
|
|
break;
|
|
}
|
|
return (theError);
|
|
}
|