home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 January: Mac OS SDK / Dev.CD Jan 00 SDK1.toast / Development Kits / Mac OS / Multiprocessing 2.0 SDK / Sample Code / SortPictsMP ƒ / Sprocket / Lib / DialogUtils.cp < prev    next >
Encoding:
Text File  |  1999-08-03  |  10.0 KB  |  375 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg
  9.  
  10.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.      
  14.          <5>    11/16/94    DRF        Added explicit #include <SegLoad.h> for latest universal
  15.                                     headers. Also added cast to keep MPW CFront happier.
  16.          <4>    11/16/94    DRF        Add StdFilterProc for THINK C.
  17.          <3>     9/27/94    DRF         AppLib.h is now Sprocket.h
  18.          <2>      9/9/94    DRF        Reordered headers and removed redundant #includes.
  19.  */
  20.  
  21. #include "Sprocket.h"
  22. extern pascal void ExitToShell(void );
  23.  
  24. #include <Fonts.h>
  25. #include <Resources.h>
  26. #include <TextUtils.h>
  27. #include <Threads.h>        //    For YieldToAnyThread()
  28. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  29. #include <SegLoad.h>        //    For ExitToShell()
  30. #include <Controls.h>
  31.  
  32. //    Some types which should probably be defined in <Dialogs.h>
  33. //    NOTE: These must be aligned on 2-byte boundaries
  34. #if defined(powerc) || defined (__powerc)
  35. #pragma options align=mac68k
  36. #endif
  37.  
  38. struct DialogItem
  39.     {
  40.     long    usedByDialogManager;
  41.     Rect    boundsRect;
  42.     char    type;
  43.     char    length;
  44.     };
  45.  
  46. struct DialogItemList            //    a.k.a. a 'DITL'
  47.     {
  48.     short        count;
  49.     DialogItem    firstItem[1];
  50.     };
  51.  
  52. //    Restore default alignment
  53. #if defined(powerc) || defined(__powerc)
  54. #pragma options align=reset
  55. #endif
  56.  
  57. typedef    DialogItem        *DialogItemPtr;
  58. typedef    DialogItemList    **DialogItemListHandle;
  59. typedef    DialogTemplate    **DialogTemplateHandle;
  60.  
  61. #ifndef    powerc
  62. #ifdef    __SC__
  63.  
  64. extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
  65.  THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
  66.  
  67. pascal Boolean
  68. StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  69.     {
  70.     ModalFilterUPP    filterUPP;
  71.  
  72.     //    Dialogs.h
  73.     
  74.     (void) GetStdFilterProc(&filterUPP);
  75.  
  76.     return    CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
  77.     }
  78.  
  79. #endif
  80. #endif
  81.  
  82. //    private function Prototypes
  83.  
  84. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  85. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  86. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  87. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  88.  
  89. ///////////////////////////////////////////////////////////
  90. //
  91. //    StandardAlert
  92. //
  93. //    An alternative to Alert() which uses the extended
  94. //    Dialog Manager capabilities.
  95. //
  96. //    I’m not sure we really need this call, but it seems
  97. //    to do the trick just fine.
  98.  
  99. short
  100. StandardAlert(    short dlogID,
  101.                 short defaultItem,                /* = ok */
  102.                 short cancelItem,                /* = 0 */
  103.                 ModalFilterUPP customFilterProc    /* = nil */)
  104.     {
  105.     DialogPtr        theDialog;
  106.     short            itemHit = 0;
  107.     ModalFilterUPP    filterToUse;
  108.     
  109.     HiliteWindowsForModalDialog(false);
  110.  
  111.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  112.     if (defaultItem)
  113.         SetDialogDefaultItem(theDialog,defaultItem);
  114.     if (cancelItem)
  115.         SetDialogCancelItem(theDialog,cancelItem);
  116.  
  117.     if (customFilterProc)
  118.         filterToUse = customFilterProc;
  119.     else
  120.         filterToUse = StandardDialogFilter;
  121.  
  122.     do
  123.         ModalDialog(filterToUse,&itemHit);
  124.     while (itemHit == 0);
  125.     
  126.     DisposeDialog(theDialog);
  127.  
  128.     HiliteWindowsForModalDialog(true);
  129.  
  130.     return itemHit;
  131.     }
  132.  
  133. ///////////////////////////////////////////////////////////
  134. //
  135. //    ErrorAlert
  136. //
  137. //    A nice error reporting routine which presents an
  138. //    auto-sized alert box containing the supplied text.
  139. //
  140. //    NOTE:    This routine ASSUMES the following 'DITL'
  141. //            structure:
  142. //
  143. //            item #1 : an “OK” button
  144. //            item #2 : a static text item, somewhere above #1
  145. //
  146. //    NOTE:    We probably need to worry more about low
  147. //            memory conditions-- this can probably
  148. //            be handled by a custom GrowZoneProc and
  149. //            reserve memory area large enough to hold
  150. //            all the space we’d need.
  151. //
  152.  
  153. void
  154. ErrorAlert(short stringList,short whichString)
  155.     {
  156.     Str255                    errorString;
  157.     GrafPtr                    oldPort,windowMgrPort;
  158.     short                    oldFont;
  159.     DialogTemplateHandle    errorDialogTemplate;
  160.     DialogItemListHandle    errorDialogItems;
  161.     TEHandle                aTEHandle;
  162.     Rect                    textRect;
  163.     short                    textHeight;
  164.     short                    additionalSpaceNeeded;
  165.     DialogItemPtr            okButtonItem,errorTextItem;
  166.     const StringPtr            nullStr = (StringPtr) "\p";
  167.  
  168.     GetIndString(errorString,stringList,whichString);
  169.     
  170.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  171.     HLock((Handle) errorDialogTemplate);
  172.     
  173.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  174.     HLock((Handle) errorDialogItems);
  175.     
  176.     //    Find the dialog items
  177.     
  178.     okButtonItem = (**errorDialogItems).firstItem;
  179.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  180.     
  181.     GetPort(&oldPort);
  182.     GetWMgrPort(&windowMgrPort);
  183.     SetPort(windowMgrPort);
  184.     oldFont = qd.thePort->txFont;
  185.     TextFont(systemFont);
  186.  
  187.     aTEHandle = TENew(&textRect,&textRect);
  188.     TESetText(&errorString[1],errorString[0],aTEHandle);
  189.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  190.     TEDispose(aTEHandle);
  191.  
  192.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  193.                             - errorTextItem->boundsRect.top);
  194.  
  195.     if (additionalSpaceNeeded > 0)
  196.         {
  197.         (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  198.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  199.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  200.         }
  201.         
  202.     TextFont(oldFont);
  203.     SetPort(oldPort);
  204.     
  205.     InitCursor();
  206.     ParamText(errorString,nullStr,nullStr,nullStr);
  207.  
  208.     (void) StandardAlert(kErrorAlertID);
  209.  
  210.     ReleaseResource((Handle) errorDialogTemplate);
  211.     ReleaseResource((Handle) errorDialogItems);
  212.     }
  213.  
  214. ///////////////////////////////////////////////////////////
  215. //
  216. //    FatalErrorAlert
  217. //
  218. //    A companion to ErrorAlert which also kills the process.
  219. //
  220.  
  221. void
  222. FatalErrorAlert(short stringList,short whichString)
  223.     {
  224.     ErrorAlert(stringList,whichString);
  225.     ExitToShell();
  226.     }
  227.  
  228. ///////////////////////////////////////////////////////////
  229. //
  230. //    StandardDialogFilter and StandardDialogFilterYD
  231. //
  232. //    These function takes care of routing events not meant
  233. //    for the dialog window to other parts of the application.
  234. //
  235. //    Use them as an alternative to passing a NIL ModalFilterProc
  236. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  237. //    filter, these routines properly processes update events
  238. //    to keep background processes running.
  239. //
  240. //    The Thread Manager, if present, is also called to yield
  241. //    control to other cooperative threads within the process.
  242. //
  243. //    Because of pascal calling conventions we need two separate
  244. //    routines, but this is minimized by sharing implementation
  245. //    in FilterProcCommon.
  246. //
  247.  
  248. ModalFilterUPP    StandardDialogFilter
  249. = NewModalFilterProc(StandardDialogFilterProc);
  250.  
  251. ModalFilterYDUPP    StandardDialogFilterYD
  252. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  253.  
  254. ModalFilterUPP    StandardCloseDialogFilter
  255. = NewModalFilterProc(StandardCloseDialogFilterProc);
  256.  
  257. pascal Boolean
  258. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  259.     {
  260.     //    Call through common code to check for events we’d like to handle.
  261.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  262.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  263.  
  264.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  265.         return true;
  266.     else
  267.         return (StdFilterProc(theDialog, anEvent, itemHit));
  268.     }
  269.  
  270. pascal Boolean
  271. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  272.     {
  273.     //    We don’t call through to StdFilterProc since the
  274.     //    Standard File Package already does everything we need.
  275.  
  276.     return FilterProcCommon(theDialog, anEvent, itemHit);
  277.     }
  278.  
  279. void
  280. PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  281.     {
  282.     Handle    itemHandle;
  283.     Rect    itemBox;
  284.     UInt32    finalTicks;
  285.     short    itemType;
  286.     
  287.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  288.  
  289.     HiliteControl((ControlHandle) itemHandle, 10);    // kControlButtonPart
  290.     Delay(8,&finalTicks);
  291.     HiliteControl((ControlHandle) itemHandle,0);
  292.     }
  293.  
  294. pascal Boolean
  295. StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  296.     {
  297.     if ((anEvent->what == keyDown))
  298.         {
  299.         char    c = (char) anEvent->message & charCodeMask;
  300.         
  301.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  302.             {
  303.             *itemHit = kDontSaveDocument;
  304.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  305.             return true;
  306.             }
  307.         }
  308.  
  309.     //    Return through the common code above so that default item processing can happen
  310.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  311.     }
  312.  
  313. Boolean
  314. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  315.     {
  316.     switch (anEvent->what)
  317.         {
  318.         case updateEvt:
  319.         case activateEvt:
  320.             //     Update or activate for the dialog window?
  321.             if (theDialog == (DialogPtr) anEvent->message)
  322.                 break;
  323.  
  324.             //    no, fall through to HandleEvent            
  325.             
  326.         case diskEvt:
  327.             HandleEvent(anEvent);
  328.             return(false);
  329.  
  330.         default:
  331.             break;        
  332.         }
  333.  
  334.     if (gHasThreadManager)        //    If we have threads, let them run!
  335.         YieldToAnyThread();
  336.  
  337.     return false;                //    We didn’t handle the event
  338.     }
  339.  
  340. //////////////////////////////////////////////////////////////////
  341. //
  342. //    StandardCloseDocument
  343. //
  344. //    Provides the standard human interface for closing a document
  345. //
  346. //    NOTE: When we make TDocument class, this will become a method
  347. //          and probably won’t need any parameters.
  348. //
  349. //    NOTE:    StandardCloseResult matches the dialog items for 
  350.  
  351. StandardCloseResult
  352. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  353.                       Boolean hasNewEditions, Boolean quitting)
  354.     {
  355.     short        whichAlert;
  356.     short        whichString;
  357.     StringPtr    nullStr = (StringPtr) "\p";
  358.     Str255        reasonForClosingStr;
  359.  
  360.     if (hasNewEditions)
  361.         whichAlert = kStandardCloseWithNewPubsAlertID;
  362.     else
  363.         whichAlert = kStandardCloseAlertID;
  364.     
  365.     if (quitting)
  366.         whichString = kQuittingStr;
  367.     else
  368.         whichString = kClosingStr;
  369.  
  370.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  371.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  372.     
  373.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  374.     }
  375.