Stroika Library 3.0d18
 
Loading...
Searching...
No Matches
FilteredFilePicker.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4
5#include "Stroika/Foundation/StroikaPreComp.h"
6
7#include <ControlDefinitions.h>
8#include <Controls.h>
9#include <Icons.h>
10
11#include <PP_Resources.h>
12#include <UDesktop.h>
13#include <UExtractFromAEDesc.h>
14#include <UModalDialogs.h>
15#include <UStandardDialogs.h>
16
17#include "LedItResources.h"
18
19#include "FilteredFilePicker.h"
20
21namespace {
22
23#if !TARGET_CARBON
24 static int Append_DITL (DialogPtr dialog, int item_list_ID);
25#endif
26
27 inline MenuHandle GetPopUpMenuHandle (ControlHandle thisControl)
28 {
29#if TARGET_CARBON
30 return ::GetControlPopupMenuHandle (thisControl);
31#else
32 // See LStdPopupMenu::GetMacMenuH() to see if there is a UniversalHeaders _STRICT
33 // way of doing this. There isn't as of PreCW9- LGP 960529
34 Led_RequireNotNil (thisControl);
35 PopupPrivateData** theMenuData = (PopupPrivateData**)(*thisControl)->contrlData;
36 Led_AssertNotNil (theMenuData);
37 Led_EnsureNotNil ((*theMenuData)->mHandle);
38 return ((*theMenuData)->mHandle);
39#endif
40 }
41
42#if qUseNavServices
43 inline NavTypeListHandle CreateNavTypeList (UInt16 inNumTypes, const OSType* inSFTypeList)
44 {
45 NavTypeListHandle list = (NavTypeListHandle)::NewHandleClear ((sizeof (NavTypeList) - sizeof (OSType)) + (inNumTypes * sizeof (OSType)));
46 Execution::ThrowIfNull (list);
47 (*list)->componentSignature = kNavGenericSignature;
48 (*list)->osTypeCount = inNumTypes;
49 memcpy ((*list)->osType, inSFTypeList, inNumTypes * sizeof (OSType));
50 return list;
51 }
52#endif
53
54 // Consider moving to LedSupport?
55 FSSpec CombineDirAndFileName (const FSSpec& dir, ConstStr255Param fileName)
56 {
57 CInfoPBRec pb;
58 memset (&pb, 0, sizeof (pb));
59 FSSpec tmpFSSpec = dir;
60 pb.dirInfo.ioNamePtr = tmpFSSpec.name;
61 pb.dirInfo.ioVRefNum = tmpFSSpec.vRefNum;
62 pb.dirInfo.ioDrDirID = tmpFSSpec.parID;
63 OSErr err = ::PBGetCatInfoSync (&pb);
64
65 FSSpec result;
66
67 err = FSMakeFSSpec (pb.dirInfo.ioVRefNum, pb.dirInfo.ioDrDirID, fileName, &result);
68 return result;
69 }
70}
71
72/*
73 ********************************************************************************
74 ******************************** FilteredSFGetDLog *****************************
75 ********************************************************************************
76 */
77FilteredSFGetDLog::FilteredSFGetDLog (const TypeSpec* typeNameList, size_t nTypes)
78 :
79#if qUseNavServices
80 fCurDialog (NULL)
81 ,
82#endif
83 fTypeSpecs (typeNameList)
84 , fTypeSpecCount (nTypes)
85 , fCurPopupIdx (kBadIndex)
86 , fPopupDLGItemNumber (0)
87#if !qUseNavServices && !TARGET_CARBON
88 , fMainDialog (NULL)
89#endif
90{
91}
92
93bool FilteredSFGetDLog::PickFile (FSSpec* result, bool* typeSpecified, size_t* typeIndex)
94{
95 Led_RequireNotNil (result);
96
97 bool userPickGood = false;
98
99 UDesktop::Deactivate ();
100
101#if qUseNavServices
102 NavDialogCreationOptions options;
103 (void)::memset (&options, 0, sizeof (options));
104 Led_ThrowIfOSStatus (::NavGetDefaultDialogCreationOptions (&options));
105 // Cannot figure out how to tell it to show ALL items - things like .sit files are disabled and we don't get the chance to say otherwise in our FilterProc
106 options.optionFlags |= kNavNoTypePopup;
107 options.optionFlags &= ~kNavAllowMultipleFiles;
108 options.optionFlags &= ~kNavAllowStationery;
109 options.optionFlags &= ~kNavAllowPreviews;
110
111 options.modality = kWindowModalityAppModal;
112
113 Led_SmallStackBuffer<OSType> osTypeBuf (fTypeSpecCount);
114 {
115 for (size_t i = 0; i < fTypeSpecCount; ++i) {
116 osTypeBuf[i] = fTypeSpecs[i].fOSType;
117 }
118 }
119
120 NavTypeListHandle typeList = NULL;
121 NavObjectFilterUPP filterProc = NULL;
122 NavEventUPP eventProc = NULL;
123 NavReplyRecord replyRec;
124 memset (&replyRec, 0, sizeof (replyRec));
125 try {
126 typeList = CreateNavTypeList (fTypeSpecCount, osTypeBuf);
127
128 eventProc = ::NewNavEventUPP (StaticNavEventProc);
129 Led_AssertNotNil (eventProc);
130 filterProc = ::NewNavObjectFilterUPP (StaticNavObjectFilterProc);
131 Led_AssertNotNil (filterProc);
132
133 Led_Assert (fCurDialog == NULL);
134 Led_ThrowIfOSStatus (::NavCreateGetFileDialog (&options, typeList, eventProc, NULL, filterProc, this, &fCurDialog));
135
136 Led_ThrowIfOSStatus (::NavDialogRun (fCurDialog));
137
138 Led_ThrowIfOSStatus (::NavDialogGetReply (fCurDialog, &replyRec));
139
140 userPickGood = replyRec.validRecord;
141 if (userPickGood) {
142 if (typeSpecified != NULL) {
143 *typeSpecified = (fCurPopupIdx != kBadIndex) and (fCurPopupIdx >= 4);
144 }
145 if (typeSpecified != NULL and *typeSpecified and typeIndex != NULL) {
146 *typeIndex = fCurPopupIdx - 4 + 0;
147 }
148 UExtractFromAEDesc::TheFSSpec (replyRec.selection, *result);
149 }
150 }
151 catch (...) {
152 userPickGood = false;
153 }
154 if (replyRec.validRecord) {
155 ::NavDisposeReply (&replyRec);
156 }
157 if (fCurDialog != NULL) {
158 ::NavDialogDispose (fCurDialog);
159 fCurDialog = NULL;
160 }
161 if (typeList != NULL) {
162 ::DisposeHandle (reinterpret_cast<Handle> (typeList));
163 }
164 if (eventProc != NULL) {
165 ::DisposeNavEventUPP (eventProc);
166 }
167 if (filterProc != NULL) {
168 ::DisposeNavObjectFilterUPP (filterProc);
169 }
170
171#elif !TARGET_CARBON
172
173 fMainDialog = NULL; // in case PickFile () called multiple times
174
175 Point where = {-1, -1};
176#if defined(powerc)
177 static RoutineDescriptor dlgProcHook_ = BUILD_ROUTINE_DESCRIPTOR (uppDlgHookYDProcInfo, SFGetDlgHook);
178 RoutineDescriptor* dlgProcHook = &dlgProcHook_;
179 static RoutineDescriptor fileFilter_ = BUILD_ROUTINE_DESCRIPTOR (uppFileFilterYDProcInfo, SFFilterProc);
180 RoutineDescriptor* fileFilter = &fileFilter_;
181#else
182 DlgHookYDProcPtr dlgProcHook = &SFGetDlgHook;
183 FileFilterYDProcPtr fileFilter = &SFFilterProc;
184#endif
185 StandardFileReply sfResult;
186 ::CustomGetFile (fileFilter, -1, NULL, &sfResult, 0, where, dlgProcHook, NULL, NULL, NULL, this);
187
188 if (typeSpecified != NULL) {
189 *typeSpecified = (fCurPopupIdx != kBadIndex) and (fCurPopupIdx >= 4);
190 }
191 if (typeSpecified != NULL and *typeSpecified and typeIndex != NULL) {
192 *typeIndex = fCurPopupIdx - 4 + 0;
193 }
194
195 userPickGood = sfResult.sfGood;
196 if (userPickGood) {
197 *result = sfResult.sfFile;
198 }
199
200#endif
201
202 UDesktop::Activate ();
203 return userPickGood;
204}
205
206#if qUseNavServices
207pascal void FilteredSFGetDLog::StaticNavEventProc (NavEventCallbackMessage inSelector, NavCBRecPtr ioParams, NavCallBackUserData ioUserData)
208{
209 Led_RequireNotNil (ioParams);
210 Led_RequireNotNil (ioUserData);
211 FilteredSFGetDLog* dlog = reinterpret_cast<FilteredSFGetDLog*> (ioUserData);
212 dlog->NavEventProc (inSelector, ioParams);
213}
214
215void FilteredSFGetDLog::NavEventProc (NavEventCallbackMessage inSelector, NavCBRecPtr ioParams)
216{
217 Led_RequireNotNil (ioParams);
218 try {
219 switch (inSelector) {
220 case kNavCBCustomize: {
221 /*
222 * Make room for the custom controls.
223 */
224 if (ioParams->customRect.right == 0 and ioParams->customRect.bottom == 0) {
225 ioParams->customRect.right = ioParams->customRect.left + 200;
226 ioParams->customRect.bottom = ioParams->customRect.top + 20;
227 }
228 } break;
229 case kNavCBStart: {
230 /*
231 * Add the custom dialog items (popup).
232 */
233 {
234 Handle dlogItems = ::GetResource ('DITL', kOpenDLOGAdditionItems_DialogID);
235 Led_ThrowIfOSErr (::NavCustomControl (fCurDialog, kNavCtlAddControlList, dlogItems));
236 ::ReleaseResource (dlogItems);
237 }
238
239 {
240 SInt16 numItems = 0;
241 Led_ThrowIfOSErr (::NavCustomControl (fCurDialog, kNavCtlGetFirstControlID, &numItems));
242 fPopupDLGItemNumber = numItems + 1;
243 }
244
245 DialogRef dialog = ::GetDialogFromWindow (ioParams->window);
246
247 Handle h;
248 short i;
249 Rect r;
250 ::GetDialogItem (dialog, fPopupDLGItemNumber, &i, &h, &r);
251 MenuHandle mm = GetPopUpMenuHandle ((ControlHandle)h);
252 for (size_t i = 0; i < fTypeSpecCount; ++i) {
253 Str255 tmp;
254 tmp[0] = strlen (fTypeSpecs[i].fName);
255 memcpy (&tmp[1], fTypeSpecs[i].fName, tmp[0]);
256 AppendMenu (mm, "\pHiMom");
257 SetMenuItemText (mm, ::CountMenuItems (mm), tmp);
258 }
259 ::SetControlMinimum ((ControlHandle)h, 1);
260 ::SetControlMaximum ((ControlHandle)h, i);
261 ::SetControlValue ((ControlHandle)h, 1);
262 fCurPopupIdx = 1;
263 } break;
264 case kNavCBEvent: {
265 if (ioParams->eventData.eventDataParms.event->what == mouseDown) {
266 DialogRef dialog = ::GetDialogFromWindow (ioParams->window);
267 Handle h;
268 short i;
269 Rect r;
270 ::GetDialogItem (dialog, fPopupDLGItemNumber, &i, &h, &r);
271 int newValue = ::GetControlValue ((ControlHandle)h);
272 if (newValue != fCurPopupIdx) {
273 fCurPopupIdx = newValue;
274 // Force a refresh of the listbox/explorer area based on newly chosen filter
275 Led_ThrowIfOSErr (::NavCustomControl (fCurDialog, kNavCtlBrowserRedraw, NULL));
276 }
277 }
278 } break;
279 }
280 }
281 catch (...) {
282 } // Can't throw back through the Toolbox
283}
284
285pascal Boolean FilteredSFGetDLog::StaticNavObjectFilterProc (AEDesc* theItem, void* info, void* callBackUD, NavFilterModes filterMode)
286{
287 Led_RequireNotNil (theItem);
288 Led_RequireNotNil (info);
289 Led_RequireNotNil (callBackUD);
290 FilteredSFGetDLog* dlog = reinterpret_cast<FilteredSFGetDLog*> (callBackUD);
291 return dlog->NavObjectFilterProc (theItem, info, filterMode);
292}
293
294bool FilteredSFGetDLog::NavObjectFilterProc (AEDesc* theItem, void* info, NavFilterModes /*filterMode*/)
295{
296 Led_RequireNotNil (theItem);
297 Led_RequireNotNil (info);
298 bool allow = true;
299 if ((theItem->descriptorType == typeFSS) or (theItem->descriptorType == typeFSRef)) {
300 NavFileOrFolderInfo* fileOrFolderInfo = reinterpret_cast<NavFileOrFolderInfo*> (info);
301 if (fileOrFolderInfo->isFolder) {
302 allow = true; // not sure if this should be TRUE or FALSE???
303 }
304 else {
305 allow = false;
306 OSType thisFileType = fileOrFolderInfo->fileAndFolder.fileInfo.finderInfo.fdType;
307 switch (fCurPopupIdx) {
308 case 1: {
309 // TRUE iff in list of types...
310 for (size_t i = 0; i < fTypeSpecCount; ++i) {
311 if (thisFileType == fTypeSpecs[i].fOSType) {
312 allow = true;
313 break;
314 }
315 }
316 } break;
317
318 case 2: {
319 allow = true; // ALL
320 } break;
321
322 default: {
323 // true only if type matches THIS entry
324 Led_Assert (fCurPopupIdx >= 4);
325 if (thisFileType == fTypeSpecs[fCurPopupIdx - 4].fOSType) {
326 allow = true;
327 }
328 } break;
329 }
330 }
331 }
332 return allow;
333}
334#endif
335
336#if !qUseNavServices && !TARGET_CARBON
337pascal short FilteredSFGetDLog::SFGetDlgHook (short item, DialogPtr dialog, void* myData)
338{
339 FilteredSFGetDLog* sThis = (FilteredSFGetDLog*)myData;
340
341 // Must check sThis->fMainDialog==NULL cuz this same hook function gets called when SFGetFile
342 // launches other SUB-Dialogs - like file is locked warning - and we don't want the popup added
343 // to that dialog as well.
344 if (item == sfHookFirstCall and sThis->fMainDialog == NULL) {
345 sThis->fMainDialog = dialog;
346 sThis->fPopupDLGItemNumber = Append_DITL (dialog, kOpenDLOGAdditionItems_DialogID);
347 Handle h;
348 short i;
349 Rect r;
350 ::GetDialogItem (dialog, sThis->fPopupDLGItemNumber, &i, &h, &r);
351 MenuHandle mm = GetPopUpMenuHandle ((ControlHandle)h);
352 for (size_t i = 0; i < sThis->fTypeSpecCount; ++i) {
353 Str255 tmp;
354 tmp[0] = strlen (sThis->fTypeSpecs[i].fName);
355 memcpy (&tmp[1], sThis->fTypeSpecs[i].fName, tmp[0]);
356 AppendMenu (mm, "\pHiMom");
357 SetMenuItemText (mm, ::CountMenuItems (mm), tmp);
358 }
359 ::SetControlMinimum ((ControlHandle)h, 1);
360 ::SetControlMaximum ((ControlHandle)h, i);
361 ::SetControlValue ((ControlHandle)h, 1);
362 sThis->fCurPopupIdx = 1;
363 }
364 else if (sThis->fMainDialog == dialog) {
365 Handle h;
366 short i;
367 Rect r;
368 ::GetDialogItem (dialog, sThis->fPopupDLGItemNumber, &i, &h, &r);
369 int newValue = ::GetControlValue ((ControlHandle)h);
370 if (newValue != sThis->fCurPopupIdx) {
371 sThis->fCurPopupIdx = newValue;
372 return sfHookRebuildList;
373 }
374 }
375
376 return item;
377}
378
379pascal Boolean FilteredSFGetDLog::SFFilterProc (CInfoPBPtr pb, void* myData)
380{
381 FilteredSFGetDLog* sThis = (FilteredSFGetDLog*)myData;
382
383 Led_AssertNotNil (pb);
384
385 // Never filter directories
386 if (pb->dirInfo.ioFlAttrib & ioDirMask) {
387 return false;
388 }
389
390 OSType thisFileType = pb->hFileInfo.ioFlFndrInfo.fdType;
391 bool filtered = true;
392 switch (sThis->fCurPopupIdx) {
393 case 1: {
394 // TRUE iff in list of types...
395 for (size_t i = 0; i < sThis->fTypeSpecCount; ++i) {
396 if (thisFileType == sThis->fTypeSpecs[i].fOSType) {
397 filtered = false;
398 break;
399 }
400 }
401 } break;
402
403 case 2: {
404 filtered = false; // ALL
405 } break;
406
407 default: {
408 // true only if type matches THIS entry
409 if (thisFileType == sThis->fTypeSpecs[sThis->fCurPopupIdx - 4].fOSType) {
410 filtered = false;
411 }
412 } break;
413 }
414
415 return filtered;
416}
417#endif
418
419/*
420 ********************************************************************************
421 ******************************** FilteredSFPutDLog *****************************
422 ********************************************************************************
423 */
424FilteredSFPutDLog::FilteredSFPutDLog (const TypeSpec* typeNameList, size_t nTypes)
425 :
426#if qUseNavServices
427 fCurDialog (NULL)
428 ,
429#endif
430 fTypeSpecs (typeNameList)
431 , fTypeSpecCount (nTypes)
432 , fCurPopupIdx (kBadIndex)
433 , fPopupDLGItemNumber (0)
434#if !qUseNavServices && !TARGET_CARBON
435 , fMainDialog (NULL)
436#endif
437{
438}
439
440bool FilteredSFPutDLog::PickFile (ConstStr255Param defaultName, FSSpec* result, bool* replacing, size_t* typeIndex)
441{
442 Led_RequireNotNil (result);
443 Led_RequireNotNil (replacing);
444
445 bool userPickGood = false;
446
447 if (typeIndex != NULL) {
448 fCurPopupIdx = *typeIndex - 0 + 1;
449 }
450
451 UDesktop::Deactivate ();
452
453#if qUseNavServices
454
455 NavDialogCreationOptions options;
456 (void)::memset (&options, 0, sizeof (options));
457 Led_ThrowIfOSStatus (::NavGetDefaultDialogCreationOptions (&options));
458 // Cannot figure out how to tell it to show ALL items - things like .sit files are disabled and we don't get the chance to say otherwise in our FilterProc
459 options.optionFlags |= kNavNoTypePopup;
460 options.optionFlags &= ~kNavAllowMultipleFiles;
461 options.optionFlags &= ~kNavAllowStationery;
462 options.optionFlags &= ~kNavAllowPreviews;
463
464 options.modality = kWindowModalityAppModal;
465
466 Led_SmallStackBuffer<OSType> osTypeBuf (fTypeSpecCount);
467 {
468 for (size_t i = 0; i < fTypeSpecCount; ++i) {
469 osTypeBuf[i] = fTypeSpecs[i].fOSType;
470 }
471 }
472
473 NavEventUPP eventProc = NULL;
474 NavReplyRecord replyRec;
475 try {
476 eventProc = ::NewNavEventUPP (StaticNavEventProc);
477 Led_AssertNotNil (eventProc);
478
479 options.saveFileName = ::CFStringCreateWithPascalString (NULL, defaultName, ::CFStringGetSystemEncoding ());
480
481 Led_Assert (fCurDialog == NULL);
482 Led_ThrowIfOSStatus (::NavCreatePutFileDialog (&options, 'TEXT', kApplicationSignature, eventProc, this, &fCurDialog));
483
484 Led_ThrowIfOSStatus (::NavDialogRun (fCurDialog));
485
486 Led_ThrowIfOSStatus (::NavDialogGetReply (fCurDialog, &replyRec));
487
488 userPickGood = replyRec.validRecord;
489 if (userPickGood) {
490 *replacing = replyRec.replacing;
491
492 FSSpec folderSpec;
493 UExtractFromAEDesc::TheFSSpec (replyRec.selection, folderSpec);
494
495 /*
496 * Wierd thing - but for NavCreatePutFileDialog - NavDialogGetReply appears to just return the parent
497 * directory for the chosen file. I saw some reference to this in the MWERKS/Apple header files, but nowhere
498 * in the actual docs on Apples website. Sigh... LGP 2003-03-12
499 */
500 Str255 tmpFileName;
501 tmpFileName[0] = 0; // in case below fails...
502 ::CFStringGetPascalString (replyRec.saveFileName, tmpFileName, sizeof (tmpFileName), ::CFStringGetSystemEncoding ());
503 *result = CombineDirAndFileName (folderSpec, tmpFileName);
504 }
505 }
506 catch (...) {
507 userPickGood = false;
508 }
509 if (replyRec.validRecord) {
510 ::NavDisposeReply (&replyRec);
511 }
512 if (fCurDialog != NULL) {
513 ::NavDialogDispose (fCurDialog);
514 fCurDialog = NULL;
515 }
516 if (eventProc != NULL) {
517 ::DisposeNavEventUPP (eventProc);
518 }
519
520#elif !TARGET_CARBON
521
522 fMainDialog = NULL; // in case PickFile () called multiple times
523
524 Str255 saveAsPrompt;
525 ::GetIndString (saveAsPrompt, STRx_Standards, str_SaveAs);
526
527 Point where = {-1, -1};
528#if defined(powerc)
529 static RoutineDescriptor dlgProcHook_ = BUILD_ROUTINE_DESCRIPTOR (uppDlgHookYDProcInfo, SFPutDlgHook);
530 RoutineDescriptor* dlgProcHook = &dlgProcHook_;
531#else
532 DlgHookYDProcPtr dlgProcHook = &SFPutDlgHook;
533#endif
534 StandardFileReply sfResult;
535 ::CustomPutFile (saveAsPrompt, defaultName, &sfResult, 0, where, dlgProcHook, NULL, NULL, NULL, this);
536
537 userPickGood = sfResult.sfGood;
538 if (userPickGood) {
539 *result = sfResult.sfFile;
540 *replacing = sfResult.sfReplacing;
541 }
542
543#endif
544
545 UDesktop::Activate ();
546
547 if (typeIndex != NULL) {
548 *typeIndex = fCurPopupIdx - 1;
549 }
550
551 return userPickGood;
552}
553
554#if qUseNavServices
555pascal void FilteredSFPutDLog::StaticNavEventProc (NavEventCallbackMessage inSelector, NavCBRecPtr ioParams, NavCallBackUserData ioUserData)
556{
557 Led_RequireNotNil (ioParams);
558 Led_RequireNotNil (ioUserData);
559 FilteredSFPutDLog* dlog = reinterpret_cast<FilteredSFPutDLog*> (ioUserData);
560 dlog->NavEventProc (inSelector, ioParams);
561}
562
563void FilteredSFPutDLog::NavEventProc (NavEventCallbackMessage inSelector, NavCBRecPtr ioParams)
564{
565 Led_RequireNotNil (ioParams);
566 try {
567 switch (inSelector) {
568 case kNavCBCustomize: {
569 /*
570 * Make room for the custom controls.
571 */
572 if (ioParams->customRect.right == 0 and ioParams->customRect.bottom == 0) {
573 ioParams->customRect.right = ioParams->customRect.left + 200;
574 ioParams->customRect.bottom = ioParams->customRect.top + 20;
575 }
576 } break;
577 case kNavCBStart: {
578 /*
579 * Add the custom dialog items (popup).
580 */
581 {
582 Handle dlogItems = ::GetResource ('DITL', kSaveDLOGAdditionItems_DialogID);
583 Led_ThrowIfOSErr (::NavCustomControl (fCurDialog, kNavCtlAddControlList, dlogItems));
584 ::ReleaseResource (dlogItems);
585 }
586
587 {
588 SInt16 numItems = 0;
589 Led_ThrowIfOSErr (::NavCustomControl (fCurDialog, kNavCtlGetFirstControlID, &numItems));
590 fPopupDLGItemNumber = numItems + 1;
591 }
592
593 DialogRef dialog = ::GetDialogFromWindow (ioParams->window);
594
595 Handle h;
596 short i;
597 Rect r;
598 ::GetDialogItem (dialog, fPopupDLGItemNumber, &i, &h, &r);
599 MenuHandle mm = GetPopUpMenuHandle ((ControlHandle)h);
600 for (size_t i = 0; i < fTypeSpecCount; ++i) {
601 Str255 tmp;
602 tmp[0] = strlen (fTypeSpecs[i].fName);
603 memcpy (&tmp[1], fTypeSpecs[i].fName, tmp[0]);
604 AppendMenu (mm, "\pHiMom");
605 SetMenuItemText (mm, ::CountMenuItems (mm), tmp);
606 }
607 ::SetControlMinimum ((ControlHandle)h, 1);
608 ::SetControlMaximum ((ControlHandle)h, i);
609 ::SetControlValue ((ControlHandle)h, 1);
610 ::SetControlValue ((ControlHandle)h, (fCurPopupIdx == kBadIndex) ? 1 : fCurPopupIdx);
611 } break;
612 case kNavCBEvent: {
613 if (ioParams->eventData.eventDataParms.event->what == mouseDown) {
614 DialogRef dialog = ::GetDialogFromWindow (ioParams->window);
615 Handle h;
616 short i;
617 Rect r;
618 ::GetDialogItem (dialog, fPopupDLGItemNumber, &i, &h, &r);
619 int newValue = ::GetControlValue ((ControlHandle)h);
620 if (newValue != fCurPopupIdx) {
621 fCurPopupIdx = newValue;
622 // Force a refresh of the listbox/explorer area based on newly chosen filter
623 Led_ThrowIfOSErr (::NavCustomControl (fCurDialog, kNavCtlBrowserRedraw, NULL));
624 }
625 }
626 } break;
627 }
628 }
629 catch (...) {
630 } // Can't throw back through the Toolbox
631}
632#endif
633
634#if !qUseNavServices && !TARGET_CARBON
635pascal short FilteredSFPutDLog::SFPutDlgHook (short item, DialogPtr dialog, void* myData)
636{
637 FilteredSFPutDLog* sThis = (FilteredSFPutDLog*)myData;
638
639 // Must check sThis->fMainDialog==NULL cuz this same hook function gets called when SFGetFile
640 // launches other SUB-Dialogs - like file is locked warning - and we don't want the popup added
641 // to that dialog as well.
642 if (item == sfHookFirstCall and sThis->fMainDialog == NULL) {
643 sThis->fMainDialog = dialog;
644 sThis->fPopupDLGItemNumber = Append_DITL (dialog, kSaveDLOGAdditionItems_DialogID);
645 Handle h;
646 short i;
647 Rect r;
648 ::GetDialogItem (dialog, sThis->fPopupDLGItemNumber, &i, &h, &r);
649 MenuHandle mm = GetPopUpMenuHandle ((ControlHandle)h);
650 for (size_t i = 0; i < sThis->fTypeSpecCount; ++i) {
651 Str255 tmp;
652 tmp[0] = strlen (sThis->fTypeSpecs[i].fName);
653 memcpy (&tmp[1], sThis->fTypeSpecs[i].fName, tmp[0]);
654 ::AppendMenu (mm, "\pHiMom");
655 ::SetMenuItemText (mm, ::CountMenuItems (mm), tmp);
656 }
657 ::SetControlMinimum ((ControlHandle)h, 1);
658 ::SetControlMaximum ((ControlHandle)h, i);
659 ::SetControlValue ((ControlHandle)h, (sThis->fCurPopupIdx == kBadIndex) ? 1 : sThis->fCurPopupIdx);
660 }
661 else if (sThis->fMainDialog == dialog) {
662 Handle h;
663 short i;
664 Rect r;
665 ::GetDialogItem (dialog, sThis->fPopupDLGItemNumber, &i, &h, &r);
666 sThis->fCurPopupIdx = ::GetControlValue ((ControlHandle)h);
667 }
668 return item;
669}
670#endif
671
672namespace {
673
674#if !TARGET_CARBON
675 /*
676 ********************************************************************************
677 ********************************** Append_DITL *********************************
678 ********************************************************************************
679 */
680 static int Append_DITL (DialogPtr dialog, int item_list_ID)
681 {
682#if PRAGMA_ALIGN_SUPPORTED
683#pragma options align = mac68k
684#endif
685 struct DialogItem {
686 Handle handle; // handle or procedure pointer for this item
687 Rect bounds; // display rectangle for this item
688 char type; // item type - 1
689 char data[1]; // length byte of data
690 };
691 struct ItemList {
692 short max_index; // number of items - 1
693 DialogItem items[1]; // first item in the array
694 };
695 union ByteAccess {
696 short integer;
697 char bytes[2];
698 };
699 Point offset;
700 Rect max_rect;
701 ItemList** append_item_list; /* handle to DITL being appended */
702 DialogItem* item; /* pointer to item being appended */
703 ItemList** dlg_item_list; /* handle to DLOG's item list */
704 int first_item;
705 int new_items, data_size, i;
706 ByteAccess usb;
707 OSErr err;
708
709 /*
710 Using the original DLOG
711
712 1. Remember the original window Size.
713 2. Set the offset Point to be the bottom of the original window.
714 3. Subtract 5 pixels from bottom and right, to be added
715 back later after we have possibly expanded window.
716 4. Get working Handle to original item list.
717 5. Calculate our first item number to be returned to caller.
718 6. Get locked Handle to DITL to be appended.
719 7. Calculate count of new items.
720 */
721 Led_AssertNotNil (dialog);
722
723 max_rect = ((DialogPeek)dialog)->window.port.portRect;
724 offset.v = max_rect.bottom;
725 offset.h = 0;
726 max_rect.bottom -= 5;
727 max_rect.right -= 5;
728
729 dlg_item_list = (ItemList**)((DialogPeek)dialog)->items;
730 first_item = (**dlg_item_list).max_index + 2;
731
732 append_item_list = (ItemList**)GetResource ('DITL', item_list_ID);
733 if (append_item_list == NULL)
734 return first_item;
735
736 HLock ((Handle)append_item_list);
737 new_items = (**append_item_list).max_index + 1;
738
739 /*
740 For each item,
741 1. Offset the rectangle to follow the original window.
742 2. Make the original window larger if necessary.
743 3. fill in item handle according to type.
744 */
745 item = (**append_item_list).items;
746 for (i = 0; i < new_items; ++i) {
747 OffsetRect (&item->bounds, offset.h, offset.v);
748 UnionRect (&item->bounds, &max_rect, &max_rect);
749 usb.integer = 0;
750 usb.bytes[1] = item->data[0];
751
752 switch (item->type & 0x7F) {
753 case ctrlItem + btnCtrl:
754 case ctrlItem + chkCtrl:
755 case ctrlItem + radCtrl:
756 item->handle = (Handle)NewControl ((DialogPtr)dialog, &item->bounds, (StringPtr)item->data, true, 0, 0, 1, item->type & 0x03, 0);
757 break;
758
759 case ctrlItem + resCtrl: {
760 item->handle = (Handle)GetNewControl (*(short*)(item->data + 1), (DialogPtr)dialog);
761 (**(ControlHandle)item->handle).contrlRect = item->bounds;
762 } break;
763
764 case statText:
765 case editText:
766 err = PtrToHand (item->data + 1, &item->handle, usb.integer);
767 break;
768
769 case iconItem:
770 item->handle = GetIcon (*(short*)(item->data + 1));
771 break;
772
773 case picItem:
774 item->handle = (Handle)GetPicture (*(short*)(item->data + 1));
775 break;
776
777 default:
778 item->handle = NULL;
779 }
780
781 data_size = (usb.integer + 1) & 0xFFFE;
782 item = (DialogItem*)((char*)item + data_size + sizeof (DialogItem));
783 }
784
785 err = PtrAndHand ((**append_item_list).items, (Handle)dlg_item_list, GetHandleSize ((Handle)append_item_list));
786 (**dlg_item_list).max_index += new_items;
787 HUnlock ((Handle)append_item_list);
788 ReleaseResource ((Handle)append_item_list);
789
790 max_rect.bottom += 5;
791 max_rect.right += 5;
792 SizeWindow ((WindowPtr)dialog, max_rect.right, max_rect.bottom, true);
793
794 return first_item;
795#if PRAGMA_ALIGN_SUPPORTED
796#pragma options align = reset
797#endif
798 }
799#endif
800}