home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Dialogs / DraftWn.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  47.9 KB  |  1,718 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DraftWn.cpp
  3.  
  4.     Contains:    Implementation of the DraftWin and DraftInfoRec classes
  5.  
  6.     Owned by:    Eric House
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <4>      7/8/96    eeh        undo task 10008 (AppleGuide buttons)
  13.          <3>     6/21/96    eeh        task 10008: add buttons etc. for AppleGuide
  14.          <2>     6/21/96    RA        T10025: Call InitBndNSUtils
  15.          <0>     6/7/96    eeh        first checked in (moved from ::DocShell:)
  16.  
  17.     To Do:
  18.     In Progress:
  19.         
  20. */
  21.  
  22.  
  23. #ifndef _DRAFTWLD_
  24. #include "DraftWLD.h"
  25. #endif
  26.  
  27. #ifndef SOM_Module_OpenDoc_StdProps_defined
  28. #include <StdProps.xh>
  29. #endif
  30.  
  31. #ifndef _DRAFTWN_
  32. #include "DraftWn.h"
  33. #endif
  34.  
  35. #ifndef _TEMPOBJ_
  36. #include "TempObj.h"
  37. #endif
  38.  
  39. #ifndef _USERSRCM_
  40. #include <UseRsrcM.h>
  41. #endif
  42.  
  43. #ifndef _AGSUPPORT_
  44. #include "AGSupprt.h"
  45. #endif
  46.  
  47. #ifndef SOM_ODDocument_xh
  48. #include <Document.xh>
  49. #endif
  50.  
  51. #ifndef SOM_ODContainer_xh
  52. #include <ODCtr.xh>
  53. #endif
  54.  
  55. #ifndef _ODUTILS_
  56. #include <ODUtils.h>
  57. #endif
  58.  
  59. #ifndef SOM_ODWindowState_xh
  60. #include <WinStat.xh>
  61. #endif
  62.  
  63. #ifndef SOM_ODWindowIterator_xh
  64. #include <WinIter.xh>
  65. #endif
  66.  
  67. #ifndef SOM_ODWindow_xh
  68. #include <Window.xh>
  69. #endif
  70.  
  71. #ifndef _DOCUTILS_
  72. #include <DocUtils.h>
  73. #endif
  74.  
  75. #ifndef SOM_ODStorageUnit_xh
  76. #include <StorageU.xh>
  77. #endif
  78.  
  79. #ifndef SOM_ODClipboard_xh
  80. #include <Clipbd.xh>
  81. #endif
  82.  
  83. #ifndef SOM_ODStorageUnitView_xh
  84. #include <SUView.xh>
  85. #endif
  86.  
  87. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  88. #include <StdTypes.xh>
  89. #endif
  90.  
  91. #ifndef _ODMEMORY_
  92. #include <ODMemory.h>
  93. #endif
  94.  
  95. #ifndef _PLFMFILE_
  96. #include <PlfmFile.h>
  97. #endif
  98.  
  99. #ifndef _DLOGUTIL_
  100. #include <DlogUtil.h>
  101. #endif
  102.  
  103. #ifndef _STORUTIL_
  104. #include <StorUtil.h>
  105. #endif
  106.  
  107. #ifdef _APPLEGUIDE_READY_
  108. #ifndef __APPLEGUIDE__
  109. #include <AppleGuide.h>
  110. #endif
  111. #endif
  112.  
  113. #ifndef __TIME_H__
  114. #include <Time.h>
  115. #endif
  116.  
  117. #ifndef _PASCLSTR_
  118. #include <PasclStr.h>
  119. #endif
  120.  
  121. #ifndef _ISOSTR_
  122. #include <ISOStr.h>
  123. #endif
  124.  
  125. #ifndef _ITEXT_
  126. #include <IText.h>
  127. #endif
  128.  
  129. #ifndef __SCRIPT__
  130. #include <script.h>
  131. #endif
  132.  
  133. #ifndef __DIALOGS__
  134. #include <Dialogs.h>
  135. #endif
  136.  
  137. #ifndef __LISTS__
  138. #include <Lists.h>
  139. #endif
  140.  
  141. #ifndef __TOOLUTILS__
  142. #include <ToolUtils.h>
  143. #endif
  144.  
  145. #ifndef __RESOURCES__
  146. #include <Resources.h>
  147. #endif
  148.  
  149. #ifdef __SC__
  150. #ifndef __PACKAGES__
  151. #include <Packages.h>
  152. #endif
  153. #else
  154. #ifndef __TEXTUTILS__
  155. #include <TextUtils.h>
  156. #endif
  157. #endif
  158.  
  159. #ifndef __ICONS__
  160. #include <Icons.h>
  161. #endif
  162.  
  163. #ifndef _ODMEMORY_
  164. #include <ODMemory.h>
  165. #endif
  166.  
  167. #ifndef SOM_ODSession_xh
  168. #include <ODSessn.xh>
  169. #endif
  170.  
  171. #ifndef _STDTYPIO_
  172. #include <StdTypIO.h>
  173. #endif
  174.  
  175. #ifndef _STORUTIL_
  176. #include <StorUtil.h>
  177. #endif
  178.  
  179. #ifndef _BNDNSUTL_
  180. #include "BndNSUtl.h"
  181. #endif
  182.  
  183. #pragma segment DraftWindow
  184.  
  185. //==============================================================================
  186. // Constants
  187. //==============================================================================
  188.  
  189. #define tenPt            10
  190. #define kNoExpandClick    -1
  191. #define kNoRowHilited    -1
  192.  
  193.  
  194. #define no_ictb_exists        false    /* try using an ictb resource instead of code */
  195.  
  196. #define kXMPNewLineChar    '\n'
  197.  
  198. #define    kDraftsActiveControl 0
  199.  
  200. // macros for passing info about default button behavior.  Currently involves
  201. // setting the low-order bit in the listhandle, which on the mac *should*
  202. // always be clear.  A cleaner implementation might be advised....
  203.  
  204. #define CREATEISSET(self)    (((DraftWindow*)(self))->CreateIsSet())
  205. #define GETLISTHANDLE(self)    (((DraftWindow*)(self))->GetListHandle())
  206. #define GETLISTRECT(self, rectPtr)                                            \
  207.         (((DraftWindow*)(self))->GetListRect((rectPtr)))
  208. #define SETREADYTOCLOSE(self)                                                \
  209.         (((DraftWindow*)(self))->SetReadyToClose(kODTrue))
  210. #define CLEARREADYTOCLOSE(self)                                                \
  211.         (((DraftWindow*)(self))->SetReadyToClose(kODFalse))
  212. #define READYTOCLOSESET(self)                                                \
  213.         (((DraftWindow*)(self))->ReadyToClose())
  214. #define kNumColumns 4
  215. #define    kCommentsColumnIndex 3
  216.  
  217. const short kControlActive = 0;
  218.  
  219. //==============================================================================
  220. // Scalar Types
  221. //==============================================================================
  222.  
  223. //==============================================================================
  224. // Local Classes
  225. //==============================================================================
  226.  
  227. //==============================================================================
  228. // Function Prototypes
  229. //==============================================================================
  230.  
  231. static void DrawDWUserStrings( struct DraftLDEFCallbackInfo *callbackInfo,
  232.         ODSShort row, const Rect* listItemRect );
  233. static DraftInfoRec* GetNthRow( DraftInfoRec* from, short whichRow );
  234. static void ContractList( FullDraftInfoRec* dir, ListHandle listH,    short parentRowNum );
  235. static void ExpandList( FullDraftInfoRec* dir, ListHandle listH, DialogPtr dialog,
  236.         short parentRowNum );
  237. static void AddRows( ListHandle listH, short startIndex, short numToAdd );
  238. static FullDraftInfoRec* FirstSelectedRow( DraftInfoRec* from );
  239. static TEHandle ITextToTERec( ODIText* iText, Rect* bothRects );
  240. static pascal void DrawBlackBoxItem(DialogPtr dlog, short theItem);
  241. static pascal ODBoolean CheckDeleteKeyFilterProc( DialogPtr dialog, EventRecord *event,
  242.         short *itemHit);
  243. static pascal ODBoolean CheckKeyScriptFirstFilterProc( DialogPtr dialog, EventRecord *event,
  244.         short *itemHit);
  245. static pascal ODBoolean DraftDlgFilterProc( DialogPtr dialog, EventRecord *event,
  246.         short *itemHit );
  247. static void SetButtonStates( DialogPtr dlog, ODBoolean hasWriteAccess,
  248.         Boolean hasContent );
  249. static void SetRows( DraftInfoRec* dir,    short startRow, ODBoolean newValue,
  250.         ListHandle listH );
  251.  
  252. #ifdef __cplusplus
  253. extern "C" {
  254. #endif
  255. ODError DraftWindowEntry( Environment* ev, ODSession* session,
  256.         ODWindowState* winState, ODDocument* document );
  257. #ifdef __cplusplus
  258.     }
  259. #endif
  260.  
  261. //==============================================================================
  262. // Entry point: 
  263. //==============================================================================
  264.  
  265. ODError DraftWindowEntry( Environment* ev, ODSession* session,
  266.         ODWindowState* winState, ODDocument* document )
  267. {
  268.     ODError result = noErr;
  269.     TRY
  270.  
  271.         InitBindingNamespaceUtils(session);
  272.     
  273.         ODDraft* topDraft = ODGetTempDraftFromOpenDocument(ev, session, document);
  274.         if (topDraft)
  275.             topDraft->Acquire(ev);
  276.         else
  277.             topDraft = document->AcquireDraft(ev,kODDPReadOnly,0,kODNULL,kODPosTop,kODFalse);
  278.         
  279.         DraftWindow* d = new DraftWindow;
  280.         DraftWinAction     dWinAction = kDraftWinNone;
  281.         ODDraft*    curDraft = kODNULL;
  282.         d->InitDraftWindow(ev, topDraft);
  283.  
  284.         winState->DeactivateFrontWindows(ev);
  285.         ArrowCursor();
  286.         do {
  287.             dWinAction = d->Drafts(ev, curDraft, dWinAction, ODDraftHasWriteAccess(ev, topDraft));
  288.             switch (dWinAction) {
  289.                 case kDraftWinCreate:
  290.                     WASSERT(ODDraftHasWriteAccess(ev, topDraft));
  291.                     winState->ActivateFrontWindows(ev);
  292.                     d->DraftSaved(ev, topDraft);
  293.                     ODSaveDocument(ev, session, document);
  294.                     ODCloseDraft(ev, session, topDraft);
  295.     #ifdef ODDebug
  296.                     ODULong topDraftRefCount = topDraft->GetRefCount(ev);
  297.                     WASSERT(topDraftRefCount == 2);
  298.     #endif
  299.                     topDraft->Release(ev); // to balance the CreateDraft when the document was opened
  300.                     topDraft = document->CreateDraft(ev, topDraft, kODTrue);
  301.                         // This CreateDraft call is doing two things with refcounts.
  302.                         // First, it is releasing topDraft which balances the Acquire at the top of
  303.                         // this function.
  304.                         // Second, it is creating a new temp draft, which puts us in the same
  305.                         // state as we were before the above topDraft->Release, except
  306.                         // for the need to Reacquire the topDraft as was done at the top of this 
  307.                         // function which we do in the next statement.
  308.                     topDraft->Acquire(ev);
  309.                     
  310.                     ODTempDraftCreated(ev, session, document, topDraft);
  311.                     curDraft = topDraft;
  312.  
  313.                     {
  314.                     TempODStorageUnit su = topDraft->AcquireDraftProperties(ev);
  315.                     ODResetDateModByInfo(ev, su);    
  316.                     }
  317.                     
  318.                     d->InitDraftWindow(ev, topDraft);
  319.                     ODOpenDraft(ev, session, topDraft);
  320.                     ODSaveDocument(ev, session, document);
  321.                     winState->DeactivateFrontWindows(ev);
  322.                     
  323.                     break;
  324.                 case kDraftWinDelete:
  325.                     ODDraft* selDraft = d->GetSelectedDraft();
  326.  
  327.                     ODCloseDraft(ev, session, selDraft);
  328.                     ODReleaseObject( ev, selDraft );    // -- TÇ: was acquired in draftswindow
  329.  
  330.                     d->DeleteSelectedDraft(ev, session); 
  331.                     break;
  332.             }
  333.         } while (dWinAction == kDraftWinDelete);
  334.  
  335.         winState->ActivateFrontWindows(ev);
  336.         
  337.         if (dWinAction == kDraftWinOpen)
  338.         {
  339.             // open selected Drafts as additional root windows within this process
  340.             // if a particular draft already has a window, bring it to front, don't create a new one
  341.             ODDraft* selDraft = d->GetSelectedDraft();
  342.             WASSERT(selDraft);
  343.             
  344.             ODOpenDraft(ev, session, selDraft);
  345.         }
  346.         ODDeleteObject(d);
  347.         ODReleaseObject( ev, topDraft );    // balances Acquire & AcquireDraft at beginning.
  348.  
  349.         if ( dWinAction == kDraftWinLowMemAbort )
  350.             result = kODErrOutOfMemory;
  351.     CATCH_ALL
  352.         result = ErrorCode();
  353.     ENDTRY
  354.     return result;
  355. }
  356.  
  357. //==============================================================================
  358. // DraftWindow
  359. //==============================================================================
  360.  
  361. //------------------------------------------------------------------------------
  362. // Creation
  363. //------------------------------------------------------------------------------
  364.  
  365. DraftWindow::DraftWindow()
  366. {
  367.     fDraft        = kODNULL;
  368.     fDocument    = kODNULL;
  369.     fDraftInfo    = kODNULL;
  370.     fSelectedDraft = kODNULL;
  371.     fSelectedDraftNumber = 0;
  372. //    fExpandClickRow = kNoExpandClick;
  373. //    fHilitedRow = kODNULL;        // clear in Drafts() instead.
  374. }
  375.  
  376. void DraftWindow::InitDraftWindow(Environment* ev, ODDraft* draft)
  377. {    
  378.     fDraft         = draft;
  379.     fDocument    = draft->GetDocument(ev);
  380.     fListH        = kODNULL;
  381.     fCreateSet    = kODFalse;
  382.     fReadyToClose = kODFalse;
  383. }
  384.  
  385. //------------------------------------------------------------------------------
  386. // Destruction
  387. //------------------------------------------------------------------------------
  388.  
  389. DraftWindow::~DraftWindow()
  390. {            
  391.     ODReleaseObject(somGetGlobalEnvironment(),fSelectedDraft);
  392.     // dispose of DraftInfoRecs and collection
  393.     ODDeleteObject(fDraftInfo);
  394. }
  395.  
  396.  
  397. //------------------------------------------------------------------------------
  398. // Dialog
  399. //------------------------------------------------------------------------------
  400.  
  401. ListHandle DraftWindow::MakeAList(DialogPtr dlg, ODSShort* numLines,
  402.         long refcon )
  403. {
  404.     Rect        itemRect, boundsRect;
  405.     Handle        itemH;
  406.     short        scratchKind;
  407.  
  408.     /* create a scrolling list */
  409.  
  410.     GetDialogItem(dlg, kDraftsListUserItem, &scratchKind, &itemH, &itemRect);
  411.     itemRect.top -= 1;                                        
  412.     itemRect.left -= 1;                                        
  413.     SetRect(&boundsRect, 0, 0, 1, 0);                            /* one column list, 0 row count for now */
  414.  
  415.     FontInfo    scriptAppFontInfo;
  416.     GetFontInfo(&scriptAppFontInfo);
  417.     ODSShort cellHeight = scriptAppFontInfo.ascent +
  418.             scriptAppFontInfo.descent + scriptAppFontInfo.leading;
  419.     *numLines = (itemRect.bottom - itemRect.top) / cellHeight;
  420.  
  421.     fListRect = itemRect;
  422.     fListRect.bottom -= 1;
  423.     itemRect.right -= 15;
  424.     
  425.     InsetRect(&itemRect, 1, 1);                                    /* leave room for the frame */
  426.  
  427.     /* use the Application Font for the list items (cell size) */
  428.     long scriptAppFontSize = GetScriptVariable(smSystemScript,smScriptAppFondSize);
  429.     TextFont(HiWord(scriptAppFontSize));
  430.     TextSize(LoWord(scriptAppFontSize));        /* make look larger; icons will force this to be right once they're added */
  431.  
  432.     (LoWord(scriptAppFontSize) < tenPt) ? TextSize(tenPt) : TextSize(LoWord(scriptAppFontSize));
  433.  
  434.     Point cellSize;
  435.     SetPt(&cellSize, 500, cellHeight);
  436.     
  437.     /* now get the real desired font size */
  438.     long scriptSmallFontSize = GetScriptVariable(smSystemScript,smScriptSmallFondSize);
  439.     (LoWord(scriptSmallFontSize) < tenPt) ? TextSize(tenPt) : TextSize(LoWord(scriptSmallFontSize));
  440.  
  441.     Handle myHandle;
  442.     ListHandle listH;
  443.     { CUsingLibraryResources r;
  444.         myHandle = Get1Resource('LDEF',kDraftWinLDEFID);
  445.         THROW_IF_NULL(myHandle);
  446.         ListDefUPP LDEFUPP = NewListDefProc(DRAFTWINDOWLDEF);
  447.         (*(ListDefUPP*)&((*myHandle)[kDraftWinLDEFAddrOffset])) = LDEFUPP;
  448.         /* This above code written from suggestion in NIM:PPC System Software 1-35,1-36 */
  449.         
  450.         listH = LNew(&itemRect, &boundsRect, cellSize, kDraftWinLDEFID, dlg,
  451.                                         kODFalse, kODFalse, kODFalse, kODTrue);
  452.     }
  453.  
  454.     if (listH != nil)    
  455.     {                                            /* list was created */
  456.         (*listH)->refCon = refcon ;
  457.         /* resize list rectangle to only display whole cells */
  458.         itemRect.bottom -= (((short) (itemRect.bottom - itemRect.top)) % cellSize.v);
  459.         LSize(itemRect.right - itemRect.left, itemRect.bottom - itemRect.top, listH);
  460.         itemRect.right += 15;                /* add room for scroll bar */    
  461.         SetDialogItem(dlg, kDraftsListUserItem, scratchKind, itemH, &itemRect);
  462.     
  463. //        (*listH)->selFlags = lNoNilHilite;
  464. //        (*listH)->selFlags = (lOnlyOne | lNoNilHilite);
  465.         
  466.         LSetDrawingMode(kODFalse, listH);
  467.  
  468.         LDelRow(0, 0, listH);            /* delete everything in the list */
  469.         AddRows( listH, 0, this->CountDrafts() );
  470.  
  471.         LAutoScroll(listH);
  472.         LUpdate(dlg->visRgn, listH);
  473.         (*listH)->lastClick = *(Cell*)0L;
  474.         if ( fDraftInfo )
  475.             this->SetHilite( fDraftInfo, 0 );
  476. //        LSetDrawingMode(kODTrue, listH);
  477.     }
  478.     return listH;
  479. }    // DraftWindow::MakeAList
  480.  
  481. #if ODDebug
  482. void DraftWindow::CheckConsistency()
  483. {
  484.     if ( !fDraftInfo )
  485.         return;
  486.  
  487.     DraftInfoRec* dir = fDraftInfo;
  488.     short fullEntryCount = 0;
  489.     short dummyEntryCount = 0;
  490.     FullDraftInfoRec* fdir = kODNULL;
  491.     WASSERT( dir->GetComment() );
  492.     ODBoolean somethingExpanded = kODFalse;
  493.     ODBoolean foundHilite = kODFalse;
  494.     while ( dir )
  495.     {
  496.         if ( dir->GetDIRType() == kDIRTypeFull )
  497.         {
  498.             ++fullEntryCount;
  499.             fdir = (FullDraftInfoRec*)dir;
  500.             if ( fdir->ShouldHilite() )
  501.             {
  502.                 WASSERT( !foundHilite );
  503.                 foundHilite = kODTrue;
  504.             }
  505.             if ( fdir->IsExpanded() )
  506.             {
  507.                 somethingExpanded = kODTrue;
  508.                 WASSERT( fdir->GetCachedComment() != kODNULL );
  509.                 WASSERT( fdir->GetComment() != kODNULL );
  510.                 WASSERT( fdir->Next() != kODNULL );
  511.                 WASSERT( fdir->Next()->GetDIRType() != kDIRTypeFull );
  512.             }
  513.             else
  514.             {
  515.                 WASSERT( fdir->GetCachedComment() == kODNULL );
  516.                 WASSERT( fdir->GetComment() != kODNULL );
  517.             }
  518.         }
  519.         else
  520.         {
  521.             ++dummyEntryCount;
  522.             DummyDraftInfoRec* ddir = (DummyDraftInfoRec*)dir;
  523.             WASSERT( ddir->GetCommentOwner() );
  524.             WASSERT( ddir->GetCommentOwner() == fdir );
  525.             WASSERT( ddir->ShouldHilite() == fdir->ShouldHilite() );
  526.         }
  527.         dir = dir->Next();
  528.     }
  529.     if ( !somethingExpanded )
  530.         WASSERT( fullEntryCount == (*fListH)->dataBounds.bottom);
  531.     else
  532.         WASSERT( fullEntryCount+dummyEntryCount == (*fListH)->dataBounds.bottom);
  533.     WASSERT( foundHilite );
  534.     WASSERT( fullEntryCount == this->CountDrafts() );
  535. }
  536. #endif
  537.  
  538. DraftWinAction    DraftWindow::Drafts(Environment* ev, ODDraft* draft,
  539.         DraftWinAction prevAction, ODBoolean hasWriteAccess )
  540. {
  541.     // show the dialog/create the window and modally respond
  542.     // to events until dismissed
  543.     
  544.     short          itemKind,itemHit;
  545.     Rect        scratchRect;
  546.     Handle        scratchHandle;
  547.     
  548.     // worst case app heap memory usage between here and when the
  549.     // delete confirmation draft is up is 6448 bytes.  So I'm
  550.     // padding to 10000 to be safe.
  551.     // <eeh> need to reconsider now that comments expand?
  552.  
  553.     if ( !ODHaveFreeSpace( 10000, 0, kODTrue) )
  554.         return kDraftWinLowMemAbort;
  555.  
  556.     if ( draft != kODNULL )
  557.         fDraft = draft;        
  558.  
  559.     /// read and construct DraftInfo
  560.     fHilitedRow = kODNULL;        // clear this each time reopen dialog
  561.     fDraftInfo = this->InternalizeHistory(ev);
  562.  
  563.     GrafPort*    savePort;
  564.     GetPort(&savePort);
  565.  
  566.     TempODStorageUnit draftProps = fDraft->AcquireDraftProperties(ev);
  567.     ODSession *session = draftProps->GetSession(ev);
  568.     DialogPtr dlg;
  569.     {CUsingLibraryResources r;
  570.         dlg = ODGetNewDialog(ev,kDraftsDlgID,session,kODFalse);
  571.     }
  572.     THROW_IF_NULL(dlg);
  573.     SetPort(dlg);
  574.  
  575.     DialogSetUpAppleGuide( dlg, kDraftsAGButtonItem );
  576.  
  577.     PlatformFile* file = GetPlatformFileFromContainer(ev,
  578.             fDraft->GetDocument(ev)->GetContainer(ev));
  579.     Str255 dWinName;
  580.     ODName* fileName = file->GetName();
  581.     ODSLong savedRefNum;
  582.     BeginUsingLibraryResources(savedRefNum);
  583.     // DMc: ensure that string is deleted:
  584.     TempODString tempString = (char*) GetITextString(fileName, (StringPtr)kODNULL);
  585.     ConstStr255Param csp = (ConstStr255Param) (char*) tempString;
  586.     ReplaceIntoString( kDraftsWnTitleResID,
  587.             csp, kODNULL,
  588.             dWinName);
  589.     EndUsingLibraryResources(savedRefNum);
  590.     DisposeIText(fileName);
  591.  
  592.     SetWTitle(dlg,(StringPtr)dWinName);
  593.     ODDeleteObject(file);
  594.  
  595.     DialogPeek dlgPeek;
  596. #if no_ictb_exists
  597.     /* use the script's small font for the static text */
  598.     scriptSmallFontSize = GetScript(smSystemScript,smScriptSmallFondSize);    
  599.     TextFont(HiWord(scriptSmallFontSize));
  600.     (LoWord(scriptSmallFontSize) < tenPt) ?
  601.             TextSize(tenPt) : TextSize(LoWord(scriptSmallFontSize));
  602.     TextFace(bold);
  603.  
  604.     /* WARNING: remember to set the font, face and size for update events */
  605.     dlgPeek = (DialogPeek) dlg;
  606.     (**(dlgPeek->textH)).txFont = HiWord(scriptSmallFontSize);
  607.     if (((**(dlgPeek->textH)).txSize = LoWord(scriptSmallFontSize)) < tenPt)
  608.         (**(dlgPeek->textH)).txSize = tenPt;
  609. //    (**(dlgPeek->textH)).txFace = bold;
  610. #endif
  611.  
  612.     UserItemUPP drawBoxItemUPP; // dialogs.h
  613.     drawBoxItemUPP    = NewUserItemProc(DrawBlackBoxItem);
  614.     
  615.     /* A horizontal line needs to be drawn above the list rectangle */
  616.     GetDialogItem(dlg, kDraftsHorizRectUserItem, &itemKind,
  617.             &scratchHandle, &scratchRect);
  618.     SetDialogItem(dlg, kDraftsHorizRectUserItem, itemKind,
  619.             (Handle)drawBoxItemUPP, &scratchRect);
  620.  
  621.     /* A rectangle needs to be drawn around the list column titles */
  622.     GetDialogItem(dlg, kDraftsHeaderRectUserItem, &itemKind,
  623.             &scratchHandle, &scratchRect);
  624.     SetDialogItem(dlg, kDraftsHeaderRectUserItem, itemKind,
  625.             (Handle)drawBoxItemUPP, &scratchRect);
  626.  
  627.     if ( hasWriteAccess  )
  628.     {
  629.         GetDialogItem(dlg, kDraftsCreateUserItem, &itemKind,
  630.                 &scratchHandle, &scratchRect);
  631.         SetDialogItem(dlg, kDraftsCreateUserItem, itemKind,
  632.                 (Handle)drawBoxItemUPP, &scratchRect);
  633.     }
  634.     else        // set up to draw box around create button
  635.     {
  636.         GetDialogItem(dlg, kDraftsCreateBtn, &itemKind, &scratchHandle,
  637.                 &scratchRect);
  638.         HiliteControl( (ControlHandle)scratchHandle, 255 );    // disable create
  639.     }
  640.  
  641.     GetDialogItem(dlg, kDraftsDoneUserItem, &itemKind,
  642.             &scratchHandle, &scratchRect);
  643.     SetDialogItem(dlg, kDraftsDoneUserItem, itemKind,
  644.             (Handle)drawBoxItemUPP, &scratchRect);
  645.  
  646.     GetDialogItem(dlg, kDraftsListUserItem, &itemKind,
  647.             &scratchHandle, &scratchRect);
  648.     SetDialogItem(dlg, kDraftsListUserItem, itemKind,
  649.             (Handle)drawBoxItemUPP, &scratchRect);
  650.  
  651.     /* create a scrolling list of draft information */
  652.     DraftLDEFCallbackInfo hc ;
  653.     hc.dialog = dlg;
  654.     hc.dir = fDraftInfo ;
  655.     hc.stringsProc = DrawDWUserStrings ;
  656.     
  657.  
  658.     GetDialogItem(dlg, kDraftsCreatorStaticTxt, &itemKind, &scratchHandle,
  659.             &scratchRect);
  660.     hc.rectEnds[0].right = scratchRect.right;
  661.     hc.rectEnds[0].left = scratchRect.left;
  662.     GetDialogItem(dlg, kDraftsDraftStaticTxt, &itemKind, &scratchHandle,
  663.             &scratchRect);
  664.     hc.rectEnds[1].right = scratchRect.right;
  665.     hc.rectEnds[1].left = scratchRect.left;
  666.     GetDialogItem(dlg, kDraftsCreatedStaticTxt, &itemKind, &scratchHandle,
  667.             &scratchRect);
  668.     hc.rectEnds[2].right = scratchRect.right;
  669.     hc.rectEnds[2].left = scratchRect.left;
  670.     GetDialogItem(dlg, kDraftsCommentStaticTxt, &itemKind, &scratchHandle,
  671.             &scratchRect);
  672.     hc.rectEnds[3].right = scratchRect.right;
  673.     hc.rectEnds[3].left = scratchRect.left;
  674.     
  675.     GetDialogItem(dlg, kDraftsArrowStaticTxt, &itemKind, &scratchHandle,
  676.             &scratchRect);
  677.     hc.arrowEnds.right = scratchRect.right;
  678.     hc.arrowEnds.left = scratchRect.left;
  679.  
  680.     fCreateSet = (prevAction == kDraftWinNone) && hasWriteAccess;
  681.  
  682.     session->GetClipboard(ev)->SetPlatformClipboard( ev, kODNULL );
  683.  
  684.     ODSShort numLines;
  685.     ListHandle listH = fListH = this->MakeAList(dlg, &numLines, (long)&hc );
  686.     ((WindowPeek)dlg)->refCon = (long)this;
  687.     dlgPeek = (DialogPeek) dlg;
  688.     UpdateDialog( dlg,(dlgPeek->window).port.visRgn);
  689.     ShowWindow(dlg);    
  690.  
  691.     // <eeh> does this work?
  692.     LSetDrawingMode(kODTrue, listH);
  693.     
  694.     DraftWinAction dWinAction = kDraftWinNone;
  695.     ODUseCommandKeyStringsResource( kDraftsCmdKeyStrs );
  696.     ModalFilterUPP modalFilter = NewModalFilterProc(CheckDeleteKeyFilterProc);
  697.     SetButtonStates( dlg, hasWriteAccess, fDraftInfo != kODNULL );
  698.     while (dWinAction == kDraftWinNone)
  699.     {
  700. #if ODDebug
  701.         this->CheckConsistency();
  702. #endif
  703.         ODUseCommandKeyStringsResource( kDraftsCmdKeyStrs );
  704.         BeginUsingLibraryResources(savedRefNum);        // for the cmd key str#
  705.         ModalDialog( modalFilter, &itemHit );
  706.         EndUsingLibraryResources(savedRefNum);
  707.         
  708.         switch    (itemHit)
  709.         {
  710.             case kODUpArrowItem:
  711.             case kODPageUpArrowItem:
  712.             case kODHomeArrowItem:
  713.             case kODDownArrowItem:
  714.             case kODPageDownArrowItem:
  715.             case kODEndArrowItem:
  716. //                ArrowKeyScrollList( itemHit, listH, numLines,
  717. //                        this->CountDrafts()-1 );
  718.                 break;
  719.  
  720.             case kDraftsDoneBtn:
  721.                 dWinAction = kDraftWinDone;
  722.                 break;
  723.  
  724.             case kDraftsCreateBtn:
  725.                 LActivate(kODFalse,listH);
  726.                 if (this->CreateDraft(ev))
  727.                     dWinAction = kDraftWinCreate;
  728.                 LActivate(kODTrue,listH);
  729.                 ShowWindow(dlg);
  730.                 break;
  731.  
  732.             case kDraftsListUserItem:
  733.                 continue;
  734.  
  735.             case kDraftsDeleteBtn:
  736.             case kDraftsOpenBtn:
  737.                 WASSERT( fDraftInfo );
  738.                 FullDraftInfoRec* selDraftInfoRec =
  739.                         FirstSelectedRow( fDraftInfo );
  740.  
  741.                 WASSERT(selDraftInfoRec);
  742.                 ODReleaseObject(ev,fSelectedDraft);
  743.                 WASSERT(selDraftInfoRec->GetDIRType() == kDIRTypeFull);
  744.                 fSelectedDraft = selDraftInfoRec->Draft();
  745.                 fSelectedDraft->Acquire(ev);
  746.                 fSelectedDraftNumber = selDraftInfoRec->Number();
  747.  
  748.                 if    (itemHit == kDraftsDeleteBtn)
  749.                 {
  750.                     LActivate(kODFalse,listH);
  751.                     if (this->RemoveSelectedDrafts(ev))
  752.                         dWinAction = kDraftWinDelete;
  753.                     LActivate(kODTrue,listH);
  754.                     ShowWindow(dlg);
  755.                 }
  756.                 else 
  757.                 {
  758.                     dWinAction = kDraftWinOpen;
  759.                 }
  760.                 break;
  761. #ifdef _APPLEGUIDE_READY_
  762.             case kDraftsAGButtonItem:
  763.                 OpenAppleGuide();
  764.                 break;
  765. #endif
  766.             default:
  767.                 break;
  768.         }
  769.         UpdateDialog(dlg,(dlgPeek->window).port.visRgn);
  770.     }
  771.  
  772.     if (listH != kODNULL)
  773.     {
  774.         CUsingLibraryResources r;
  775.         // Release LDEF and the UPP it points to after deleting the list:
  776.         Handle ldef = (**listH).listDefProc;
  777.         LDispose(listH);
  778.         DisposeRoutineDescriptor(
  779.                 (*(ListDefUPP*)&((*ldef)[kDraftWinLDEFAddrOffset])) );
  780.         ReleaseResource(ldef);
  781.     }
  782.  
  783.     DisposeRoutineDescriptor(modalFilter);
  784.     DisposeRoutineDescriptor(drawBoxItemUPP);
  785.     
  786.     DisposeDialog(dlg);
  787.     SetPort(savePort);
  788.     
  789.     // dispose of DraftInfoRecs and collection
  790.     ODDeleteObject(fDraftInfo);
  791.  
  792.     if (dWinAction == kDraftWinCreate)
  793.     {
  794.         ODReleaseObject(ev,fSelectedDraft);
  795.         fSelectedDraftNumber = 0;
  796.     }
  797.  
  798.     return dWinAction;
  799. }    // DraftWindow::Drafts
  800.  
  801. void    DraftWindow::DeleteSelectedDraft(Environment* ev, ODSession* session) 
  802. {
  803.     WASSERT(fSelectedDraft);
  804.     if (fSelectedDraft == fDraft) 
  805.         ; // can't delete current draft, this shouldn't happen!
  806.     else if (fSelectedDraft->GetRefCount(ev)>1)
  807.     {
  808.         // When the exceptionalert code becomes a utility, call it
  809.         // here.  That allow us to not THROW an error, which we don't
  810.         // want to do because there's no code to catch it in places
  811.         // where cleanup must be done.
  812.  
  813.         WARN( "kODErrOutstandingDraft: trying to delete open draft." );
  814.         SysBeep( 2 );
  815.     }
  816.     else 
  817.     {
  818.         ODDraft* fromDraft = 
  819.                 fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL,    /* -- TÇ: $$$$$ Don't know if this is a true leak */
  820.                 fSelectedDraft, kODPosFirstAbove,kODFalse);
  821.         ODBoolean openDraftAbove = kODFalse;
  822.         // if draft just above selected draft is open, close and open it again
  823.         // otherwise the window would be pointing to the wrong draft
  824.         ODWindowState* windowState = session->GetWindowState(ev);
  825.         if (windowState->GetRootWindowCount(ev, fromDraft)) {
  826.             ODCloseDraft(ev, session, fromDraft);
  827.             openDraftAbove = kODTrue;
  828.         }
  829.         fDocument->SaveToAPrevDraft(ev,fromDraft,fSelectedDraft);
  830.         fDocument->CollapseDrafts(ev,fromDraft,fSelectedDraft); // Releases fSelectedDraft
  831.  
  832.         // open the selected draft again, this is now what was the draft just above it
  833.         if (openDraftAbove != kODFalse)
  834.             ODOpenDraft(ev, session, fSelectedDraft);
  835.         
  836.         // rename any open window in the drafts above
  837.         TempODDraft topDraft = fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL,kODNULL,kODPosTop,kODFalse);
  838.         TempODDraft nextDraft = fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL,
  839.                         fSelectedDraft, kODPosFirstAbove,kODFalse);
  840.         while (ODObjectsAreEqual(ev, nextDraft, topDraft) == kODFalse) {
  841.             windowState->SetDefaultWindowTitles(ev, nextDraft);
  842.             nextDraft = fDocument->AcquireDraft(ev,kODDPReadOnly,kODNULL, nextDraft, kODPosFirstAbove,kODTrue);
  843.         }
  844.  
  845.         fSelectedDraft = kODNULL;
  846.         fSelectedDraftNumber = 0;
  847.     }
  848. }
  849.  
  850. //------------------------------------------------------------------------------
  851. // InternalizeHistory
  852. //------------------------------------------------------------------------------
  853.  
  854. FullDraftInfoRec* DraftWindow::InternalizeHistory(Environment* ev)
  855. {
  856.     ODDocument*        document = fDraft->GetDocument(ev);
  857.     TempODDraft        prevDraft = kODNULL;
  858.     TempODDraft        bottomDraft = document->AcquireBaseDraft(ev,kODDPReadOnly);
  859.     FullDraftInfoRec*    aDraftInfoRec;
  860.     
  861.     if (HAS_WRITE_ACCESS(fDraft->GetPermissions(ev)))
  862.     {
  863.         WASSERT(document->Exists(ev, 0, fDraft, kODPosFirstBelow));
  864.  
  865.         prevDraft =    document->AcquireDraft(ev,kODDPReadOnly,kODNULL,fDraft,
  866.                     kODPosFirstBelow,kODFalse);
  867.     }
  868.     else 
  869.     {
  870.         prevDraft = fDraft;
  871.         prevDraft->Acquire(ev);
  872.     }
  873.  
  874.     FullDraftInfoRec* firstInfoRec = kODNULL;
  875.     if ( prevDraft != bottomDraft )
  876.     {
  877.         ODULong    curDraftNumber = 1;
  878.         for ( ; ; )
  879.         {
  880.             // $$$$$ <eeh> each draft gets aquired twice: here and in InitDraftInfoRec
  881.             prevDraft = document->AcquireDraft( ev, kODDPReadOnly, kODNULL,
  882.                     prevDraft, kODPosFirstBelow, kODTrue );
  883.     
  884.             FullDraftInfoRec* newDIR = new FullDraftInfoRec;
  885.             newDIR->InitDraftInfoRec(ev, prevDraft);
  886.     
  887.             if ( firstInfoRec )
  888.             {
  889.                 aDraftInfoRec->SetNext(newDIR);
  890.                 aDraftInfoRec = newDIR;
  891.             }
  892.             else
  893.             {
  894.                 aDraftInfoRec = newDIR;
  895.                 firstInfoRec = aDraftInfoRec;
  896.             }
  897.             if ( prevDraft == bottomDraft )
  898.                 break;
  899.             ++curDraftNumber;
  900.         }
  901.     
  902.         ODScriptCode script = FontToScript( GetSysFont() );
  903.         ODLangCode lang = GetScriptVariable( script, smScriptLang );
  904.     
  905.         for (aDraftInfoRec = firstInfoRec; aDraftInfoRec!=kODNULL;
  906.                 aDraftInfoRec =
  907.                 (FullDraftInfoRec*)((DraftInfoRec*)aDraftInfoRec)->Next())
  908.         {
  909.             aDraftInfoRec->SetNumber( curDraftNumber-- );
  910.             Str255 numberStr;
  911.             NumToString( aDraftInfoRec->Number(), numberStr);
  912.             aDraftInfoRec->SetNumberString( CreateIText( script, lang, numberStr ));
  913.         }
  914.     }
  915.  
  916.     return firstInfoRec;
  917. }
  918.  
  919. void    DraftWindow::DraftSaved(Environment* ev, ODDraft* draft) 
  920. {
  921.     ODTime    savedTimeDate;
  922.     time((time_t *)(&savedTimeDate));
  923.     TempODStorageUnit    su = draft->AcquireDraftProperties(ev);
  924.     ODSetTime_TProp(ev, su, kODPropDraftSavedDate, kODTime_T, savedTimeDate);
  925. }
  926.  
  927. ODSShort    DraftWindow::CountDrafts()
  928. {
  929.     DraftInfoRec* dir = fDraftInfo;
  930.     ODSShort result;
  931.     for ( result = 0; dir; dir = dir->Next() )
  932.         if ( dir->GetDIRType() == kDIRTypeFull )
  933.             ++result;
  934.     return result;
  935. }
  936.  
  937. ODBoolean    DraftWindow::CreateDraft(Environment* ev)
  938. {
  939.     short          itemHit,itemKind;
  940.     Handle        itemHandle;
  941.     Rect        scratchRect;
  942.     DialogPtr      dlg;
  943.     Str255        aS255;
  944.     ODBoolean    result;
  945.     GrafPort*    savePort;
  946.  
  947.     TempODStorageUnit su = fDraft->AcquireDraftProperties(ev);
  948.     ODSession *session = su->GetSession(ev);
  949.  
  950.     GetPort(&savePort);
  951.     { CUsingLibraryResources r;
  952.         dlg  = ODGetNewDialog(ev,kCreateDraftsDlgID,session);
  953.     }
  954.     THROW_IF_NULL(dlg);
  955.     SetPort(dlg);
  956.     DialogSetUpAppleGuide( dlg, kCreateDraftsAGButtonItem );
  957.  
  958.     SetDialogDefaultItem(dlg, kCreateDraftsCreateBtn);
  959.     SetDialogCancelItem(dlg, kCreateDraftsCancelBtn);
  960.  
  961.     GetDialogItem(dlg, kCreateDraftsNameEditTxt, &itemKind,
  962.             &itemHandle, &scratchRect);
  963.     ODIText userName;
  964.     session->GetUserName(ev, &userName);
  965.     Str255 userNamePStr ;
  966.     IntlToPStr(&userName, userNamePStr);
  967.     SetDialogItemText(itemHandle,userNamePStr);
  968.     DisposeITextStruct(userName);
  969.     
  970.     /* make the Comments edit text field active: (0, 0) = beginning of text */
  971.     SelectDialogItemText(dlg, kCreateDraftsCommentsEditTxt, 0, 0);
  972.     
  973.     /* get the draft # dynamically and add to static text… */
  974.     ODULong num = fDraftInfo?fDraftInfo->Number() + 1 : 1;
  975.     NumToString( num, aS255 );
  976.  
  977.     // This acts to replace the "^0" in static text item 8 with the
  978.     // number of the draft.  Since item 8 is the only static text item
  979.     // in the dialog we don't have to say which one.  I guess....
  980.     ParamText(aS255,"\p","\p","\p");
  981.  
  982.     DialogScriptData dsd;
  983.     ODUseDialogScriptData( &dsd, dlg );
  984.  
  985.     ShowWindow(dlg);
  986.     
  987.     ModalFilterUPP modalFilter =
  988.             NewModalFilterProc(CheckKeyScriptFirstFilterProc);
  989.  
  990.     ODUseCommandKeyStringsResource( kDraftsCreateCmdKeyStrs );
  991.     do {
  992.         ODSLong savedRefNum;
  993.         BeginUsingLibraryResources(savedRefNum);        // for the cmd key str#
  994.         ModalDialog( modalFilter, &itemHit );
  995.  
  996.         EndUsingLibraryResources(savedRefNum);
  997.         switch(itemHit)
  998.         {
  999.             case kCreateDraftsNameEditTxt:
  1000.                 break;
  1001.             case kCreateDraftsCommentsEditTxt:
  1002.                 break;
  1003. #ifdef _APPLEGUIDE_READY_
  1004.             case kCreateDraftsAGButtonItem:
  1005. //                OpenAppleGuide( "\pDrafts" );
  1006.                 OpenAppleGuide();
  1007.         //        (void)AGOpenWithSearch( "\pOpenDoc Guide", 0, NULL, "\pDrafts", 0 );
  1008.                 break;
  1009. #endif
  1010.         }
  1011.     } while ((itemHit != kCreateDraftsCreateBtn) &&
  1012.             (itemHit != kCreateDraftsCancelBtn));
  1013.  
  1014.     DisposeRoutineDescriptor(modalFilter);
  1015.  
  1016.     result = (itemHit == kCreateDraftsCreateBtn);
  1017.     if (result)
  1018.     {
  1019.         Str255 aStr255;
  1020.         
  1021.     // update Name
  1022.         GetDialogItem(dlg, kCreateDraftsNameEditTxt, &itemHit,
  1023.                 &itemHandle, &scratchRect);
  1024.         GetDialogItemText(itemHandle,aStr255);
  1025.         TempODIText name = CreateIText( dsd.Script(), dsd.Language(),
  1026.                 (StringPtr)aStr255 );
  1027.         ODSetITextProp( ev, su, kODPropModUser, kODMacIText, name);
  1028.  
  1029.     // update Comments.  Note that it's now possible to display long ones
  1030.     // and that therefore we want to allow them bigger than 255.
  1031.         GetDialogItem(dlg, kCreateDraftsCommentsEditTxt, &itemHit, &itemHandle,
  1032.                 &scratchRect);
  1033.         ODSize strLen = GetHandleSize(itemHandle);
  1034.         TempODIText comments = CreateIText( dsd.Script(), dsd.Language(),
  1035.                 (ODUByte*)*itemHandle, strLen );
  1036.         ODSetITextProp( ev, su, kODPropDraftComment, kODMacIText, comments);
  1037.     }
  1038.     DisposeDialog(dlg);
  1039.     SetPort(savePort);
  1040.     return result;
  1041. }    // CreateDraft()
  1042.  
  1043.  
  1044. ODBoolean    DraftWindow::RemoveSelectedDrafts(Environment* ev)
  1045. {
  1046.     short          itemHit;
  1047.     DialogPtr      dlg;
  1048.     Str255        aS255,aS2552;
  1049.     GrafPort*    savePort;
  1050.  
  1051.     GetPort(&savePort);
  1052.     {    
  1053.         TempODStorageUnit draftProps = fDraft->AcquireDraftProperties(ev);
  1054.         ODSession *session = draftProps->GetSession(ev);
  1055.         CUsingLibraryResources r;
  1056.         dlg = ODGetNewDialog( ev, kDeleteDraftsDlogID, session );
  1057.     }
  1058.     THROW_IF_NULL(dlg);
  1059.     SetPort(dlg);
  1060.  
  1061.     SetDialogDefaultItem(dlg, kDeleteDraftsCancelBtn);
  1062.     SetDialogCancelItem(dlg, kDeleteDraftsCancelBtn);
  1063.  
  1064.     PlatformFile* file = GetPlatformFileFromContainer(ev,
  1065.             fDraft->GetDocument(ev)->GetContainer(ev));
  1066.  
  1067.     file->GetAsciiName((char*)aS255,255);
  1068.     ODDeleteObject(file);
  1069.     CToPascalString((char*)aS255);
  1070.     NumToString( fSelectedDraftNumber, aS2552 );
  1071.     ParamText(aS2552,aS255,"\p","\p");
  1072.  
  1073.     ShowWindow(dlg);
  1074.     ModalFilterUPP modalFilter = NewModalFilterProc( CheckDeleteKeyFilterProc );
  1075.     
  1076.     do {
  1077.         ODSLong savedRefNum;
  1078.         BeginUsingLibraryResources(savedRefNum);    // for the cmd key str#
  1079.         ModalDialog( modalFilter, &itemHit );
  1080.         EndUsingLibraryResources(savedRefNum);
  1081.     } while ((itemHit != kDeleteDraftsCancelBtn) &&
  1082.             (itemHit != kDeleteDraftsDeleteBtn));
  1083.     
  1084.     DisposeRoutineDescriptor(modalFilter);
  1085.     DisposeDialog(dlg);
  1086.     SetPort(savePort);
  1087.  
  1088.     return itemHit == kDeleteDraftsDeleteBtn;
  1089. }
  1090.  
  1091. void DraftWindow::SetHilite( DraftInfoRec* from, short whichRow )
  1092. {
  1093.     if ( fHilitedRow != kODNULL )
  1094.         SetRows( fHilitedRow, 0, kODFalse, fListH );
  1095.     SetRows( from, whichRow, kODTrue, fListH );
  1096.     fHilitedRow = (FullDraftInfoRec*)GetNthRow( from, whichRow );
  1097. }
  1098.  
  1099. void    DraftWindow::Print()
  1100. {
  1101. }
  1102.  
  1103. //==============================================================================
  1104. // DraftInfoRec
  1105. //==============================================================================
  1106.  
  1107. DraftInfoRec::DraftInfoRec()
  1108. {
  1109.     fDIRType            = kDIRTypeUnknown;
  1110. //    fFirst                = kODNULL;
  1111.     fNext                 = kODNULL;
  1112.     fComment            = kODNULL;
  1113. }
  1114.  
  1115. //==============================================================================
  1116. // DummyDraftInfoRec
  1117. //==============================================================================
  1118.  
  1119. DummyDraftInfoRec::DummyDraftInfoRec()
  1120. {
  1121.     this->SetDIRType( kDIRTypeDummy );
  1122.     this->SetShouldHilite( kODFalse );
  1123.  
  1124. //    fPartialComment = kODNULL;
  1125.     fCommentOwner    = kODNULL;
  1126. }
  1127.  
  1128. //==============================================================================
  1129. // FullDraftInfoRec
  1130. //==============================================================================
  1131.  
  1132. //------------------------------------------------------------------------------
  1133. // Creation
  1134. //------------------------------------------------------------------------------
  1135.  
  1136. FullDraftInfoRec::FullDraftInfoRec()
  1137. {
  1138.     this->SetDIRType( kDIRTypeFull );
  1139.     this->SetShouldHilite( kODFalse );
  1140.  
  1141.     fDraft                 = kODNULL;
  1142.     fDraftProperties    = kODNULL;
  1143.     fDraftID             = kODNULL;
  1144.     fDraftNumber         = 0;
  1145.     fDraftNumberString    = kODNULL;
  1146.     fSaved                = kODNULL;
  1147.     fSavedString        = kODNULL;
  1148.     fCachedComment        = kODNULL;
  1149.     fModifiedBy            = kODNULL;
  1150.     fCanExpand            = kODFalse;
  1151. }
  1152.  
  1153. void FullDraftInfoRec::InitDraftInfoRec(Environment* ev, ODDraft* draft )
  1154. {    
  1155.     draft->Acquire(ev);
  1156.     fDraft = draft;
  1157.     fDraftProperties = draft->AcquireDraftProperties(ev);
  1158.     fDraftID = draft->GetID(ev);
  1159.  
  1160.     fModifiedBy = ODGetITextProp( ev, fDraftProperties,
  1161.                         kODPropModUser, kODMacIText, kODNULL);
  1162.  
  1163.     fSaved = ODGetTime_TProp(ev, fDraftProperties, kODPropDraftSavedDate,
  1164.             kODTime_T);
  1165.  
  1166.     Str255 dateString;
  1167.     IUDateString( fSaved, shortDate, dateString );
  1168.     Str255 timeString;
  1169.     IUTimeString( fSaved, kODFalse, timeString );
  1170.     
  1171.     Str255 dateTimeString;
  1172.     ODSLong savedRefNum;
  1173.     BeginUsingLibraryResources(savedRefNum);
  1174.     ReplaceIntoString( kDraftsWnDateSpaceResID, dateString,
  1175.             timeString, dateTimeString );
  1176.     EndUsingLibraryResources(savedRefNum);
  1177.     ODScriptCode script = GetScriptManagerVariable(smSysScript);
  1178.     ODLangCode lang = GetScriptVariable(script, smScriptLang);
  1179.     fSavedString = CreateIText( script, lang, dateTimeString );
  1180.  
  1181.     ODIText* comment = ODGetITextProp( ev, fDraftProperties,
  1182.                         kODPropDraftComment, kODMacIText, kODNULL );
  1183.     WASSERT( comment );
  1184.     this->SetComment( comment );
  1185. }
  1186.  
  1187.  
  1188. //------------------------------------------------------------------------------
  1189. // Destruction
  1190. //------------------------------------------------------------------------------
  1191.  
  1192. DraftInfoRec::~DraftInfoRec()
  1193. {
  1194.     ODDeleteObject(fNext);
  1195.     DisposeIText(fComment);
  1196. }
  1197.  
  1198. #if ODDebug
  1199. DummyDraftInfoRec::~DummyDraftInfoRec()
  1200. {
  1201.     WASSERT( this->GetDIRType() == kDIRTypeDummy);
  1202. }
  1203. #endif
  1204.  
  1205. FullDraftInfoRec::~FullDraftInfoRec()
  1206. {
  1207.     WASSERT( this->GetDIRType() == kDIRTypeFull);
  1208.     Environment* ev = somGetGlobalEnvironment();
  1209.     
  1210.     ODReleaseObject(ev,fDraftProperties);
  1211.     ODReleaseObject(ev,fDraft);
  1212.     
  1213.     DisposeIText(fDraftNumberString);
  1214.     DisposeIText(fSavedString);
  1215.     DisposeIText(fModifiedBy);
  1216.     DisposeIText(fCachedComment);
  1217. }
  1218.  
  1219. //------------------------------------------------------------------------------
  1220. // filter procs
  1221. //------------------------------------------------------------------------------
  1222.  
  1223. static pascal ODBoolean DraftDlgFilterProc( DialogPtr dialog, EventRecord *event,
  1224.         short *itemHit )
  1225. {    
  1226.     Rect        itemRect;
  1227.     short        itemType;
  1228.     Handle        itemHandle;
  1229.     long refcon = ((WindowPeek)dialog)->refCon;
  1230.     DraftWindow* self = (DraftWindow*)refcon;
  1231.     ListHandle listH = self->GetListHandle();
  1232.     ODBoolean result = kODFalse;
  1233.  
  1234.     if (event->what == mouseUp)
  1235.     {
  1236.         if ( READYTOCLOSESET( refcon ) )
  1237.         {
  1238.             *itemHit = kDraftsOpenBtn;
  1239.             result = kODTrue;
  1240.         }
  1241.     }
  1242.     else if (event->what == mouseDown)
  1243.     {
  1244.         GetDialogItem(dialog, kDraftsListUserItem, &itemType, &itemHandle, &itemRect);
  1245.         Point mpt = event->where;
  1246.         SetPort(dialog);
  1247.         GlobalToLocal(&mpt);
  1248.         if ( PtInRect(mpt, &itemRect) )
  1249.         {
  1250.             if ( LClick( mpt, event->modifiers, listH ) )
  1251.             {
  1252.                 WASSERT( !READYTOCLOSESET( refcon ) );
  1253.                 SETREADYTOCLOSE( refcon );
  1254.             }
  1255.             else if ( self->ProcessMousedownInList( dialog, listH, mpt ) )
  1256.                 InvalRect( &itemRect );
  1257.             *itemHit = kDraftsListUserItem;
  1258.             result = kODTrue;
  1259.         }
  1260.     }
  1261.     // <eeh> autoKey too?
  1262.     else if ( (event->what == keyDown) && !CREATEISSET(refcon) )
  1263.     {
  1264.         // the "done" button is shown as the default though it is item
  1265.         // #2, so we need to override the ODArrowKeyFilterProc's behavior.
  1266.         char key = event->message & charCodeMask;
  1267.         if ( (key == kEnterKey) || (key ==kReturnKey) )
  1268.         {
  1269.             FlashButtonItem( dialog, kDraftsDoneBtn );
  1270.             *itemHit = kDraftsDoneBtn;
  1271.             result = kODTrue;
  1272.         }
  1273.     }
  1274.  
  1275.     return result || ODArrowKeyFilterProc( dialog, event, itemHit );
  1276. }
  1277.  
  1278. static pascal ODBoolean CheckKeyScriptFirstFilterProc( DialogPtr dialog,
  1279.         EventRecord *event, short *itemHit)
  1280. {
  1281.     // pass to the next filter proc.  This one just changes state, never
  1282.     // consuming the event.
  1283.     return CheckKeyScriptChangeFilterProc( dialog, event, itemHit )
  1284.             || ODButtonKeyFilterProc( dialog, event, itemHit );
  1285. }
  1286.  
  1287. static DraftInfoRec* GetNthRow( DraftInfoRec* from, short whichRow )
  1288. {
  1289.     WASSERT( from );
  1290.     WASSERT( whichRow >= 0 );
  1291.     while ( whichRow-- )
  1292.     {
  1293.         from = from->Next();
  1294.         WASSERT( from );
  1295.     }
  1296.     return from;
  1297. }
  1298.  
  1299. static void SetRows( DraftInfoRec* dir,    short startRow, ODBoolean newValue,
  1300.         ListHandle listH )
  1301. {
  1302.     dir = GetNthRow( dir, startRow );
  1303.     WASSERT(dir);
  1304.     WASSERT( dir->GetDIRType() == kDIRTypeFull );
  1305.     dir->SetShouldHilite( newValue );
  1306.     Cell cell;
  1307.     cell.h = 0;
  1308.     cell.v = startRow;
  1309.     while ( ((dir = dir->Next()) != NULL) && dir->GetDIRType() == kDIRTypeDummy )
  1310.     {
  1311.         dir->SetShouldHilite( newValue );
  1312.         ++cell.v;
  1313.     }
  1314. }
  1315.  
  1316. static FullDraftInfoRec* FirstSelectedRow( DraftInfoRec* from )
  1317. {
  1318.     while ( from && !from->ShouldHilite() )
  1319.         from = (FullDraftInfoRec*)from->Next();
  1320.  
  1321.     WASSERT( from );
  1322.     WASSERT( from->GetDIRType() == kDIRTypeFull );
  1323.     return (FullDraftInfoRec*)from;
  1324. }
  1325.  
  1326. static pascal void OutlineButton(Rect *theBox, DialogPtr dlog)
  1327. {    
  1328.     GrafPtr oldPort;
  1329.     GetPort( &oldPort );
  1330.     SetPort( dlog );
  1331.  
  1332.     PenState curPen;
  1333.     GetPenState( &curPen );
  1334.     PenNormal();
  1335.     PenSize( 3, 3 );
  1336.     FrameRoundRect( theBox, 16, 16 );
  1337.     
  1338.     SetPenState( &curPen );
  1339.     SetPort( oldPort );
  1340. }
  1341.  
  1342. static pascal void DrawBlackBoxItem(DialogPtr dlog, short theItem)
  1343. {
  1344.     Rect     boxRect;
  1345.     Handle    scratchHandle;
  1346.     short    scratchKind;
  1347.     
  1348.     GetDialogItem(dlog, theItem, &scratchKind, &scratchHandle, &boxRect);
  1349.     switch ( theItem )
  1350.     {
  1351.         case kDraftsHorizRectUserItem:
  1352.         case kDraftsHeaderRectUserItem:
  1353.             DrawItemFrame(dlog,theItem);
  1354.             break;
  1355.         case kDraftsCreateUserItem:
  1356.         case kDraftsDoneUserItem:
  1357.             ODBoolean createIsDefault = CREATEISSET(((WindowPeek)dlog)->refCon);
  1358.             if ( createIsDefault && theItem == kDraftsCreateUserItem)
  1359.                 OutlineButton(&boxRect, dlog);
  1360.             else if ( !createIsDefault && theItem == kDraftsDoneUserItem)
  1361.                 OutlineButton(&boxRect, dlog);
  1362.             break;
  1363.         case kDraftsListUserItem:
  1364.             LUpdate(dlog->visRgn, GETLISTHANDLE(((WindowPeek)dlog)->refCon));
  1365.             Rect listRect;
  1366.             GETLISTRECT( ((WindowPeek)dlog)->refCon, &listRect );
  1367.             FrameRect( &listRect );
  1368.             break;
  1369.     }
  1370. }
  1371.  
  1372. static void ContractList( FullDraftInfoRec* dir, ListHandle listH,    short parentRowNum )
  1373. {
  1374.     WASSERT( dir );
  1375.     WASSERT( dir->GetDIRType() == kDIRTypeFull );
  1376.  
  1377.     DisposeIText( dir->GetComment() );
  1378.     dir->UncacheComment();
  1379.  
  1380.     // Patch around the dummy entries and dispose them.  Remember that
  1381.     // ~DraftInfoRec deletes fNext recursively, so clip the list free
  1382.     // at both ends before deleting.
  1383.  
  1384.     DummyDraftInfoRec* findNextFull = (DummyDraftInfoRec*)dir->Next();
  1385.     WASSERT(findNextFull);
  1386.     DummyDraftInfoRec* rememberPrev = kODNULL;
  1387.     short removedCount = 0;
  1388.     while ( findNextFull && (findNextFull->GetDIRType() != kDIRTypeFull) )
  1389.     {
  1390.         rememberPrev = findNextFull;
  1391.         findNextFull = (DummyDraftInfoRec*)findNextFull->Next();
  1392.         ++removedCount;
  1393.     }
  1394.     WASSERT( rememberPrev );
  1395.     rememberPrev->SetNext( kODNULL );
  1396.     delete dir->Next();        // this is the head of the list
  1397.  
  1398.     dir->SetNext( findNextFull );
  1399.     
  1400.     LDelRow( removedCount, parentRowNum, listH );
  1401. }
  1402.  
  1403. static TEHandle ITextToTERec( ODIText* iText, Rect* bothRects )
  1404. {
  1405.     TEHandle hTE = TENew( bothRects, bothRects );
  1406.  
  1407.     short newFont = GetScriptVariable( GetITextScriptCode(iText),
  1408.             smScriptAppFond );
  1409.     (*hTE)->txFont = newFont;
  1410.     TESetText( GetITextPtr( iText ), GetITextStringLength(iText), hTE );
  1411.     return hTE;
  1412. }
  1413.  
  1414. static void ExpandList( FullDraftInfoRec* dir, ListHandle listH, DialogPtr dialog,
  1415.         short parentRowNum )
  1416. {
  1417.     WASSERT(dir);
  1418.     WASSERT(dir->GetDIRType() == kDIRTypeFull);
  1419.     
  1420.     // Get the text of the comment, figure out how many lines it'll require
  1421.     // not truncated, and create dummy DraftInfoRecs each of them holding
  1422.     // one line.  TE will calculate line breaks based on a rect given,
  1423.     // so use the left and right fields from the comments column.
  1424.     // REMEMBER that the first line goes in the existing "parent" entry.
  1425.     
  1426.     Rect itemRect;
  1427.     short ignoreType;
  1428.     Handle ignoreHandle;
  1429.     GetDialogItem( dialog, kDraftsCommentStaticTxt, &ignoreType, &ignoreHandle,
  1430.             &itemRect );
  1431.     itemRect.top = 0;
  1432.     itemRect.bottom = 0x7fff;        // why be shy?
  1433.     itemRect.right -= 1;            // make TE linewrap same as our trunc function
  1434.     
  1435.     ODIText* iText = dir->GetComment();
  1436.     // save off the truncatable comment for when we're contracted
  1437.     dir->CacheComment();
  1438.     
  1439.     TEHandle teh = ITextToTERec( iText, &itemRect );
  1440.  
  1441.     HLock( (Handle)teh );
  1442.     HLock( (*teh)->hText );
  1443.     char* currentLine = *(*teh)->hText;
  1444.     short* curLineStart = (*teh)->lineStarts;
  1445.     WASSERT( *curLineStart == 0 );
  1446.     ODScriptCode script = GetITextScriptCode( iText );
  1447.     ODLangCode lang = GetITextLangCode( iText );
  1448.     
  1449.     FullDraftInfoRec* savedNext = (FullDraftInfoRec*)dir->Next();
  1450.     DraftInfoRec* currentParent = dir;
  1451.     ODBoolean hiliteState = dir->ShouldHilite();
  1452.     
  1453.     short numLines = (*teh)->nLines;
  1454.     LSetDrawingMode(kODFalse, listH);                                    /* turn list drawing off */
  1455.     AddRows( listH, parentRowNum, numLines-1 );
  1456.     LSetDrawingMode(kODTrue, listH);                                    /* turn list drawing off */
  1457.     for ( short i = 0 ;i < numLines; ++i )
  1458.     {
  1459.         ODUByte* thisLine = (ODUByte*)¤tLine[*curLineStart++];
  1460.         ODUByte* nextLine = (ODUByte*)¤tLine[*curLineStart];
  1461.         ODSize len = nextLine - thisLine;
  1462.         ODIText* partialComment = CreateIText( script, lang, thisLine, len );
  1463.  
  1464.         if ( i == 0 )
  1465.         {
  1466.             dir->SetComment( partialComment );
  1467.         }
  1468.         else
  1469.         {
  1470.             DummyDraftInfoRec* newDummy = new DummyDraftInfoRec;
  1471.             newDummy->SetComment( partialComment );
  1472.             newDummy->SetCommentOwner( dir );
  1473.             newDummy->SetShouldHilite( hiliteState );
  1474.             
  1475.             currentParent->SetNext(newDummy);
  1476.             currentParent = newDummy;
  1477.         }
  1478.     }
  1479.     
  1480.     TEDispose( teh );
  1481.     currentParent->SetNext(savedNext);
  1482. }
  1483.  
  1484. ODBoolean DraftWindow::ProcessMousedownInList( DialogPtr dialog,
  1485.         ListHandle listH, Point mpt )
  1486. {
  1487.     // get last cell clicked in, but
  1488.     // ignore it if the cell doesn't exist (why is this necessary?)
  1489.     Cell lastClick = LLastClick( listH );
  1490.     if ( (lastClick.v) == -1 ||
  1491.             (lastClick.v >= (*listH)->dataBounds.bottom) )
  1492.         return kODFalse;
  1493.  
  1494.     ODBoolean result = kODFalse;
  1495.  
  1496.     DraftInfoRec* dir = GetNthRow( fDraftInfo, lastClick.v );
  1497.     WASSERT( dir );
  1498.  
  1499.     if ( dir->GetDIRType() == kDIRTypeDummy )
  1500.     {
  1501.         DraftInfoRec* parent =
  1502.                 ((DummyDraftInfoRec*)dir)->GetCommentOwner();
  1503.         ODBoolean isHilited = dir->ShouldHilite();
  1504.         WASSERT( isHilited == parent->ShouldHilite() );
  1505.         if ( !isHilited )
  1506.         {
  1507.             this->SetHilite( parent, 0 );
  1508.             result = kODTrue;
  1509.         }
  1510.         return result;
  1511.     }
  1512.  
  1513.     Rect scratchRect;
  1514.     short itemType;
  1515.     Handle ignore;
  1516.     GetDialogItem(dialog, kDraftsArrowStaticTxt, &itemType,
  1517.             &ignore, &scratchRect);
  1518.     ODBoolean inGrowColumn = (mpt.h > scratchRect.left)
  1519.             && (mpt.h < scratchRect.right);
  1520.     
  1521.     if ( inGrowColumn && ((FullDraftInfoRec*)dir)->CanExpand() )
  1522.     {
  1523.         if ( ((FullDraftInfoRec*)dir)->IsExpanded() )
  1524.             ContractList( (FullDraftInfoRec*)dir, listH, lastClick.v );
  1525.         else
  1526.             ExpandList( (FullDraftInfoRec*)dir, listH, dialog, lastClick.v );
  1527.         result = kODTrue;
  1528.     }
  1529.     else if ( !dir->ShouldHilite() )
  1530.     {
  1531.         this->SetHilite( dir, 0 );
  1532.         result = kODTrue;
  1533.     }
  1534.     return result;
  1535. }
  1536.  
  1537.  
  1538. static pascal ODBoolean CheckDeleteKeyFilterProc( DialogPtr dialog, EventRecord *event,
  1539.         short *itemHit)
  1540. {
  1541.     ODBoolean result = kODFalse;
  1542.     ODBoolean isDraftsDlog = ((WindowPeek)dialog)->refCon != 0;
  1543.  
  1544.     if (event->what == keyDown)
  1545.     {
  1546.         const char kDeleteButton = 0x08;
  1547.         char key = event->message & charCodeMask;
  1548.         if ( key == kDeleteButton )
  1549.         {
  1550.             if ( isDraftsDlog )
  1551.             {
  1552.                 *itemHit = kDraftsDeleteBtn;
  1553.                 result = kODTrue;
  1554.             }
  1555.             else
  1556.             {
  1557.                 *itemHit = kDeleteDraftsDeleteBtn;
  1558.                 result = kODTrue;
  1559.             }
  1560.         }
  1561.     }
  1562.     if ( result )
  1563.         FlashButtonItem( dialog, *itemHit );
  1564.     else
  1565.     {
  1566.         if ( isDraftsDlog )
  1567.             result = DraftDlgFilterProc( dialog, event, itemHit );
  1568.         else
  1569.             result = ODDialogFilterProc( dialog, event, itemHit );
  1570.     }
  1571.  
  1572.     return result;
  1573. }
  1574.  
  1575. static void SetButtonStates( DialogPtr dlog, ODBoolean hasWriteAccess,
  1576.         Boolean hasContent )
  1577. {
  1578.     short openHiliteState = hasContent? kDraftsActiveControl : 255;
  1579.     short deleteHiliteState
  1580.             = hasContent && hasWriteAccess? kDraftsActiveControl : 255;
  1581.  
  1582.     short ignoreT;
  1583.     ControlHandle control;
  1584.     Rect ignoreR;
  1585.  
  1586.     GetDialogItem( dlog, kDraftsDeleteBtn, &ignoreT,
  1587.             (Handle*)&control, &ignoreR );
  1588.     HiliteControl( control, deleteHiliteState);
  1589.     SetControlReference( control, deleteHiliteState );
  1590.  
  1591.     GetDialogItem( dlog, kDraftsOpenBtn, &ignoreT, (Handle*)&control,
  1592.             &ignoreR );
  1593.     HiliteControl( control, openHiliteState );
  1594.     SetControlReference( control, openHiliteState );
  1595. }
  1596.  
  1597. static void AddRows( ListHandle listH, short startIndex, short numToAdd )
  1598. {
  1599.     char aByte = 'a' ;
  1600.     Cell newCell;
  1601.     newCell.h = 0;
  1602.     short finalIndex = startIndex + numToAdd;
  1603.     while ( startIndex < finalIndex )
  1604.     {
  1605.         LAddRow(1, startIndex, listH);
  1606.         newCell.v = startIndex++;
  1607.         LSetCell( &aByte, 1, newCell, listH );
  1608.     }
  1609. }
  1610.  
  1611. //------------------------------------------------------------------------------
  1612. // Callback to let LDEF communicate with DraftWindow
  1613. //------------------------------------------------------------------------------
  1614.  
  1615. void DrawDWUserStrings( struct DraftLDEFCallbackInfo *callbackInfo,
  1616.         ODSShort row, const Rect* listItemRect)
  1617. {
  1618.     DraftInfoRec *dir = callbackInfo->dir ;
  1619.     WASSERT(dir);
  1620.  
  1621.     TRY    // much of what follows can't throw, but some of it can, so I'm
  1622.         // making this thing cover nearly all of the routine.  The overhead
  1623.         // is paid but once anyway.
  1624.  
  1625.         dir = GetNthRow( dir, row );
  1626.         WASSERT( dir );
  1627.     
  1628.         DialogPtr dlog = callbackInfo->dialog;
  1629.         Rect localRect;
  1630.         localRect.top = listItemRect->top;
  1631.         localRect.bottom = listItemRect->bottom;
  1632.         
  1633.         ODIText* fourStrings[kNumColumns];
  1634.         fourStrings[kCommentsColumnIndex] = dir->GetComment();
  1635.         ODBoolean isFullType = dir->GetDIRType() == kDIRTypeFull;
  1636.         if ( isFullType )
  1637.         {
  1638.             fourStrings[0] = ((FullDraftInfoRec*)dir)->GetModifiedBy();
  1639.             fourStrings[1] = ((FullDraftInfoRec*)dir)->GetNumberString();
  1640.             fourStrings[2] = ((FullDraftInfoRec*)dir)->GetCreated();
  1641.         }
  1642.         else
  1643.         {
  1644.             WASSERT(dir->GetDIRType() == kDIRTypeDummy);
  1645.             fourStrings[0] = fourStrings[1] = fourStrings[2] = kODNULL;
  1646.         }
  1647.     
  1648.         // Determination whether a comment is too long to be drawn in a single
  1649.         // line is done lazily: it's put off until now, where the DrawITextInDlogBox
  1650.         // function get the necessary information as part of its job.  So now, in
  1651.         // addition to drawing the strings, we need to save off that information.
  1652.     
  1653.         ODBoolean truncatedThisComment = kODFalse;        // default values
  1654.         ODBoolean mayWantToTruncate;
  1655.         for ( short index = 0; index < kNumColumns; ++index )
  1656.         {
  1657.             localRect.left = callbackInfo->rectEnds[index].left;
  1658.             localRect.right = callbackInfo->rectEnds[index].right;
  1659.             if ( fourStrings[index] )
  1660.             {
  1661.                 // don't try to truncate if guaranteed short enough already.  This fixes
  1662.                 // TextEdit's ignoring of training spaces when calculating line breaks.
  1663.                 // If this is a dummy record, we *know* that the comment will fit; otherwise
  1664.                 // check if this is an expanded full record's comments column, in which
  1665.                 // case we've already clipped the comments to fit.
  1666.                 mayWantToTruncate = isFullType &&
  1667.                         ((index != kCommentsColumnIndex)
  1668.                         || !(((FullDraftInfoRec*)dir)->IsExpanded()));
  1669.                 ODBoolean truncatedThisColumn =
  1670.                         DrawITextInDlogBox( fourStrings[index],
  1671.                         &localRect, dlog, mayWantToTruncate );
  1672.                 if ( index == kCommentsColumnIndex )
  1673.                     truncatedThisComment =
  1674.                             truncatedThisComment || truncatedThisColumn;
  1675.             }
  1676.         }
  1677.         if ( truncatedThisComment )
  1678.         {
  1679.             WASSERT( dir->GetDIRType() == kDIRTypeFull );
  1680.             WASSERT( ((FullDraftInfoRec*)dir)->IsExpanded() == kODFalse );
  1681.             // record that this entry has a too-long comment
  1682.             ((FullDraftInfoRec*)dir)->SetCanExpand();
  1683.         }
  1684.     
  1685.         // now decide whether we need to draw the expansion icon and draw
  1686.         // the right one.
  1687.         
  1688.         if ( isFullType && ((FullDraftInfoRec*)dir)->CanExpand() )
  1689.         {
  1690.             localRect.left = callbackInfo->arrowEnds.left;
  1691.             localRect.right = callbackInfo->arrowEnds.right;
  1692.     
  1693.             ODSLong savedRefNum;
  1694.             BeginUsingLibraryResources(savedRefNum);        
  1695.             OSErr err = PlotIconID( &localRect, atNone, ttNone,
  1696.                     ((FullDraftInfoRec*)dir)->IsExpanded() ?
  1697.                     kDWOpenTriangleResID : kDWClosedTriangleResID );
  1698.             EndUsingLibraryResources(savedRefNum);
  1699.         }
  1700.  
  1701.         // finally, hilite if this record is [part of] the selection
  1702.         if ( dir->ShouldHilite() )
  1703.         {
  1704.             short oldPenMode = dlog->pnMode;
  1705.             PenMode( hilitetransfermode );
  1706.             PaintRect( listItemRect ) ;
  1707.             PenMode( oldPenMode );
  1708.         }
  1709.  
  1710.     CATCH_ALL
  1711.         WARN( "ignoring error in DrawDWUserStrings" );
  1712.     ENDTRY
  1713. }
  1714.  
  1715.  
  1716.  
  1717.  
  1718.