home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / SW Demo / Demo Source / SpellHandler.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-10  |  31.5 KB  |  1,069 lines  |  [TEXT/MPCC]

  1. #include "SpellHandler.h"
  2. #include "SpellWright.h"
  3. #include "ctype.h"
  4. #include "string.h"
  5. #include "WindowHandler.h"
  6. #include "Globals.h"
  7. #include "Strings.h"
  8. #include "TEHandler.h"
  9.  
  10. char *GetNextWord(TEHandle    theTE);
  11. void SpellIgnore(char *word, TEHandle theTE, DialogPtr SpellDialog);
  12. void SpellIgnoreAll(char *word, TEHandle theTE, DialogPtr SpellDialog);
  13. void SpellReplace(char *word, TEHandle theTE, DialogPtr SpellDialog);
  14. void SpellReplaceAll(char *word, TEHandle theTE, DialogPtr SpellDialog);
  15. void SpellSuggest(char *word, TEHandle theTE, DialogPtr SpellDialog);
  16. void SpellAdd(char *word, TEHandle theTE, DialogPtr SpellDialog);
  17. void DialogSuggestion(DialogPtr SpellDialog);
  18. void SpellOptions(void );
  19. void InitializeList(ListHandle theList);
  20. void DoSuggest(DialogPtr SpellDialog);
  21. pascal Boolean ListHandler( DialogPtr theDialog, EventRecord *theEvent, short *itemHit);
  22. Boolean GetNextMisspell(TEHandle theTE, DialogPtr theDialog);
  23. void MakeSpellWindow(void);
  24.  
  25. // ----------------------------------------------------------------------------------
  26. // Moveable Dialog Stuff
  27. // Copywrite 1994 Jim Stout
  28. // ----------------------------------------------------------------------------------
  29.  
  30.  
  31.  
  32. typedef pascal char (*filterProc)(DialogPtr, EventRecord *, short *);
  33.  
  34. pascal void     movableModalDialog    (filterProc filter, short *theItem);
  35. static short     preFilterEvent        (DialogPtr d, EventRecord *theEvent);
  36. static short     doMouseDialog        (DialogPtr d, EventRecord * theEvent);
  37. extern void     diskEvent            (EventRecord *theEvent);
  38.  
  39.  
  40. extern Boolean TrapAvailable ( short tNum, short tType);
  41. extern void DrawClippedGrowIcon(WindowPtr theWindow);
  42.  
  43. // ----------------------------------------------------------------------------------
  44.  
  45. ListHandle         theList;
  46. short            listCount = 0;
  47. static short    where;
  48. static short    oldwhere;
  49. static short    whereEnd;
  50. char            *currentWord;
  51. Boolean            newCheck;
  52. SWChecker        gtheSpeller;
  53. short            theCase;
  54. short            Duplicate;
  55. short            toReplace;
  56. WordInfo         theInfo;
  57.  
  58. static unsigned long        theDocDict = 0;
  59. static unsigned long        theMainDict = 0;
  60. static unsigned long        theUserDict = 0;
  61. static unsigned long        theSkipDict = 0;
  62. static unsigned long        theAutoDict = 0;
  63. static unsigned long        theSuggestDict = 0;
  64. static unsigned long        gMain = 0;
  65.     
  66. // ----------------------------------------------------------------------------------
  67. // Moveable Modal Windows
  68. // Copywrite Jim Stout 1994
  69. // 
  70. // These enable the modal dialog to be moved around
  71. // ----------------------------------------------------------------------------------
  72.  
  73. // ----------------------------------------------------------------------------------
  74. // UpdateWindow
  75. // ----------------------------------------------------------------------------------
  76. // Handles updating the window.  Nothing done here
  77.  
  78. void updateWindow(WindowPtr theWindow)
  79. {
  80.     GrafPtr        savePort;
  81.     TEHandle    theTE;
  82.     
  83.     theTE = GetTE(theWindow);
  84.     BeginUpdate(theWindow);    
  85.     
  86.     GetPort(&savePort);                        // Save the port
  87.     SetPort(theWindow);                
  88.     EraseRect(&theWindow->portRect);        // Erase the window
  89.     TEUpdate( &(theWindow->portRect), theTE );
  90.     DrawClippedGrowIcon(theWindow);        // Draw the grow icon
  91.     DrawControls(theWindow);                // Draw the window's controls    
  92.     UpdateDocWindow(theWindow);
  93.     SetPort(savePort);                        // Restore the port
  94.     
  95.     EndUpdate(theWindow);
  96.     
  97. }
  98.  
  99. // ----------------------------------------------------------------------------------
  100. // moveableModalDialog
  101. // ----------------------------------------------------------------------------------
  102. // Replaces the ModalDialog toolbox call and lets you move your window around.
  103.  
  104. pascal void movableModalDialog(filterProc filter, short *theItem)
  105. {
  106.     EventRecord theEvent;
  107.     DialogPtr    d,thisDialog;
  108.     
  109.     thisDialog = FrontWindow();
  110.     
  111.     for(;;) {
  112.         WaitNextEvent(everyEvent, &theEvent, 20, 0L);
  113.         if(*theItem = preFilterEvent(thisDialog, &theEvent))
  114.             break;
  115.         
  116.         if (filter != nil)
  117.             if (filter(thisDialog, &theEvent, theItem))
  118.                 break;
  119.  
  120.         if (IsDialogEvent(&theEvent))
  121.             if (DialogSelect(&theEvent, &d, theItem))
  122.                 break;
  123.     }
  124. }
  125.  
  126. // ----------------------------------------------------------------------------------
  127. // preFilterEvent
  128. // ----------------------------------------------------------------------------------
  129. // Handles events before the filter routine of the dialog manager
  130.  
  131. static short preFilterEvent(DialogPtr d, EventRecord *theEvent)
  132. {
  133.     short ret=0;
  134.     
  135.     switch (theEvent->what) {
  136.         case mouseDown:
  137.             ret = doMouseDialog(d,theEvent);         /* handle drag etc. of dialog        */
  138.         break;
  139.         case diskEvt:
  140.             diskEvent(theEvent);
  141.         break;
  142.         case updateEvt:
  143.             if(d != (DialogPtr)theEvent->message)
  144.                 /* pass update evt back to mainline    */
  145.                 updateWindow((WindowPtr)theEvent->message);    
  146.         break;
  147.     }
  148.     return (ret);
  149. }
  150.  
  151. // ----------------------------------------------------------------------------------
  152. // doMouseDialog
  153. // ----------------------------------------------------------------------------------
  154. // handle mouse events in the dialog box
  155.  
  156. static short doMouseDialog(DialogPtr d, EventRecord *theEvent)
  157. {
  158.     WindowPtr    theWindow;
  159.     short        partCode, ret=0;
  160.     
  161.     switch (partCode = FindWindow(theEvent->where,&theWindow)) {
  162.         case inDrag:
  163.             if(theWindow == d) {
  164.                 DragWindow(d, theEvent->where, &qd.screenBits.bounds);
  165.                 theEvent->what = nullEvent;
  166.             }
  167.             break;
  168.         
  169.         case inMenuBar:
  170.             MenuSelect(theEvent->where);
  171.             HiliteMenu(0);
  172.             break;
  173.  
  174.         case inGoAway:
  175.             if (TrackBox (theWindow, theEvent->where, partCode)) {
  176.                 ret = cancel;
  177.                 theEvent->what = nullEvent;
  178.             }
  179.             break;
  180.         case inGrow:
  181.             break;
  182.         case inZoomIn:
  183.         case inZoomOut:
  184.             break;
  185.         case inContent:
  186.             break;
  187.         default:
  188.             break;
  189.     }
  190.     return(ret);
  191. }
  192.  
  193. // ----------------------------------------------------------------------------------
  194. // Handle disk events
  195. // ----------------------------------------------------------------------------------
  196. // Handles disk insertion events
  197.  
  198. void diskEvent(EventRecord *theEvent)
  199. {
  200.     Point diskInitPt;
  201.  
  202.     if (HiWord (theEvent->message) != noErr) {
  203.         diskInitPt.v = 120;
  204.         diskInitPt.h = 100;
  205.         DILoad ();
  206.         (void) DIBadMount (diskInitPt, theEvent->message);
  207.         DIUnload ();
  208.         theEvent->what = nullEvent;
  209.     }
  210. }
  211.  
  212.  
  213. // ----------------------------------------------------------------------------------
  214. // Initialize Main Dictionary
  215. // ----------------------------------------------------------------------------------
  216. // By popular demand this is an automatically opened main dictionary.  This function
  217. // looks for a dictionary named "Main Dictionary" and if it exists automatically
  218. // opens it, storing it's number in gMain.
  219.  
  220. void InitMainDict(void)
  221. {
  222.     short                vRefNum;
  223.     FSSpec                theFile;
  224.     StandardFileReply    reply;
  225.     
  226.     SFTypeList    types = {'Dict'};
  227.  
  228.     if ( GetVol(0, &vRefNum) )
  229.         return;
  230.         
  231.     if ( FSMakeFSSpec( vRefNum, 0, "\p:Main Dictionary", &theFile) )
  232.     {    // file doesn't exist
  233.         // prompt for a dictionary
  234.         StandardGetFile(nil, 1, types, &reply);
  235.         if (reply.sfGood)
  236.             DictOpen(gtheSpeller, &gMain, MAIN_DICT, 15, &reply.sfFile); 
  237.         
  238.         if (GetSpellError())
  239.             DictClose(gtheSpeller, gMain);
  240.     
  241.         return;
  242.     }
  243.     
  244.     DictOpen(gtheSpeller, &gMain, MAIN_DICT, 15, &theFile); 
  245.     
  246. }
  247.  
  248.  
  249. // ----------------------------------------------------------------------------------
  250. // GetNextWord
  251. // ----------------------------------------------------------------------------------
  252. // This gets the next word in the TE text.  A globals keep track of where we are
  253. // in the text.  Right now the word delineator is merely any non-alphanum char.
  254. // The string returned by this function is stored internally as a static variable,
  255. // so don't mangle the pointer by trying to free it or something.
  256.  
  257. char *GetNextWord(TEHandle    theTE)
  258. {
  259.     CharsHandle theText;
  260.     short    counter = 0;
  261.     static char    word[60];
  262.     short finish;
  263.     
  264.     theText = TEGetText(theTE);
  265.  
  266.     finish = whereEnd - 1;
  267.     
  268.     // skip white space & punctuation
  269.     while (( !isalnum(*(*theText + where)) )  && (where <= finish))
  270.     {    where++;
  271.     }
  272.     
  273.     if (where >= whereEnd)
  274.         return nil;
  275.     
  276.     oldwhere = where;
  277.     while (( isalnum(*(*theText + where + counter)) ) && (counter<59) && (where + counter <= finish))
  278.     {    word[counter] = *(*theText + where + counter);
  279.         counter++;
  280.     } // while
  281.     
  282.     where += counter;
  283.     word[counter] = '\0';
  284.     TESetSelect(oldwhere, where, theTE);
  285.     return (word);
  286.  
  287. } // GetNextWord
  288.  
  289. // ----------------------------------------------------------------------------------
  290. // SpellIgnore
  291. // ----------------------------------------------------------------------------------
  292. // Does nothing, as the word is being ignored.  I could add something here in the
  293. // future if I wanted.
  294.  
  295. void SpellIgnore(char *word, TEHandle theTE, DialogPtr SpellDialog)
  296. {
  297.     return;     // gets next word
  298. } // SpellIgnore
  299.  
  300. // ----------------------------------------------------------------------------------
  301. // SpellIgnoreAll
  302. // ----------------------------------------------------------------------------------
  303. // Ignores the word and also adds it to the Skip Dictionary.  If a skip dictionary
  304. // hasn't been opened then this doesn't work too well.  I'll probably create a 
  305. // specific skip dictionary for this soon.
  306. // 
  307.  
  308. void SpellIgnoreAll(char *word, TEHandle theTE, DialogPtr SpellDialog)
  309. {
  310.     if (theSkipDict)
  311.         AddToDictionary(gtheSpeller, theSkipDict, word, nil, nil);
  312.     return;
  313. }
  314.  
  315. // ----------------------------------------------------------------------------------
  316. // SpellReplace
  317. // ----------------------------------------------------------------------------------
  318. // This gets the text of the replacement field and replaces the current word with
  319. // it, updating the selection and our location counters.  Basically it selects
  320. // the current word, deletes it, and inserts some more text.  Other than the
  321. // Dialog munging there are only really three commands.
  322.  
  323. void SpellReplace(char *word, TEHandle theTE, DialogPtr SpellDialog)
  324. {
  325.     short    tempItem;
  326.     Handle    tempHandle;
  327.     Rect    tempRect;
  328.     Str255    theWord;
  329.     GrafPtr    oldport;
  330.     
  331.     TESetSelect(oldwhere, where, theTE);
  332.     
  333.     GetDItem(SpellDialog, edReplace, &tempItem, &tempHandle, &tempRect);
  334.     GetIText(tempHandle, theWord);
  335.     
  336.     
  337.     TEDelete(theTE);    // delete the old word
  338.     TEInsert(theWord +1 , theWord[0], theTE);    // insert the replacement word
  339.     
  340.     TESetSelect(oldwhere, oldwhere + theWord[0] + 1, theTE);
  341.     whereEnd = whereEnd - (where - oldwhere) + theWord[0];    // adjust end for new word
  342.  
  343.  
  344.     where = oldwhere;    // check this word
  345.     
  346.     // Clean up windowing artifacts
  347.     GetPort(&oldport);
  348.     SetPort(gDocWindow);
  349.     
  350.     SetPort(oldport);
  351.     
  352. } // SpellReplace
  353.  
  354. // ----------------------------------------------------------------------------------
  355. // SpellReplaceAll
  356. // ----------------------------------------------------------------------------------
  357. // This replaces the word and then adds it to the Auto Dictionary.  It will then
  358. // be automatically replaced.  Right now you have to open the dictionary yourself
  359. // in the options menu.  The next version will do this automatically, or more likely
  360. // have a second dictionary.
  361.  
  362. void SpellReplaceAll(char *word, TEHandle theTE, DialogPtr SpellDialog)
  363. {
  364.  
  365.     SpellReplace(word, theTE, SpellDialog);
  366.     if (theAutoDict)
  367.         AddToDictionary(gtheSpeller, theAutoDict, word, nil, nil);    
  368.     
  369. } // SpellReplaceAll
  370.  
  371. // ----------------------------------------------------------------------------------
  372. // SpellSuggest
  373. // ----------------------------------------------------------------------------------
  374. // This replaces the misspelled word with the replacement word.  At the moment
  375. // that is about all it does, other than changing the current word as well.
  376.  
  377. void SpellSuggest(char *word, TEHandle theTE, DialogPtr SpellDialog)
  378. {
  379.     short    tempItem;
  380.     Handle    tempHandle;
  381.     Rect    tempRect;
  382.     Str255    theWord;
  383.     
  384.     GetDItem(SpellDialog, edReplace, &tempItem, &tempHandle, &tempRect);
  385.     GetIText(tempHandle, theWord);
  386.     
  387.     GetDItem(SpellDialog, edUnknown, &tempItem, &tempHandle, &tempRect);
  388.     SetIText(tempHandle, theWord);
  389.     
  390.     currentWord = P2CStr(theWord);
  391.     
  392.  
  393. }
  394.  
  395. // ----------------------------------------------------------------------------------
  396. // SpellAdd
  397. // ----------------------------------------------------------------------------------
  398. // Not currently used.
  399.  
  400. void SpellAdd(char *word, TEHandle theTE, DialogPtr SpellDialog)
  401. {
  402.     
  403. }
  404.  
  405.  
  406. // ----------------------------------------------------------------------------------
  407. // DialogSuggestion
  408. // ----------------------------------------------------------------------------------
  409. // This brings up a dialog box to add words to a dictionary.
  410.  
  411. void DialogSuggestion(DialogPtr SpellDialog)
  412. {
  413.     DialogPtr    SuggestDialog = nil;
  414.     short        theHit = 0;
  415.     Boolean        dDone = 0;
  416.     short        tempItem;
  417.     Handle        tempHandle;
  418.     Rect        tempRect;
  419.     Str255        addWord;
  420.     Str255        addSuggest;
  421.     Str255        addComment;
  422.     
  423.     
  424.     InitCursor();
  425.     
  426.     SuggestDialog = GetNewDialog(rSuggestion, nil, (WindowPtr) -1);
  427.     ShowWindow((WindowPtr) SuggestDialog);
  428.  
  429.  
  430.     if (SpellDialog)
  431.     {
  432.         GetDItem(SpellDialog, edUnknown, &tempItem, &tempHandle, &tempRect);
  433.         GetIText(tempHandle, addWord);
  434.         GetDItem(SuggestDialog, eAddWord, &tempItem, &tempHandle, &tempRect);
  435.         SetIText(tempHandle, addWord);
  436.         
  437.         GetDItem(SpellDialog, edReplace, &tempItem, &tempHandle, &tempRect);
  438.         GetIText(tempHandle, addSuggest);
  439.         GetDItem(SuggestDialog, eAddSuggest, &tempItem, &tempHandle, &tempRect);
  440.         SetIText(tempHandle, addSuggest);
  441.  
  442.         GetDItem(SuggestDialog, eAddWord, &tempItem, &tempHandle, &tempRect);
  443.         GetIText(tempHandle, C2PStr(currentWord));
  444.         currentWord = P2CStr((StringPtr) currentWord);
  445.         
  446.  
  447.     } // if
  448.  
  449.     DrawDialog(SuggestDialog);
  450.         
  451.     do
  452.     {    movableModalDialog( nil, &theHit);
  453.         switch (theHit)
  454.         {    case iUserAdd: 
  455.             case iAutoAdd: 
  456.             case iSuggestAdd:    
  457.                             GetDItem(SuggestDialog, eAddWord, &tempItem, &tempHandle, &tempRect);
  458.                             GetIText(tempHandle, addWord);
  459.                             
  460.                             GetDItem(SuggestDialog, eAddSuggest, &tempItem, &tempHandle, &tempRect);
  461.                             GetIText(tempHandle, addSuggest);
  462.                             
  463.                             GetDItem(SuggestDialog, eAddComment, &tempItem, &tempHandle, &tempRect);
  464.                             GetIText(tempHandle, addComment);
  465.                             
  466.                             
  467.                             if ( (theHit == iUserAdd) && theUserDict)
  468.                             {    AddToDictionary(gtheSpeller, theUserDict, P2CStr(addWord),
  469.                                     P2CStr(addSuggest), P2CStr(addComment));
  470.                         
  471.                             } else if ( (theHit == iAutoAdd) && theAutoDict)
  472.                             {    AddToDictionary(gtheSpeller, theAutoDict, P2CStr(addWord),
  473.                                     P2CStr(addSuggest), P2CStr(addComment));
  474.                             
  475.                             } else if ( (theHit == iSuggestAdd) && theSuggestDict) 
  476.                             {    AddToDictionary(gtheSpeller, theSuggestDict, P2CStr(addWord),
  477.                                     P2CStr(addSuggest), P2CStr(addComment));
  478.                             
  479.                             }
  480.                             dDone = true;    
  481.                             break;
  482.             case iCancelAdd:    
  483.                             dDone = true;
  484.                             break;
  485.         
  486.         } // switch
  487.     
  488.     
  489.     } while (!dDone);
  490.         
  491.     DisposeDialog( SuggestDialog );
  492.  
  493. } // DialogSuggestion
  494.  
  495.  
  496. // ----------------------------------------------------------------------------------
  497. // SpellOptions
  498. // ----------------------------------------------------------------------------------
  499. // This brings up a dialog box to open or create dictionaries.  Note that I can
  500. // get my own icon in the dictionary by creating it myself and then passing it
  501. // to the library.  (Those creator and type values ought to be #defined)
  502.  
  503. void SpellOptions(void )
  504. {
  505.     DialogPtr    OptionDialog = nil;
  506.     short        theHit = 0;
  507.     Boolean        dDone = 0;
  508.     Boolean        error;
  509.     OSErr        err;
  510.     
  511.     StandardFileReply    reply;
  512.     SFTypeList    types = {'Dict'};
  513.     
  514.     OptionDialog = GetNewDialog(rDictionary, nil, (WindowPtr) -1);
  515.     ShowWindow((WindowPtr) OptionDialog);
  516.     DrawDialog(OptionDialog);
  517.     
  518.     do
  519.     {    ModalDialog( nil, &theHit);
  520.         switch (theHit)
  521.         {    case iMain:        StandardGetFile(nil, 1, types, &reply);
  522.                             if (reply.sfGood)
  523.                                 DictOpen(gtheSpeller, &theMainDict, MAIN_DICT, 15, &reply.sfFile); 
  524.                             error = GetSpellError();
  525.                             break;
  526.             case iUser:        StandardGetFile(nil, 1, types, &reply);
  527.                             if (reply.sfGood)
  528.                                 DictOpen(gtheSpeller, &theUserDict, USER_DICT, 200, &reply.sfFile); 
  529.                             error = GetSpellError();
  530.                             break;
  531.                             
  532.             case iSuggest:    StandardGetFile(nil, 1, types, &reply);
  533.                             if (reply.sfGood)
  534.                                 DictOpen(gtheSpeller, &theAutoDict, SUGGEST_DICT, 200, &reply.sfFile); 
  535.                             break;
  536.                             
  537.             case iAuto:        StandardGetFile(nil, 1, types, &reply);
  538.                             if (reply.sfGood)
  539.                                 DictOpen(gtheSpeller, &theSuggestDict, AUTO_DICT, 200, &reply.sfFile); 
  540.                             break;
  541.                             
  542.             case iNSuggest:    StandardPutFile("\pSuggest Dictionary to Create", "\pSuggest", &reply);
  543.                             if (reply.sfGood)
  544.                             {    err = FSpCreate(&reply.sfFile, 'DLLL', 'Dict', reply.sfScript);
  545.                                 DictOpen(gtheSpeller, &theSuggestDict, SUGGEST_DICT, 200, &reply.sfFile);
  546.                             } 
  547.                             break;
  548.                             
  549.             case iNAuto:    StandardPutFile("\pSuggest Dictionary to Create", "\pSuggest", &reply);
  550.                             if (reply.sfGood)
  551.                             {    err = FSpCreate(&reply.sfFile, 'DLLL', 'Dict', reply.sfScript);
  552.                                 DictOpen(gtheSpeller, &theAutoDict, AUTO_DICT, 200, &reply.sfFile); 
  553.                             }
  554.                             break;
  555.                             
  556.             case iNUser:    StandardPutFile("\pSuggest Dictionary to Create", "\pSuggest", &reply);
  557.                             if (reply.sfGood)
  558.                             {    err = FSpCreate(&reply.sfFile, 'DLLL', 'Dict', reply.sfScript);
  559.                                 DictOpen(gtheSpeller, &theUserDict, USER_DICT, 200, &reply.sfFile); 
  560.                             }
  561.                             break;
  562.                             
  563.             case iNAdd:        {    DialogSuggestion(nil);
  564.                                 break;
  565.                             }
  566.  
  567.             case iCancel:    dDone = true;
  568.                             break;
  569.         
  570.         
  571.         } // switch
  572.     
  573.     
  574.     } while (!dDone);
  575.     
  576.     DisposeDialog( OptionDialog );
  577.  
  578. } // SpellOptions
  579.  
  580. // ----------------------------------------------------------------------------------
  581. // InitializeList
  582. // ----------------------------------------------------------------------------------
  583. // Not currently utilized.  If I do something odd to the list before using it
  584. // I can do it here.  I'll probably remove this code.
  585.  
  586. void InitializeList(ListHandle theList)
  587. {
  588.  
  589. }
  590.  
  591. // ----------------------------------------------------------------------------------
  592. // DoSuggest
  593. // ----------------------------------------------------------------------------------
  594. // This is the main routine.  It finds a misspelled word, enters suggestions in 
  595. // a dialog's list, and then lets the user select a suggestion and replace the
  596. // misspelling with it.  More functionality is needed here.  In practice you
  597. // would probably just use our interface which is much nicer than these 
  598. // modal dialog boxes.  Ideally we'd allow selection and replacement while
  599. // we were still getting suggestions.  It would be fairly easy to do, but I've
  600. // opted for simplicity and clarity rather than functionality in the demo.  If
  601. // you don't want to code that yourself, use our interface that does it all for
  602. // you (and will hopefully support threads under Sys7.5).
  603. //
  604. // Note: the handling of the dialog's clicks isn't done here.  This only adds
  605. // the suggestions, comments, and errors to the dialog.  The main dialog
  606. // routines are in MakeSpellWindow.
  607.  
  608. void DoSuggest(DialogPtr SpellDialog)
  609. {
  610.     Cell     cp;
  611.     Str255     theString;
  612.     Rect    tempRect;
  613.     short     tempItem;
  614.     Handle     tempHandle;
  615.     char    replace[60];
  616.     char    comment[255];
  617.  
  618.     // clear current list
  619.     LDelRow(0, 0, theList);
  620.     // Update the list
  621.     LDraw(cp, theList);
  622.     
  623.     listCount = 0;
  624.  
  625.     if (Duplicate)
  626.     {    GetDItem(SpellDialog, edSuggest, &tempItem, &tempHandle, &tempRect);
  627.         SetIText(tempHandle, "\pDuplicate Word");
  628.         return;
  629.     } // if
  630.         
  631.     // Add the first suggestion.  (This resets the suggestion indicator)
  632.     if (FindFirstSuggestion(gtheSpeller, gMain + theDocDict + theMainDict + theUserDict + theSkipDict + 
  633.             theAutoDict + theSuggestDict, 0, currentWord, replace, comment, &toReplace)) 
  634.     {    
  635.         // check to see if there was an error (due to a number)
  636.         if (GetSpellError())
  637.             return;
  638.         
  639.         // make sure the case matches
  640.         FixCase(gtheSpeller, replace, theInfo.Case);
  641.         
  642.         listCount = LAddRow(1, listCount + 1, theList);
  643.  
  644.         cp.h = 0;
  645.         cp.v = listCount;
  646.         
  647.         LAddToCell(replace, strlen(replace), cp, theList);
  648.         
  649.         // Update the list
  650.         LDraw(cp, theList);
  651.         
  652.         // put in replace
  653.         GetDItem(SpellDialog, edReplace, &tempItem, &tempHandle, &tempRect);
  654.         SetIText(tempHandle, C2PStr(replace) );
  655.         
  656.             
  657.         if (comment[0] != '\0')
  658.         {    GetDItem(SpellDialog, edSuggest, &tempItem, &tempHandle, &tempRect);
  659.             SetIText(tempHandle, C2PStr(comment));
  660.         } // if
  661.         
  662.  
  663.     
  664.     } // if
  665.     
  666.     // Add all the suggestions.  NOT_FOUND = 0, so we can use FindNextSuggestion like
  667.     // this.  Here we merely add the suggestions to the list.
  668.     
  669.     while (FindNextSuggestion(gtheSpeller, gMain + theDocDict + theMainDict + theUserDict + theSkipDict + 
  670.             theAutoDict + theSuggestDict, 0, currentWord, replace, comment, &toReplace))
  671.     {    
  672.         // make sure the case is correct
  673.         FixCase(gtheSpeller, replace, theInfo.Case);
  674.  
  675.         // clear current list
  676.         
  677.         listCount = LAddRow(1, listCount + 1, theList);
  678.  
  679.         cp.h = 0;
  680.         cp.v = listCount;
  681.         
  682.         LAddToCell(replace, strlen(replace), cp, theList);
  683.         // Update the list
  684.         LDraw(cp, theList);    
  685.     } // while
  686.     
  687. } // DoSuggest
  688.  
  689.  
  690.  
  691. // ----------------------------------------------------------------------------------
  692. // ListHandler
  693. // ----------------------------------------------------------------------------------
  694. // This handles clicks in the list.  It is passed to the Dialog manager as a callback
  695. // routine.  This way we can update the list and dialog box.  Here we merely check
  696. // for a click and update the replacement word with the clicked cell.  A double
  697. // click replaces the misspelled word with the suggestion double clicked on.
  698.  
  699. pascal Boolean ListHandler( DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  700. {
  701.     
  702.     Rect         tempR;
  703.     Boolean     returnValue = false;
  704.     Boolean     theBoolean;
  705.     WindowPtr     oldP;
  706.     char        theWord[60];
  707.     Rect         tempRect;
  708.     short         tempItem;
  709.     Handle         tempHandle;
  710.     Cell        theCell;
  711.      short        size;
  712.  
  713.     
  714.     // get the current port, set the port to this dialog
  715.     GetPort(&oldP);
  716.     SetPort(theDialog);
  717.     
  718.     // was this an update event for this dialog?
  719.     if (  (theEvent->what == updateEvt) && ( theEvent->message == (long) theDialog)) 
  720.     {
  721.         
  722.         // Update the list.
  723.         LUpdate(theDialog->visRgn, theList);
  724.         
  725.         // get the list rectangle
  726.         tempR = (*theList)->rView;
  727.         
  728.         // push it outwards one pixel and frame the list
  729.         InsetRect(&tempR, -1, -1);
  730.         FrameRect(&tempR);
  731.                 
  732.     } else {
  733.         // see if this was a mouseDown event
  734.         if (theEvent->what == mouseDown) {
  735.             Point theP;
  736.  
  737.             // we set the port to the dialog on entry to the filter, so a GetMouse will work
  738.             GetMouse(&theP);
  739.             
  740.             // get the list rectangle
  741.             tempR = (*theList)->rView;
  742.             
  743.             // add the scroll bar back in for hit testing (remember we took it out earlier)
  744.             tempR.right += 16;
  745.             
  746.             // See if they clicked in our list!
  747.             if (PtInRect(theP, &tempR)) {
  748.                 theBoolean = LClick(theP, nil, theList);
  749.                 // if they double-clicked the list, replace the suggestion
  750.                 size = 60;
  751.                 tempR.right -= 15; // take the scroll bar out.
  752.                 if (theBoolean)
  753.                 {   if (PtInRect(theP, &tempR)) 
  754.                     {
  755.                         *itemHit = bReplace;        // double click does a replace
  756.         
  757.                         theCell = LLastClick(theList);    // get the cell clicked in
  758.                         LGetCell((Ptr) theWord, &size, theCell, theList);    // get the word of that cell
  759.                         theWord[size] = '\0';        // make it a c string
  760.                         
  761.                         if (*theWord != '\0')
  762.                         {    GetDItem(theDialog, edReplace, &tempItem, &tempHandle, &tempRect);
  763.                             C2PStr(theWord);
  764.                             SetIText(tempHandle, (StringPtr) theWord);
  765.                         } // if
  766.                     } else 
  767.                         *itemHit = uList;
  768.                 } // if
  769.                 else
  770.                 {    *itemHit = uList;
  771.                     if (PtInRect(theP, &tempR)) 
  772.                     {    
  773.                         
  774.                         theCell = LLastClick(theList);    // get the cell clicked in
  775.                         LGetCell((Ptr) theWord, &size, theCell, theList);    // get the word of that cell
  776.                         theWord[size] = '\0';        // make it a c string
  777.                         
  778.                         if (*theWord != '\0')
  779.                         {    GetDItem(theDialog, edReplace, &tempItem, &tempHandle, &tempRect);
  780.                             C2PStr(theWord);
  781.                             SetIText(tempHandle, (StringPtr) theWord);
  782.                         } // if
  783.                     } // if
  784.                 } // if/else
  785.                 
  786.                 // tell the Dialog Manager that we handled this click, it can stop searching for a click-owner
  787.                 returnValue = true;
  788.             } // if
  789.         } // if
  790.     } // if
  791.     
  792.     // reset the original port
  793.     
  794.     SetPort(oldP);
  795.     
  796.     return(returnValue);
  797.  
  798. } // ListHandler
  799.  
  800. // ----------------------------------------------------------------------------------
  801. // AutoReplace
  802. // ----------------------------------------------------------------------------------
  803.  
  804. void AutoReplace(TEHandle theTE, DialogPtr SpellDialog)
  805. {
  806.     char    replace[60], comment[255];
  807.     int        t;
  808.     
  809.     t = oldwhere;
  810.     
  811.     // Get suggestion (only takes first one)
  812.     if (FindFirstSuggestion(gtheSpeller, theAutoDict, 0, currentWord, replace, comment, &toReplace)) 
  813.     {
  814.         // check to see if there was an error
  815.         if (GetSpellError())
  816.             return;
  817.             
  818.         // make sure the case matches
  819.         FixCase(gtheSpeller, replace, theInfo.Case);
  820.         
  821.         // select the word
  822.         TESetSelect(oldwhere, where, theTE);
  823.         
  824.         // delete the old word
  825.         TEDelete(theTE);    
  826.     
  827.         // insert the new word and select it
  828.         C2PStr(replace);
  829.         TEInsert(replace +1 , replace[0], theTE);
  830.         TESetSelect(oldwhere, oldwhere + replace[0] + 1, theTE);
  831.         whereEnd = whereEnd - (where - oldwhere) + replace[0];
  832.         where = oldwhere; // to check this word
  833.         
  834.     } // if
  835. } // AutoReplace
  836.  
  837. // ----------------------------------------------------------------------------------
  838. // GetNextMisspell
  839. // ----------------------------------------------------------------------------------
  840. // This reads words repeatedly, checking the word with the open dictionaries.  It
  841. // stops when it reaches the end of the text or when it finds a misspelling.  It
  842. // sets the 'toReplace' flag to determine if a word is to be automatically replaced.
  843. // That functionality needs a little cleanup in the code here, as it depends upon
  844. // a user opened AutoDict.  Right now though if a word is flagged as toReplace, it
  845. // calls the replace function.  
  846. //
  847. // Note: we can send all our dictionaries to the spelling routines as each dictionary
  848. // is a long whose bit represents the dictionary.  Thus we add them all together to
  849. // get the dictionaries to be searched.  As the unused dictionaries are zero, they
  850. // add nothing to the routine.
  851.  
  852. Boolean GetNextMisspell(TEHandle theTE, DialogPtr theDialog)
  853. {
  854.     Boolean SpelledRight;
  855.     Rect tempRect;
  856.     short tempItem;
  857.     Handle tempHandle;
  858.  
  859.     Duplicate = WORD_NOT_DUPLICATED;
  860.     SpelledRight = FOUND;
  861.     
  862.     while ( (SpelledRight == FOUND) && (Duplicate == WORD_NOT_DUPLICATED ) && (currentWord != nil))
  863.     {    currentWord = GetNextWord(theTE);
  864.         if (currentWord == nil)
  865.             return false; // finished, no more text
  866.  
  867.         SpelledRight = CheckWord(gtheSpeller, gMain + theDocDict + theMainDict + theUserDict + theSkipDict + 
  868.             theAutoDict + theSuggestDict, 0, currentWord, &theInfo);
  869.     
  870.         if (newCheck && Duplicate)    // ignore first duplicate
  871.         {     newCheck = false;
  872.             Duplicate = WORD_NOT_DUPLICATED;
  873.             SpelledRight = FOUND;
  874.         } // if
  875.         
  876.         Duplicate = theInfo.Duplicate;
  877.         toReplace = theInfo.Replace;
  878.         theCase = theInfo.Case;
  879.                 
  880.         if (!SpelledRight && toReplace)
  881.         {
  882.             AutoReplace(theTE, theDialog);
  883.             SpelledRight = FOUND;    // we've corrected it now
  884.         }
  885.     } // while
  886.     
  887.  
  888.                 
  889.     // display misspelled word
  890.     GetDItem(theDialog, edUnknown, &tempItem, &tempHandle, &tempRect);
  891.     SetIText(tempHandle, C2PStr(currentWord));
  892.     currentWord = P2CStr((StringPtr)currentWord);
  893.     return true;
  894.  
  895. } // GetNextMisspell
  896.  
  897. // ----------------------------------------------------------------------------------
  898. // MakeSpellWindow
  899. // ----------------------------------------------------------------------------------
  900. // This brings up a dialog box, finds each misspelling,creates a list for each of 
  901. // suggestions, and allows the user to fix the text.  Most of this is done by
  902. // calling other routines.  The main part of this routine is initializing the
  903. // dialog and then the switch statement dealing with the user choices.  We also
  904. // create a DocDict that is basically a buffer of 'found' words.  This speeds
  905. // up the checking of words as we don't need to scan through the physical dictionary
  906. // to find the word.  Our routines make that extremely fast, but this buffer is
  907. // even faster.
  908.  
  909. void MakeSpellWindow(void)
  910. {
  911.     short        hitItem = 0;    
  912.     Rect        listRect = { 0, 0, 0, 1 };    // data boundaries of the list (1 column list)
  913.     Cell        theCell = { 0, 0 };
  914.     Str255        theString;
  915.     
  916.     Boolean        sugDone = false;
  917.     Boolean        dDone = false;    // done with dialog
  918.     
  919.     DialogPtr SpellDialog = nil;    // the window
  920.     // ModalFilterUPP    theFilter;
  921.     
  922.     Rect tempRect;
  923.     short tempItem;
  924.     Handle tempHandle;
  925.     TEHandle    theTE;
  926.     
  927.     Boolean        SpelledRight = false;
  928.     
  929.     newCheck = true;
  930.     
  931.     InitCursor();
  932.     
  933.     if (!gDocWindow)
  934.         return;
  935.     
  936.     theTE = (TEHandle) GetTE(gDocWindow);
  937.     
  938.     where = (*theTE)->selStart;
  939.     whereEnd = (*theTE)->selEnd;
  940.     
  941.     if (whereEnd <= where)
  942.     {    whereEnd = (*theTE)->teLength;
  943.         where = 0;
  944.     }
  945.  
  946.     
  947.     SpellDialog = GetNewDialog(rSpellDlog, nil, (WindowPtr) -1);
  948.     
  949.     // Setup the list
  950.     GetDItem(SpellDialog, uList, &tempItem, &tempHandle, &tempRect);
  951.     tempRect.right -= 16;
  952.     
  953.     SetPort(SpellDialog);
  954.     theList = LNew( &tempRect, &listRect, theCell, nil, SpellDialog,
  955.             false, false, false, true);
  956.             
  957.     InitializeList(theList);
  958.     LDoDraw(true, theList);
  959.     
  960.     
  961.     // Supposedly these are Sys7 routines that automatically set the default item.
  962.     if ( TrapAvailable(_DialogDispatch, ToolTrap))
  963.     {    SetDialogDefaultItem(SpellDialog, bReplace);
  964.         SetDialogCancelItem(SpellDialog, bClose);
  965.         SetDialogTracksCursor(SpellDialog, true);
  966.     }
  967.     
  968.     
  969.     
  970.     ShowWindow((WindowPtr) SpellDialog);
  971.     DrawDialog(SpellDialog);
  972.     // theFilter = NewModalFilterProc( ListHandler );
  973.     
  974.     
  975.     // Open the Document Dictionary as a buffer (buffering is automatically done)
  976.     DictOpen(gtheSpeller, &theDocDict, DOCUMENT_DICT, 100, NULL);
  977.     if ( GetSpellError() < eNo_Err)
  978.     {    DisposeDialog( SpellDialog );
  979.         EndSpellCheckSession(gtheSpeller);
  980.         return;
  981.     }
  982.  
  983.     currentWord = " "; // just to get started
  984.     
  985.     // find first wrong word before dialog    
  986.     dDone = !GetNextMisspell(theTE, SpellDialog);    // if no misspelled word then done
  987.     
  988.     
  989.     
  990.     // if there was a misspelling put up the suggestions.
  991.     if (!dDone)
  992.         DoSuggest(SpellDialog);
  993.         
  994.     while (!dDone) 
  995.     {    // ModalDialog(theFilter, &hitItem);
  996.         movableModalDialog ((filterProc) ListHandler, &hitItem );
  997.                 
  998.         switch (hitItem) {
  999.             case bIgnore:
  1000.             {
  1001.                 SpellIgnore(currentWord, theTE, SpellDialog);
  1002.                 dDone = !GetNextMisspell(theTE, SpellDialog);
  1003.                 if (!dDone)
  1004.                     DoSuggest(SpellDialog);
  1005.                 break;
  1006.             }
  1007.             case bIgnoreAll:
  1008.             {    
  1009.                 SpellIgnoreAll(currentWord, theTE, SpellDialog);
  1010.                 dDone = !GetNextMisspell(theTE, SpellDialog);
  1011.                 if (!dDone)
  1012.                     DoSuggest(SpellDialog);
  1013.                 break;
  1014.             }
  1015.             case bReplace:
  1016.             {
  1017.                 // Get replacement word
  1018.                 SpellReplace(currentWord, theTE, SpellDialog);
  1019.                 dDone = !GetNextMisspell(theTE, SpellDialog);
  1020.                 if (!dDone)
  1021.                     DoSuggest(SpellDialog);
  1022.                 break;
  1023.             }
  1024.             case bReplaceAll:
  1025.             {
  1026.                 SpellReplaceAll(currentWord, theTE, SpellDialog);
  1027.                 dDone = !GetNextMisspell(theTE, SpellDialog);
  1028.                 if (!dDone)
  1029.                     DoSuggest(SpellDialog);
  1030.                 break;
  1031.             }
  1032.             case bSuggest:
  1033.             {
  1034.                 GetDItem(SpellDialog, edReplace, &tempItem, &tempHandle, &tempRect);
  1035.                 GetIText(tempHandle, theString);
  1036.                 GetDItem(SpellDialog, edUnknown, &tempItem, &tempHandle, &tempRect);
  1037.                 SetIText(tempHandle, theString);
  1038.                 currentWord = P2CStr(theString);
  1039.                 DoSuggest(SpellDialog);
  1040.                 break;
  1041.             }
  1042.             case bAdd:
  1043.             {    DialogSuggestion(SpellDialog);
  1044.                 break;
  1045.             }
  1046.             case bOptions:
  1047.             {    SpellOptions();
  1048.                 break;
  1049.             }
  1050.             case bClose:
  1051.             {
  1052.                 dDone = true;
  1053.                 break;
  1054.             }
  1055.             default:    
  1056.                 break;
  1057.         } // case
  1058.         
  1059.         
  1060.     } // while
  1061.             
  1062.     DisposeDialog( SpellDialog );
  1063.     
  1064.     // close our document dictionary  (We could alternatively make this a global,
  1065.     // and use it for all our windows, but this way saves money and there really
  1066.     // isn't much of an advantage of keeping around anyway)
  1067.     DictClose(gtheSpeller, theDocDict);
  1068.     
  1069. } // MakeSpellWindow