home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / Ph 1.1.1 / PhClient / edit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-16  |  68.9 KB  |  2,427 lines  |  [TEXT/MPS ]

  1. /*_____________________________________________________________________
  2.  
  3.       edit.c - Edit Window Manager
  4. ____________________________________________________________________*/
  5.  
  6. /*_____________________________________________________________________
  7.  
  8.     Header Files.
  9. _____________________________________________________________________*/
  10.  
  11. #pragma load "precompile"
  12. #include "MacTCPCommonTypes.h"
  13. #include "rez.h"
  14. #include "utl.h"
  15. #include "mtcp.h"
  16. #include "serv.h"
  17. #include "glob.h"
  18. #include "edit.h"
  19. #include "login.h"
  20. #include "pswd.h"
  21. #include "open.h"
  22. #include "oop.h"
  23. #include "new.h"
  24. #include "wstm.h"
  25.  
  26. #pragma segment edit
  27.  
  28. /*_____________________________________________________________________
  29.  
  30.     Defines.
  31. _____________________________________________________________________*/
  32.  
  33. #define headerRule        26            /* v coord of top line of header double rule */
  34. #define headerHeight        (headerRule+4)        
  35.                                             /* total height of window header area */
  36. #define sBarWidth            16            /* width of scroll bar */
  37. #define sBarWidthM1        (sBarWidth-1)
  38. #define fChangedBase        11            /* base line for •=Field Changed */
  39. #define cantChangeBase    22            /* base line for ¬=Can’t Change Field */
  40. #define textMargin        4            /* left and right margins for text */
  41. #define minWindHeight    125        /* min window height */
  42. #define infoWhite1        3            /* white space before first field info rule */
  43. #define infoWhite2        3            /* white space after first field info rule */
  44. #define infoWhite3        5            /* white space before second field info rule */
  45. #define infoWhite4        5            /* white space after second field info rule */
  46. #define infoWhite            (infoWhite1+infoWhite2+infoWhite3+infoWhite4)
  47. #define infoHeight        (infoWhite + 2 + 2*LineHeight)    
  48.                                             /* total height of field info - must be even! */
  49.  
  50. /*_____________________________________________________________________
  51.  
  52.     Types.
  53. _____________________________________________________________________*/
  54.  
  55. typedef struct EditInfo {
  56.     FieldInfo            **fields;                /* handle to field info */
  57.     short                    numFields;                /* number of fields */
  58.     short                    curField;                /* current active field */
  59.     short                    aliasFieldIndex;        /* index in Fields array of alias field */
  60.     ControlHandle        scrollBar;                /* handle to scroll bar control */
  61.     ControlHandle        showFieldInfoBox;        /* handle to show field info checkbox */
  62.     ControlHandle        revertButton;            /* handle to revert field button */
  63.     ControlHandle        revertAllButton;        /* handle to revert all fields button */
  64.     RgnHandle            clipRgn;                    /* window clipped to scrolling area */
  65.     Boolean                showFieldInfo;            /* true to show field info */
  66.     Boolean                dirty;                    /* true if any changes made */
  67.     Str255                alias;                    /* alias */
  68.     Str255                server;                    /* login server */
  69.     Str255                loginAlias;                /* login alias */
  70.     Str255                pswd;                        /* login password */
  71.     short                    windNum;                    /* window number */
  72. } EditInfo;
  73.  
  74. /*_____________________________________________________________________
  75.  
  76.     Global Variables.
  77. _____________________________________________________________________*/
  78.  
  79. static Boolean            LoggedIn = false;        /* true if logged in */
  80. static WindowPtr        LoginWindow;            /* pointer to login window */
  81. static Boolean            Hero;                        /* true if hero */
  82. static Str255            Server;                    /* login server */
  83. static Str255            Alias;                    /* login alias */
  84. static Str255            Password;                /* login password */
  85. static Boolean            Proxy;                    /* true if server supports proxy menu */
  86.  
  87. static Rect                SizeRect;                /* size rectangle */
  88. static short            Width;                    /* font char width */
  89. static short            NameRight;                /* field name right margin */
  90. static short            TextLeft;                /* field text left margin */
  91. static short            TextRight;                /* field text right margin */
  92.  
  93. static oop_Dispatch dispatch = {
  94.                                 edit_DoPeriodic,
  95.                                 edit_DoClick,
  96.                                 edit_DoKey,
  97.                                 edit_DoUpdate,
  98.                                 edit_DoActivate,
  99.                                 edit_DoDeactivate,
  100.                                 edit_DoGrow,
  101.                                 edit_DoZoom,
  102.                                 edit_DoClose,
  103.                                 edit_DoCommand
  104.                             };
  105.  
  106. /*_____________________________________________________________________
  107.  
  108.     GetEditInfo - Get EditInfo Handle from Window Pointer
  109.     
  110.     Entry:    w = pointer to window record
  111.     
  112.     Exit:        Function result = handle to EditInfo record.
  113. _____________________________________________________________________*/
  114.  
  115. static EditInfo **GetEditInfo (WindowPtr w)
  116.  
  117. {
  118.     return (EditInfo**)oop_GetWindInfo(w);
  119. }
  120.  
  121. /*_____________________________________________________________________
  122.  
  123.     TextTop - Get Top Coord of Text.
  124.     
  125.     Entry:    e = handle to EditInfo record.
  126.     
  127.     Exit:        Function result = top coord of text.
  128. _____________________________________________________________________*/
  129.  
  130. static short TextTop (EditInfo **e)
  131.  
  132. {
  133.     return (**(*(**e).fields)[0].edit).viewRect.top -
  134.         ((**e).showFieldInfo ? infoHeight : 0);
  135. }
  136.  
  137. /*_____________________________________________________________________
  138.  
  139.     TextBot - Get Bottom Coord of Text.
  140.     
  141.     Entry:    e = handle to EditInfo record.
  142.     
  143.     Exit:        Function result = bottom coord of text.
  144. _____________________________________________________________________*/
  145.  
  146. static short TextBot (EditInfo **e)
  147.  
  148. {
  149.     return (**(*(**e).fields)[(**e).numFields-1].edit).viewRect.bottom;
  150. }
  151.  
  152. /*_____________________________________________________________________
  153.  
  154.     TextHeight - Compute Total Text Height.
  155.     
  156.     Entry:    e = handle to EditInfo record.
  157.     
  158.     Exit:        Function result = total text height in pixels.
  159. _____________________________________________________________________*/
  160.  
  161. static short TextHeight (EditInfo **e)
  162.  
  163. {
  164.     return TextBot(e) - TextTop(e);
  165. }
  166.  
  167. /*_____________________________________________________________________
  168.  
  169.     GetViewRect - Get View Rectangle.
  170.     
  171.     Entry:    w = pointer to window record.
  172.     
  173.     Exit:        *viewRect = view rectangle.
  174. _____________________________________________________________________*/
  175.  
  176. static void GetViewRect (WindowPtr w, Rect *viewRect)
  177.  
  178. {
  179.     *viewRect = w->portRect;
  180.     viewRect->top += headerHeight;
  181.     viewRect->bottom -= sBarWidthM1;
  182.     viewRect->right -= sBarWidthM1;
  183. }
  184.  
  185. /*_____________________________________________________________________
  186.  
  187.     MakeIbeamRgn - Make Ibeam Region.
  188.     
  189.     Entry:    w = pointer to window.
  190. _____________________________________________________________________*/
  191.  
  192. static void MakeIbeamRgn (WindowPtr w)
  193.  
  194. {
  195.     EditInfo        **e;            /* handle to edit info */
  196.     short            i;                /* loop index */
  197.     FieldInfo    *f;            /* pointer to field info record */
  198.     Rect            r;                /* textedit rectangle */
  199.     RgnHandle    rgn;            /* scratch region */
  200.     short            numFields;    /* number of fields */
  201.     RgnHandle    ibeamRgn;    /* ibeam region */
  202.  
  203.     e = GetEditInfo(w);
  204.     ibeamRgn = oop_GetWindIbeamRgn(w);
  205.     SetEmptyRgn(ibeamRgn);
  206.     rgn = NewRgn();
  207.     numFields = (**e).numFields;
  208.     HLock((Handle)(**e).fields);
  209.     for (i = 0; i < numFields; i++) {
  210.         f = &(*(**e).fields)[i];
  211.         if (f->canEdit) {
  212.             r = (**f->edit).viewRect;
  213.             r.left -= textMargin;
  214.             r.right += textMargin;
  215.             RectRgn(rgn, &r);
  216.             UnionRgn(ibeamRgn, rgn, ibeamRgn);
  217.         }
  218.     }
  219.     HUnlock((Handle)(**e).fields);
  220.     DisposeRgn(rgn);
  221. }
  222.  
  223. /*_____________________________________________________________________
  224.  
  225.     AdjustScrollMax - Adjust Scroll Bar Max Value.
  226.     
  227.     Entry:    w = pointer to window record.
  228. _____________________________________________________________________*/
  229.  
  230. static void AdjustScrollMax (WindowPtr w)
  231.  
  232. {
  233.     EditInfo            **e;                    /* handle to edit info */
  234.     short                windHeight;            /* height of window text */
  235.     short                max;                    /* computed max scroll bar value */
  236.     
  237.     SetPort(w);
  238.     e = GetEditInfo(w);
  239.     windHeight = w->portRect.bottom - sBarWidthM1 - headerHeight;
  240.     max = TextHeight(e) - windHeight;
  241.     if (max < 0) max = 0;
  242.     SetCtlMax((**e).scrollBar, max); 
  243. }
  244.  
  245. /*_____________________________________________________________________
  246.  
  247.     Scroll - Scroll the Window.
  248.     
  249.     Entry:    w = pointer to window record.
  250.                 dv = number of pixels to scroll.
  251. _____________________________________________________________________*/
  252.  
  253. static void Scroll (WindowPtr w, short dv)
  254.  
  255. {
  256.     EditInfo            **e;            /* handle to edit info */
  257.     Rect                viewRect;    /* view rectangle */
  258.     short                i;                /* loop index */
  259.     FieldInfo        *f;            /* pointer to field info */
  260.     TEHandle            edit;            /* handle to TextEdit record */
  261.     RgnHandle        rgn;            /* scratch region */
  262.     short                numFields;    /* number of fields */
  263.     RgnHandle        ibeamRgn;    /* ibeam region */
  264.  
  265.     e = GetEditInfo(w);
  266.     SetPort(w);
  267.     GetViewRect(w, &viewRect);
  268.     rgn = NewRgn();
  269.     ScrollRect(&viewRect, 0, dv, rgn);
  270.     InvalRgn(rgn);
  271.     DisposeRgn(rgn);
  272.     SetOrigin(0, 0);
  273.     numFields = (**e).numFields;
  274.     for (i = 0; i < numFields; i++) {
  275.         f = &(*(**e).fields)[i];
  276.         edit = f->edit;
  277.         OffsetRect(&(**edit).viewRect, 0, dv);
  278.         OffsetRect(&(**edit).destRect, 0, dv);
  279.     }
  280.     ibeamRgn = oop_GetWindIbeamRgn(w);
  281.     OffsetRgn(ibeamRgn, 0, dv);
  282.     oop_UpdateAll();
  283. }
  284.  
  285. /*_____________________________________________________________________
  286.  
  287.     GetLineNumber - Get Line Number of Character Position in TextEdit field.
  288.     
  289.     Entry:    pos = character position (0-based).
  290.                 h = handle to TextEdit record..
  291.                     
  292.     Exit:        function result = line number (0-based).
  293. _____________________________________________________________________*/
  294.  
  295. static short GetLineNumber (short pos, TEHandle h)
  296.  
  297. {
  298.     short            *lineStarts;            /* ptr to lineStarts array */
  299.     short            nLines;                    /* number of lines */
  300.     short            i;                            /* loop index */
  301.  
  302.     lineStarts = (**h).lineStarts;
  303.     nLines = (**h).nLines;
  304.     i = 0;
  305.     while (lineStarts[i] <= pos && i <= nLines) i++;
  306.     return i-1;
  307. }
  308.  
  309. /*_____________________________________________________________________
  310.  
  311.     AutoScroll - Make Sure Selection Range is Visible.
  312.     
  313.     Entry:    w = pointer to window record.
  314.                 fNum = field number.
  315. _____________________________________________________________________*/
  316.  
  317. static void AutoScroll (WindowPtr w, short fNum)
  318.  
  319. {
  320.     EditInfo            **e;            /* handle to edit info */
  321.     TEHandle            edit;            /* handle to TextEdit record */
  322.     short                lineStart;    /* selection range start line num */
  323.     short                lineEnd;        /* selection range end line num */
  324.     short                top;            /* top coord of field */
  325.     short                vStart;        /* selection range start v coord */
  326.     short                vEnd;            /* selection range end v coord */
  327.     Rect                viewRect;    /* view rectangle */
  328.     Boolean            tooBig;        /* true if selection is bigger than view */
  329.     short                dv;            /* number of pixels to scroll */
  330.     short                oldVal;        /* old scroll bar control value */
  331.     short                max;            /* scroll bar max value */
  332.     
  333.     e = GetEditInfo(w);
  334.     edit = (*(**e).fields)[fNum].edit;
  335.     lineStart = GetLineNumber((**edit).selStart, edit);
  336.     lineEnd = GetLineNumber((**edit).selEnd, edit);
  337.     top = (**edit).viewRect.top;
  338.     vStart = top + lineStart*LineHeight;
  339.     vEnd = top + (lineEnd+1)*LineHeight;
  340.     GetViewRect(w, &viewRect);
  341.     tooBig = (vEnd - vStart) > (viewRect.bottom - viewRect.top);
  342.     if (vEnd > viewRect.bottom) {
  343.         if (tooBig && vStart <= viewRect.top) return;
  344.         dv = viewRect.bottom - vEnd;
  345.     } else if (vStart < viewRect.top) {
  346.         if (tooBig && vEnd >= viewRect.bottom) return;
  347.         dv = viewRect.top - vStart + ((**e).showFieldInfo ? infoHeight : 0);
  348.     } else {
  349.         return;
  350.     }
  351.     oldVal = GetCtlValue((**e).scrollBar);
  352.     max = GetCtlMax((**e).scrollBar);
  353.     if (oldVal - dv > max) dv = oldVal - max;
  354.     Scroll(w, dv);
  355.     AdjustScrollMax(w);
  356.     SetCtlValue((**e).scrollBar, oldVal-dv);
  357. }
  358.  
  359. /*_____________________________________________________________________
  360.  
  361.     ChangeSize - Process Window Size Change.
  362.     
  363.     Entry:    w = pointer to window record.
  364.                 height = new window height
  365. _____________________________________________________________________*/
  366.  
  367. static void ChangeSize (WindowPtr w, short height)
  368.  
  369. {
  370.     EditInfo        **e;                    /* handle to edit info */
  371.     short            offTop;                /* amount of text scrolled off top */
  372.     short            textBot;                /* bottom text coord */
  373.     short            viewBot;                /* bottom view coord */
  374.     short            dv;                    /* amount to scroll */
  375.     Rect            viewRect;            /* view rectangle */
  376.  
  377.     e = GetEditInfo(w);
  378.     SizeControl((**e).scrollBar, sBarWidth, height-12-headerHeight);
  379.     AdjustScrollMax(w);
  380.     offTop = headerHeight - TextTop(e);
  381.     textBot = TextBot(e);
  382.     viewBot = w->portRect.bottom - sBarWidthM1;
  383.     if (textBot < viewBot && offTop) {
  384.         dv = viewBot - textBot;
  385.         if (dv > offTop) dv = offTop;
  386.         Scroll(w, dv);
  387.     }
  388.     GetViewRect(w, &viewRect);
  389.     RectRgn((**e).clipRgn, &viewRect);
  390. }
  391.  
  392. /*_____________________________________________________________________
  393.  
  394.     ScrollAction - Scroll Bar Action Procedure
  395. _____________________________________________________________________*/
  396.  
  397. static pascal void ScrollAction (ControlHandle scrollBar, short partCode)
  398.  
  399. {
  400.     WindowPtr        w;                    /* pointer to window */
  401.     short                val;                /* scroll bar value */
  402.     short                min;                /* scroll bar minimum value */
  403.     short                max;                /* scroll bar maximum value */
  404.     short                viewHeight;        /* height of view rectangle */
  405.     short                dv;                /* amount to scroll */
  406.     
  407.     w = FrontWindow();
  408.     val = (**scrollBar).contrlValue;
  409.     min = (**scrollBar).contrlMin;
  410.     max = (**scrollBar).contrlMax;
  411.     viewHeight = w->portRect.bottom - sBarWidthM1 - headerHeight - LineHeight;
  412.     dv = 0;
  413.     switch (partCode) {
  414.         case inUpButton:
  415.             dv = (LineHeight < val-min) ? LineHeight : val-min;
  416.             break;
  417.         case inDownButton:
  418.             dv = (LineHeight < max-val) ? -LineHeight : val-max;
  419.             break;
  420.         case inPageUp:
  421.             dv = (viewHeight < val-min) ? viewHeight : val-min;
  422.             break;
  423.         case inPageDown:
  424.             dv = (viewHeight < max-val) ? -viewHeight : val-max;
  425.             break;
  426.     }
  427.     if (dv) {
  428.         SetCtlValue(scrollBar, val-dv);
  429.         Scroll(w, dv);
  430.     }
  431. }
  432.  
  433. /*_____________________________________________________________________
  434.  
  435.     GetAliasFieldIndex - Get Index in Fields Array of Alias Field
  436.     
  437.     Entry:    fields = handle to fields array.
  438.                 numFields = number of fields.
  439.                     
  440.     Exit:        Function result = index in fields array of alias field.
  441. _____________________________________________________________________*/
  442.  
  443. static short GetAliasFieldIndex (FieldInfo **fields, short numFields)
  444.  
  445. {
  446.     short            i;                        /* loop index */
  447.     FieldInfo    *f;                    /* pointer to field info record */
  448.     char            aliasStr[20];        /* "alias" field name */
  449.  
  450.     GetIndString(aliasStr, fieldNames, aliasFieldName);
  451.     p2cstr(aliasStr);
  452.     for (i = 0; i < numFields; i++) {
  453.         f = &(*fields)[i];
  454.         if (!strcmp(f->name+1, aliasStr)) break;
  455.     }
  456.     return i;
  457. }
  458.  
  459. /*_____________________________________________________________________
  460.  
  461.     GetProxyFieldIndex - Get Index in Fields Array of Proxy Field
  462.     
  463.     Entry:    fields = handle to fields array.
  464.                 numFields = number of fields.
  465.                     
  466.     Exit:        Function result = index in fields array of proxy field.
  467. _____________________________________________________________________*/
  468.  
  469. static short GetProxyFieldIndex (FieldInfo **fields, short numFields)
  470.  
  471. {
  472.     short            i;                        /* loop index */
  473.     FieldInfo    *f;                    /* pointer to field info record */
  474.     char            proxyStr[20];        /* "alias" field name */
  475.  
  476.     GetIndString(proxyStr, fieldNames, proxyFieldName);
  477.     p2cstr(proxyStr);
  478.     for (i = 0; i < numFields; i++) {
  479.         f = &(*fields)[i];
  480.         if (!strcmp(f->name+1, proxyStr)) break;
  481.     }
  482.     return i;
  483. }
  484.  
  485. /*_____________________________________________________________________
  486.  
  487.     GetHero - Check to See if User is a Hero.
  488.     
  489.     Entry:    fields = handle to field info.
  490.                 numFields = number of fields.
  491.                     
  492.     Exit:        Function result = true if user is a hero.
  493. _____________________________________________________________________*/
  494.  
  495. static Boolean GetHero (FieldInfo **fields, short numFields)
  496.  
  497. {
  498.     short            i;                        /* loop index */
  499.     FieldInfo    *f;                    /* pointer to field info record */
  500.     char            heroStr[20];        /* "hero" field name */
  501.     
  502.     GetIndString(heroStr, fieldNames, heroFieldName);
  503.     p2cstr(heroStr);
  504.     for (i = 0; i < numFields; i++) {
  505.         f = &(*fields)[i];
  506.         if (!strcmp(f->name+1, heroStr)) break;
  507.     }
  508.     return f->origSize;
  509. }
  510.  
  511. /*_____________________________________________________________________
  512.  
  513.     CompleteFieldInitialization - Complete Field Initialiation.
  514.     
  515.     Entry:    e = handle to edit info.
  516.                 Following fields set in fields array:
  517.                 name, maxSize, attributes, description, original, origSize.
  518.                     
  519.     Exit:        Remaining fields set in fields array:
  520.                 canEdit, dirty, nLines, edit.
  521.                     
  522.     Special text is also stored in the password field and in all encrypted
  523.     fields.
  524.     
  525.     Fields which cannot be displayed and are empty or encrypted are
  526.     removed from the Fields array.
  527. _____________________________________________________________________*/
  528.  
  529. static void CompleteFieldInitialization (EditInfo **e)
  530.  
  531. {
  532.     short            top;                    /* top coord of field */
  533.     short            i;                        /* loop index */
  534.     short            j;                        /* loop index */
  535.     FieldInfo    *f;                    /* pointer to field info record */
  536.     Rect            vdRect;                /* view = destination rect */
  537.     TEHandle        hText;                /* handle to TextEdit record */
  538.     short            nLines;                /* number of lines in text */
  539.     char            changeStr[20];        /* "Change" attribute string */
  540.     char            encryptStr[20];    /* "Encrypt" attribute string */
  541.     char            pswdStr[20];        /* "password" field name */
  542.     Str255        msg;                    /* special text */
  543.     Boolean        display;                /* true if field should be displayed */
  544.     short            numFields;            /* number of fields */
  545.     
  546.     GetIndString(changeStr, fieldAttrs, changeAttr);
  547.     p2cstr(changeStr);
  548.     GetIndString(encryptStr, fieldAttrs, encryptAttr);
  549.     p2cstr(encryptStr);
  550.     GetIndString(pswdStr, fieldNames, pswdFieldName);
  551.     p2cstr(pswdStr);
  552.     top = headerHeight;
  553.     numFields = (**e).numFields;
  554.     HLock((Handle)(**e).fields);
  555.     for (i = 0; i < numFields; i++) {
  556.         f = &(*(**e).fields)[i];
  557.         f->hasChangeAttr = strstr(*f->attributes+1, changeStr);
  558.         f->canEdit = Hero ? true : f->hasChangeAttr;
  559.         display = f->canEdit || f->origSize;
  560.         if (!strcmp(f->name+1, pswdStr)) {
  561.             f->canEdit = false;
  562.             display = true;
  563.             GetIndString(msg, stringsID, pswdMsg);
  564.             SetHandleSize(f->original, *msg);
  565.             memcpy(*f->original, msg+1, *msg);
  566.             f->origSize = *msg;
  567.         } else if (strstr(*f->attributes+1, encryptStr)) {
  568.             if (display = Hero) {
  569.                 f->canEdit = false;
  570.                 GetIndString(msg, stringsID, encryptMsg);
  571.                 SetHandleSize(f->original, *msg);
  572.                 memcpy(*f->original, msg+1, *msg);
  573.                 f->origSize = *msg;
  574.             }
  575.         }
  576.         if (display) {
  577.             f->dirty = false;
  578.             SetRect(&vdRect, TextLeft, top, TextRight, 0x7fff);
  579.             f->edit = hText = TENew(&vdRect, &vdRect);
  580.             (**hText).txSize = 9;
  581.             (**hText).txFont = FontNum;
  582.             (**hText).lineHeight = LineHeight;
  583.             (**hText).fontAscent = Ascent;
  584.             HLock(f->original);
  585.             TESetText(*f->original, f->origSize, hText);
  586.             HUnlock(f->original);
  587.             TECalText(hText);
  588.             nLines = (**hText).nLines;
  589.             if (!nLines) nLines = 1;
  590.             f->nLines = nLines;
  591.             top += nLines*LineHeight;
  592.             (**hText).destRect.bottom = (**hText).viewRect.bottom = top;
  593.             if (!i) {
  594.                 TESetSelect(0, 0x7fff, hText);
  595.                 TEActivate(hText);
  596.             }
  597.         } else {
  598.             DisposHandle(f->original);
  599.             for (j = i+1; j < numFields; j++) (*(**e).fields)[j-1] = (*(**e).fields)[j];
  600.             i--;
  601.             numFields--;
  602.         }
  603.     }
  604.     HUnlock((Handle)(**e).fields);
  605.     SetHandleSize((Handle)(**e).fields, numFields*sizeof(FieldInfo));
  606.     (**e).numFields = numFields;
  607.     (**e).aliasFieldIndex = GetAliasFieldIndex((**e).fields, (**e).numFields);
  608. }
  609.  
  610. /*_____________________________________________________________________
  611.  
  612.     ToggleShowFieldInfo - Toggle Show Field Info Option.
  613.     
  614.     Entry:    w = pointer to window record.
  615. _____________________________________________________________________*/
  616.  
  617. static void ToggleShowFieldInfo (WindowPtr w)
  618.  
  619. {
  620.     EditInfo            **e;                /* handle to edit info */
  621.     short                i;                    /* index of field at top of window */
  622.     short                j;                    /* loop index */
  623.     FieldInfo        *f;                /* pointer to field info */
  624.     TEHandle            edit;                /* handle to TextEdit record */
  625.     short                top;                /* top coord of cur field */
  626.     short                dvi;                /* change in v coord of field i */
  627.     short                dv;                /* increase or decrease in field height */
  628.     short                offset;            /* amount to offset field */
  629.     Rect                r;                    /* rectangle to invalidate */
  630.     short                numFields;        /* number of fields */
  631.     Boolean            showFieldInfo;    /* true to show full field info */
  632.  
  633.     e = GetEditInfo(w);
  634.     showFieldInfo = (**e).showFieldInfo = !(**e).showFieldInfo;
  635.     SetCtlValue((**e).showFieldInfoBox, showFieldInfo ? 1 : 0);
  636.     numFields = (**e).numFields;
  637.     HLock((Handle)(**e).fields);
  638.     i = (**e).curField;
  639.     f = &(*(**e).fields)[i];
  640.     edit = f->edit;
  641.     top = (**edit).viewRect.top - (showFieldInfo ? infoHeight : 0);
  642.     dvi = headerHeight - top;
  643.     if (dvi) {
  644.         OffsetRect(&(**edit).viewRect, 0, dvi);
  645.         OffsetRect(&(**edit).destRect, 0, dvi);
  646.     }
  647.     dv = showFieldInfo ? -infoHeight : infoHeight;
  648.     offset = dvi + dv;
  649.     for (j = i-1; j >= 0; j--) {
  650.         f = &(*(**e).fields)[j];
  651.         edit = f->edit;
  652.         OffsetRect(&(**edit).viewRect, 0, offset);
  653.         OffsetRect(&(**edit).destRect, 0, offset);
  654.         offset += dv;
  655.     }
  656.     dv = -dv;
  657.     offset = dvi + dv;
  658.     for (j = i+1; j < numFields; j++) {
  659.         f = &(*(**e).fields)[j];
  660.         edit = f->edit;
  661.         OffsetRect(&(**edit).viewRect, 0, offset);
  662.         OffsetRect(&(**edit).destRect, 0, offset);
  663.         offset += dv;
  664.     }
  665.     HUnlock((Handle)(**e).fields);
  666.     r = w->portRect;
  667.     r.top += headerHeight;
  668.     InvalRect(&r);
  669.     ChangeSize(w, r.bottom);
  670.     SetCtlValue((**e).scrollBar, headerHeight - TextTop(e));
  671.     MakeIbeamRgn(w);
  672. }
  673.  
  674. /*_____________________________________________________________________
  675.  
  676.     ChangeCurField - Change Current Active Field
  677.     
  678.     Entry:    e = handle to edit info.
  679.                 i = index of new current field.
  680. _____________________________________________________________________*/
  681.  
  682. static void ChangeCurField (EditInfo **e, short i)
  683.  
  684. {
  685.     FieldInfo        *f;            /* pointer to field info */
  686.     TEHandle            edit;            /* handle to TextEdit record */
  687.     
  688.     SetClip((**e).clipRgn);
  689.     HLock((Handle)(**e).fields);
  690.     f = &(*(**e).fields)[(**e).curField];
  691.     edit = f->edit;
  692.     TESetSelect(0, 0, edit);
  693.     TEDeactivate(edit);
  694.     (**e).curField = i;
  695.     f = &(*(**e).fields)[i];
  696.     edit = f->edit;
  697.     TEActivate(edit);
  698.     SetClip(BigClipRgn);
  699.     HiliteControl((**e).revertButton, f->dirty ? 0 : 255);
  700.     HUnlock((Handle)(**e).fields);
  701. }
  702.  
  703. /*_____________________________________________________________________
  704.  
  705.     SetWindowTitle - Set Window Title.
  706.     
  707.     Entry:    w = pointer to window record.
  708. _____________________________________________________________________*/
  709.  
  710. static void SetWindowTitle (WindowPtr w)
  711.  
  712. {
  713.     EditInfo            **e;            /* handle to edit info */
  714.     Str255            alias;        /* alias */
  715.     short                strIndex;    /* index of template string */
  716.     Str255            tmpl;            /* window title template */
  717.     Str255            ttl;            /* new window title */
  718.     Str255            oldttl;        /* old window title */
  719.     
  720.     if (!w) return;
  721.     e = GetEditInfo(w);
  722.     utl_CopyPString(alias, (**e).alias);
  723.     if (!LoggedIn || w != LoginWindow) {
  724.         strIndex = wTitleRegular;
  725.     } else if (Hero) {
  726.         strIndex = wTitleHero;
  727.     } else {
  728.         strIndex = wTitleLogin;
  729.     }
  730.     GetIndString(tmpl, stringsID, strIndex);
  731.     utl_PlugParams(tmpl, ttl, (**e).dirty ? "\p• " : "\p", alias, nil, nil);
  732.     GetWTitle(w, oldttl);
  733.     if (!EqualString(oldttl, ttl, true, true)) SetWTitle(w, ttl);
  734. }
  735.  
  736. /*_____________________________________________________________________
  737.  
  738.     ChangeDirtyState - Change Dirty Window State.
  739.     
  740.     Entry:    w = pointer to window record.
  741.                 dirty = true if window is dirty.
  742.                 
  743.     Exit:        Dirty flag set in edit info record.
  744.                 Revert All Fields button hilighted.
  745.                 Window title adjusted.
  746. _____________________________________________________________________*/
  747.  
  748. static void ChangeDirtyState (WindowPtr w, Boolean dirty)
  749.  
  750. {
  751.     EditInfo            **e;            /* handle to edit info */
  752.     
  753.     e = GetEditInfo(w);
  754.     if ((**e).dirty == dirty) return;
  755.     (**e).dirty = dirty;
  756.     HiliteControl((**e).revertAllButton, dirty ? 0 : 255);
  757.     SetWindowTitle(w);
  758. }
  759.  
  760. /*_____________________________________________________________________
  761.  
  762.     ProcessFieldChange - Process Changed Field
  763.     
  764.     Entry:    w = pointer to window record.
  765.                 dirty = true if field should be marked dirty.
  766. _____________________________________________________________________*/
  767.  
  768. static void ProcessFieldChange (WindowPtr w, Boolean dirty)
  769.  
  770. {
  771.     EditInfo            **e;            /* handle to edit info */
  772.     FieldInfo        *f;            /* pointer to field info */
  773.     TEHandle            edit;            /* handle to TextEdit record */
  774.     short                nLines;        /* number of lines in field */
  775.     Handle            hText;        /* handle to field text */
  776.     short                dv;            /* change in field height */
  777.     short                i;                /* loop index */
  778.     FieldInfo        *q;            /* pointer to field info */
  779.     TEHandle            qEdit;        /* handle to TextEdit record */
  780.     Rect                r;                /* rectangle to invalidate */
  781.     short                top;            /* first field top coord */
  782.     short                bot;            /* last field bot coord */
  783.     Rect                viewRect;    /* view rectangle */
  784.     short                numFields;    /* number of fields */
  785.     short                curField;    /* current field number */
  786.  
  787.     e = GetEditInfo(w);
  788.     curField = (**e).curField;
  789.     HLock((Handle)(**e).fields);
  790.     f = &(*(**e).fields)[curField];
  791.     edit = f->edit;
  792.     GetViewRect(w, &viewRect);
  793.     if (dirty && !f->dirty) {
  794.         f->dirty = true;
  795.         SetClip((**e).clipRgn);
  796.         r.left = TextLeft - Width;
  797.         r.right = TextLeft;
  798.         r.top = (**edit).viewRect.top;
  799.         r.bottom = r.top + LineHeight;
  800.         EraseRect(&r);
  801.         MoveTo(r.left, r.top + Leading + Ascent);
  802.         DrawChar('•');
  803.         SetClip(BigClipRgn);
  804.         HiliteControl((**e).revertButton, 0);
  805.         ChangeDirtyState(w, true);
  806.     }
  807.     nLines = (**edit).nLines;
  808.     if (!nLines) {
  809.         nLines = 1;
  810.     } else {
  811.         hText = (**edit).hText;
  812.         if (*(*hText + (**edit).teLength - 1) == '\n') nLines++;
  813.     }
  814.     if (nLines != f->nLines) {
  815.         dv = (nLines - f->nLines)*LineHeight;
  816.         (**edit).viewRect.bottom += dv;
  817.         (**edit).destRect.bottom += dv;
  818.         numFields = (**e).numFields;
  819.         for (i = curField + 1; i < numFields; i++) {
  820.             q = &(*(**e).fields)[i];
  821.             qEdit = q->edit;
  822.             OffsetRect(&(**qEdit).viewRect, 0, dv);
  823.             OffsetRect(&(**qEdit).destRect, 0, dv);
  824.         }
  825.         AdjustScrollMax(w);
  826.         MakeIbeamRgn(w);
  827.         bot = TextBot(e);
  828.         if (bot < viewRect.bottom) {
  829.             dv = viewRect.bottom-bot;
  830.             top = TextTop(e);
  831.             if (top + dv > headerHeight) dv = headerHeight - top;
  832.             if (dv) Scroll(w, dv);
  833.         }
  834.         AutoScroll(w, curField);
  835.         r = viewRect;
  836.         r.top = (**edit).viewRect.top;
  837.         InvalRect(&r);
  838.         f->nLines = nLines;
  839.     }
  840.     HUnlock((Handle)(**e).fields);
  841. }
  842.  
  843. /*_____________________________________________________________________
  844.  
  845.     Revert - Revert Current Field to Original Value.
  846.     
  847.     Entry:    w = pointer to window record.
  848. _____________________________________________________________________*/
  849.  
  850. static void Revert (WindowPtr w)
  851.  
  852. {
  853.     EditInfo            **e;            /* handle to edit info */
  854.     FieldInfo        *f;            /* pointer to field info */
  855.     TEHandle            edit;            /* handle to TextEdit record */
  856.     short                i;                /* loop index */
  857.     Rect                r;                /* rectangle to erase */
  858.     short                numFields;    /* number of fields */
  859.     Boolean            newDirty;    /* new window dirty flag */
  860.  
  861.     e = GetEditInfo(w);
  862.     HLock((Handle)(**e).fields);
  863.     f = &(*(**e).fields)[(**e).curField];
  864.     edit = f->edit;
  865.     SetClip((**e).clipRgn);
  866.     HLock(f->original);
  867.     TESetText(*f->original, f->origSize, edit);
  868.     HUnlock(f->original);
  869.     InvalRect(&(**edit).viewRect);
  870.     TECalText(edit);
  871.     SetClip(BigClipRgn);
  872.     ProcessFieldChange(w, false);
  873.     f->dirty = false;
  874.     newDirty = false;
  875.     numFields = (**e).numFields;
  876.     for (i = 0; i < numFields; i++) {
  877.         if ((*(**e).fields)[i].dirty) {
  878.             newDirty = true;
  879.             break;
  880.         }
  881.     }
  882.     SetClip((**e).clipRgn);
  883.     r.left = TextLeft - Width;
  884.     r.right = TextLeft;
  885.     r.top = (**edit).viewRect.top;
  886.     r.bottom = r.top + LineHeight;
  887.     EraseRect(&r);
  888.     if (!f->hasChangeAttr && f->canEdit) {
  889.         MoveTo(r.left, r.top + Leading + Ascent);
  890.         DrawChar('§');
  891.     }
  892.     SetClip(BigClipRgn);
  893.     HiliteControl((**e).revertButton, 255);
  894.     ChangeDirtyState(w, newDirty);
  895.     AutoScroll(w, (**e).curField);
  896.     HUnlock((Handle)(**e).fields);
  897. }
  898.  
  899. /*_____________________________________________________________________
  900.  
  901.     RevertAll - Revert All Fields to Original Values.
  902.     
  903.     Entry:    w = pointer to window record.
  904. _____________________________________________________________________*/
  905.  
  906. static void RevertAll (WindowPtr w)
  907.  
  908. {
  909.     EditInfo            **e;            /* handle to edit info */
  910.     short                i;                        /* loop index */
  911.     short                oldCurField;        /* saved current field */
  912.     short                numFields;    /* number of fields */
  913.  
  914.     e = GetEditInfo(w);
  915.     oldCurField = (**e).curField;
  916.     numFields = (**e).numFields;
  917.     for (i = 0; i < numFields; i++) {
  918.         if ((*(**e).fields)[i].dirty) {
  919.             ChangeCurField(e, i);
  920.             Revert(w);
  921.         }
  922.     }
  923.     ChangeCurField(e, oldCurField);
  924. }
  925.  
  926. /*_____________________________________________________________________
  927.  
  928.     FieldTooBig - Check for Field Too Big.
  929.     
  930.     Entry:    e = handle to edit info.
  931.                 n = number of characters to be inserted into current field.
  932.     
  933.     Exit:        Function result = true if field too big after insertion.
  934. _____________________________________________________________________*/
  935.  
  936. static Boolean FieldTooBig (EditInfo **e, short n)
  937.  
  938. {
  939.     FieldInfo            *f;            /* pointer to field info */
  940.     TEHandle                edit;            /* handle to TextEdit record */
  941.     short                    nSel;            /* selection size */
  942.     short                    teLength;    /* field size */
  943.     char                    lenStr[20];    /* max field size as a string */
  944.     Boolean                tooBig;        /* true if fields is too big */
  945.  
  946.     HLock((Handle)(**e).fields);
  947.     f = &(*(**e).fields)[(**e).curField];
  948.     edit = f->edit;
  949.     nSel = (**edit).selEnd - (**edit).selStart;
  950.     teLength = (**edit).teLength;
  951.     if (tooBig = (teLength - nSel + n > f->maxSize)) {
  952.         NumToString(f->maxSize, lenStr);
  953.         glob_Error(servErrors, msgFieldTooBig, lenStr);
  954.     }
  955.     HUnlock((Handle)(**e).fields);
  956.     return tooBig;
  957. }
  958.  
  959. /*_____________________________________________________________________
  960.  
  961.     DrawGrowBox - Draw Grow Box.
  962.     
  963.     Entry:    w = pointer to window record.
  964. _____________________________________________________________________*/
  965.  
  966. static void DrawGrowBox (WindowPtr w)
  967.  
  968. {
  969.     Rect            r;                /* clip rect */
  970.     
  971.     r = w->portRect;
  972.     r.top += headerHeight-1;
  973.     ClipRect(&r);
  974.     DrawGrowIcon(w);
  975.     SetClip(BigClipRgn);
  976. }
  977.  
  978. /*_____________________________________________________________________
  979.  
  980.     InvalScroll - Invalidate Scroll Bars.
  981.     
  982.     Entry:    w = pointer to window record.
  983. _____________________________________________________________________*/
  984.  
  985.  
  986. static void InvalScroll (WindowPtr w)
  987.  
  988. {
  989.     Rect                r;                    /* rectangle to invalidate */
  990.     
  991.     r = w->portRect;
  992.     r.left = r.right - sBarWidthM1;
  993.     InvalRect(&r);
  994.     r = w->portRect;
  995.     r.top = r.bottom - sBarWidthM1;
  996.     InvalRect(&r);
  997. }
  998.  
  999. /*_____________________________________________________________________
  1000.  
  1001.     DoSave - Send Field Changes to Server.
  1002.     
  1003.     Entry:    w = pointer to window record.
  1004.     
  1005.     Exit:        function result = true if save operation cancelled by user or
  1006.                     all the fields were not updated because of some other error.
  1007. _____________________________________________________________________*/
  1008.  
  1009. static Boolean DoSave (WindowPtr w)
  1010.  
  1011. {
  1012.     EditInfo            **e;                /* handle to edit info */
  1013.     short                i;                    /* loop index */
  1014.     FieldInfo        *f;                /* pointer to field info */
  1015.     TEHandle            edit;                /* handle to TextEdit record */
  1016.     short                teLength;        /* length of text */
  1017.     Rect                viewRect;        /* view rect */
  1018.     OSErr                rCode;            /* result code */
  1019.     short                numFields;        /* number of fields */
  1020.     Str255            alias;            /* alias */
  1021.     Str255            server;            /* login server */
  1022.     Str255            loginAlias;        /* login alias */
  1023.     Str255            pswd;                /* login password */
  1024.     WindowPtr        v;                    /* pointer to traverse window list */
  1025.     EditInfo            **g;                /* handle to edit info for window v */
  1026.     Boolean            aliasChanged;    /* trued if alias was changed */
  1027.     Boolean            someNotPut;        /* true if some fields not put ok */
  1028.     short                sCode;            /* server response code */
  1029.  
  1030.     e = GetEditInfo(w);
  1031.     numFields = (**e).numFields;
  1032.     i = (**e).aliasFieldIndex;
  1033.     f = &(*(**e).fields)[i];
  1034.     edit = f->edit;
  1035.     if (!(**edit).teLength) {
  1036.         glob_Error(servErrors, msgSaveNoAlias, nil);
  1037.         return true;
  1038.     }
  1039.     utl_CopyPString(alias, (**e).alias);
  1040.     utl_CopyPString(server, (**e).server);
  1041.     utl_CopyPString(loginAlias, (**e).loginAlias);
  1042.     utl_CopyPString(pswd, (**e).pswd);
  1043.     for (i = 0; i < numFields; i++) {
  1044.         f = &(*(**e).fields)[i];
  1045.         f->putOK = false;
  1046.         f->servErrMsg = nil;
  1047.     }
  1048.     rCode = serv_PutRecord(server, loginAlias, pswd, alias, (**e).fields, 
  1049.         numFields, &sCode);
  1050.     if (rCode) {
  1051.         glob_ErrorCode(rCode);
  1052.     } else if (sCode != phSuccess) {
  1053.         glob_ServErrorCode(sCode);
  1054.     }
  1055.     SetPort(w);
  1056.     aliasChanged = someNotPut = false;
  1057.     HLock((Handle)(**e).fields);
  1058.     for (i = 0; i < numFields; i++) {
  1059.         f = &(*(**e).fields)[i];
  1060.         if (!f->dirty) continue;
  1061.         if (f->putOK) {
  1062.             f->dirty = false;
  1063.             edit = f->edit;
  1064.             teLength = (**edit).teLength;
  1065.             SetHandleSize(f->original, teLength);
  1066.             memcpy(*f->original, *(**edit).hText, teLength);
  1067.             f->origSize = teLength;
  1068.             if (i == (**e).aliasFieldIndex) {
  1069.                 *alias = teLength;
  1070.                 memcpy(alias+1, *f->original, teLength);
  1071.                 aliasChanged = true;
  1072.             }
  1073.             if (i == (**e).curField) HiliteControl((**e).revertButton, 255);
  1074.         } else {
  1075.             someNotPut = true;
  1076.         }
  1077.     }
  1078.     HUnlock((Handle)(**e).fields);
  1079.     if (aliasChanged) {
  1080.         v = FrontWindow();
  1081.         while (v) {
  1082.             if (oop_GetWindKind(v) == editWind) {
  1083.                 g = GetEditInfo(v);
  1084.                 if (EqualString((**g).server, (**e).server, true, true) && 
  1085.                     EqualString((**g).loginAlias, (**e).alias, true, true)) {
  1086.                     utl_CopyPString((**g).loginAlias, alias);
  1087.                 }
  1088.             }
  1089.             v = (WindowPtr)((WindowPeek)v)->nextWindow;
  1090.         }
  1091.         if (EqualString(server, Server, true, true) &&
  1092.             EqualString((**e).alias, Alias, true, true))
  1093.             utl_CopyPString(Alias, alias);
  1094.         utl_CopyPString((**e).alias, alias);
  1095.     }
  1096.     SetWindowTitle(w);
  1097.     GetViewRect(w, &viewRect);
  1098.     InvalRect(&viewRect);
  1099.     oop_UpdateAll();
  1100.     if (someNotPut) {
  1101.         HLock((Handle)(**e).fields);
  1102.         for (i = 0; i < numFields; i++) {
  1103.             f = &(*(**e).fields)[i];
  1104.             if (f->putOK) continue;
  1105.             if (f->servErrMsg) {
  1106.                 HLock(f->servErrMsg);
  1107.                 glob_BringToFront();
  1108.                 utl_ErrorAlertRez(servErrors, msgBadVal, errorMsgID,
  1109.                     oop_ModalUpdate,
  1110.                     f->name, *(f->servErrMsg), nil, nil);
  1111.                 DisposHandle(f->servErrMsg);
  1112.                 SetPort(w);
  1113.             }
  1114.         }
  1115.         HUnlock((Handle)(**e).fields);
  1116.     } else {
  1117.         ChangeDirtyState(w, false);
  1118.     }
  1119.     return someNotPut;
  1120. }
  1121.  
  1122. /*_____________________________________________________________________
  1123.  
  1124.     AlertIfDirty - Ask User if He Wants to Save Changes.
  1125.     
  1126.     Entry:    w = pointer to window record.
  1127.                 index = index of "quitting" or "closing window" string.
  1128.     
  1129.     Exit:        Function result = true if alert canceled.
  1130. _____________________________________________________________________*/
  1131.  
  1132. static Boolean AlertIfDirty (WindowPtr w, short index)
  1133.  
  1134. {
  1135.     EditInfo            **e;                /* handle to edit info */
  1136.     Str255            alias;            /* alias */
  1137.     Str255            str;                /* "quitting" or "closing window" */
  1138.  
  1139.     e = GetEditInfo(w);
  1140.     if (!(**e).dirty) return false;
  1141.     utl_CopyPString(alias, (**e).alias);
  1142.     GetIndString(str, stringsID, index);
  1143.     glob_BringToFront();
  1144.     oop_UpdateAll();
  1145.     switch (utl_SaveChangesAlertRez(stringsID, msgSaveChanges, saveChangesID,
  1146.         oop_ModalUpdate, alias, str, nil, nil)) {
  1147.         case saveSave:
  1148.             oop_UpdateAll();
  1149.             return DoSave(w);
  1150.         case saveCancel:
  1151.             return true;
  1152.         case saveDont:
  1153.             return false;
  1154.     }
  1155. }
  1156.  
  1157. /*_____________________________________________________________________
  1158.  
  1159.     DisposeFields - Dispose Fields Array.
  1160.     
  1161.     Entry:    fields = handle to fields array.
  1162.                 numFields = number of fields.
  1163.                 intialized = true if field intitialization has been completed.
  1164. _____________________________________________________________________*/
  1165.  
  1166. static void DisposeFields (FieldInfo **fields, short numFields, Boolean initialized)
  1167.  
  1168. {
  1169.     short                i;                /* loop index */
  1170.     FieldInfo        *f;            /* pointer to field info */
  1171.     
  1172.     HLock((Handle)fields);
  1173.     for (i = 0; i < numFields; i++) {
  1174.         f = &(*fields)[i];
  1175.         DisposHandle(f->attributes);
  1176.         DisposHandle(f->description);
  1177.         DisposHandle(f->original);
  1178.         if (initialized) TEDispose(f->edit);
  1179.     }
  1180.     DisposHandle((Handle)fields);
  1181. }
  1182.  
  1183. /*_____________________________________________________________________
  1184.  
  1185.     CloseEditWindow - Close Window.
  1186.     
  1187.     Entry:    w = pointer to window record.
  1188. _____________________________________________________________________*/
  1189.  
  1190. static void CloseEditWindow (WindowPtr w)
  1191.  
  1192. {
  1193.     EditInfo            **e;            /* handle to edit info */
  1194.     short                windNum;        /* window number */
  1195.     
  1196.     if (w == LoginWindow) LoginWindow = nil;
  1197.     e = GetEditInfo(w);
  1198.     windNum = (**e).windNum;
  1199.     if (windNum <= numPosSave) wstm_Save(w, &EditStates[windNum]);
  1200.     DisposeFields((**e).fields, (**e).numFields, true);
  1201.     DisposeRgn((**e).clipRgn);
  1202.     DisposHandle((Handle)e);
  1203.     oop_DoClose(w);
  1204. }
  1205.  
  1206. /*_____________________________________________________________________
  1207.  
  1208.     NewEditWindow - Create New Edit Window.
  1209.     
  1210.     Entry:    fields = handle to field info.
  1211.                 numFields = number of fields.
  1212.                 alias = alias.
  1213. _____________________________________________________________________*/
  1214.  
  1215. static void NewEditWindow (FieldInfo **fields, short numFields, Str255 alias)
  1216.     
  1217. {
  1218.     WindowPtr            v;                        /* traverses window list */
  1219.     EditInfo                **g;                    /* handle to edit info for window v */
  1220.     Boolean                haveWindNum;        /* true when window number found */
  1221.     short                    windNum;                /* window number */
  1222.     WindState            windState;            /* window state record */
  1223.     EditInfo                **e;                    /* handle to edit info */
  1224.     Rect                    viewRect;            /* view rectangle */
  1225.     WindowPtr            w;                        /* pointer to window */
  1226.     
  1227.     /* Create the new window record */
  1228.  
  1229.     windNum = 1;
  1230.     haveWindNum = false;
  1231.     while (true) {
  1232.         v = FrontWindow();
  1233.         if (!v) break;
  1234.         while (v) {
  1235.             if (oop_GetWindKind(v) == editWind) {
  1236.                 g = GetEditInfo(v);
  1237.                 if ((**g).windNum == windNum) break;
  1238.             }
  1239.             v = (WindowPtr)((WindowPeek)v)->nextWindow;
  1240.             if (!v) haveWindNum = true;
  1241.         }
  1242.         if (haveWindNum) break;
  1243.         windNum++;
  1244.     }
  1245.     windState.moved = false;
  1246.     w = wstm_Restore(false, editWindID, nil, 
  1247.         windNum <= numPosSave ? &EditStates[windNum] : &windState);
  1248.     SetPort(w);
  1249.     TextFont(FontNum);
  1250.     TextSize(fontSize);
  1251.     
  1252.     /* Create the new EditInfo record. */
  1253.     
  1254.     e = (EditInfo**)NewHandle(sizeof(EditInfo));
  1255.     (**e).fields = fields;
  1256.     (**e).numFields = numFields;
  1257.     (**e).curField = 0;
  1258.     (**e).aliasFieldIndex = GetAliasFieldIndex((**e).fields, (**e).numFields);
  1259.     (**e).scrollBar = GetNewControl(sBarID, w);
  1260.     (**e).showFieldInfoBox = GetNewControl(showInfoID, w);
  1261.     (**e).revertButton = GetNewControl(revertID, w);
  1262.     HiliteControl((**e).revertButton, 255);
  1263.     (**e).revertAllButton = GetNewControl(revertAllID, w);
  1264.     HiliteControl((**e).revertAllButton, 255);
  1265.     (**e).showFieldInfo = false;
  1266.     (**e).dirty = false;
  1267.     utl_CopyPString((**e).alias, alias);
  1268.     utl_CopyPString((**e).server, Server);
  1269.     utl_CopyPString((**e).loginAlias, Alias);
  1270.     utl_CopyPString((**e).pswd, Password);
  1271.     (**e).windNum = windNum;
  1272.     
  1273.     /* Create the new window object. */
  1274.     
  1275.     oop_NewWindow(w, editWind, (Handle)e, &dispatch);
  1276.     
  1277.     /* Finish initializing and show the window. */
  1278.     
  1279.     CompleteFieldInitialization(e);
  1280.     MakeIbeamRgn(w);
  1281.     GetViewRect(w, &viewRect);
  1282.     (**e).clipRgn = NewRgn();
  1283.     RectRgn((**e).clipRgn, &viewRect);
  1284.     ChangeSize(w, w->portRect.bottom);
  1285.     AdjustScrollMax(w);
  1286.     InvalRect(&w->portRect);
  1287.     ShowWindow(w);    
  1288.     
  1289.     return;
  1290. }
  1291.  
  1292. /*_____________________________________________________________________
  1293.  
  1294.     AlreadyOpen - Check to See if Record is Already Open.
  1295.     
  1296.     Entry:    server = server.
  1297.                 alias = alias.
  1298.                 
  1299.     Exit:        function result = pointer to window record, or nil if none.
  1300. _____________________________________________________________________*/
  1301.  
  1302. static WindowPtr AlreadyOpen (Str255 server, Str255 alias)
  1303.     
  1304. {
  1305.     WindowPtr        v;                        /* pointer to traverse window list */
  1306.     EditInfo            **g;                    /* handle to edit info */
  1307.     
  1308.     v = FrontWindow();
  1309.     while (v) {
  1310.         if (oop_GetWindKind(v) == editWind) {
  1311.             g = GetEditInfo(v);
  1312.             if (EqualString((**g).server, server, true, true) &&
  1313.                 EqualString((**g).alias, alias, true, true)) {
  1314.                 return v;
  1315.             }
  1316.         }
  1317.         v = (WindowPtr)((WindowPeek)v)->nextWindow;
  1318.     }
  1319.     return nil;
  1320. }
  1321.  
  1322. /*_____________________________________________________________________
  1323.  
  1324.     GetRecord - Get a Ph Record and Open an Editing Window.
  1325.     
  1326.     Entry:    user = alias or username.
  1327.     
  1328.     Exit:        function result = true if record opened ok.
  1329. _____________________________________________________________________*/
  1330.  
  1331. static Boolean GetRecord (Str255 user)
  1332.  
  1333. {
  1334.     OSErr                    rCode;                /* result code */
  1335.     Str255                alias;                /* alias for new record */
  1336.     FieldInfo            **fields;            /* handle to field info */
  1337.     short                    numFields;            /* number of fields */
  1338.     short                    sCode;                /* server response code */
  1339.     short                    i;                        /* index of field */
  1340.     FieldInfo            *f;                    /* pointer to field info */
  1341.     Boolean                canPut;                /* true if login user permitted to edit
  1342.                                                         this record */
  1343.     short                    proxyLen;            /* length of proxy field */
  1344.     short                    aliasLen;            /* length of login alias */
  1345.     short                    j;                        /* loop index */
  1346.     WindowPtr            w;                        /* ptr to window if already open */
  1347.  
  1348.     fields = nil;
  1349.     if (rCode = serv_GetRecord(Server, Alias, Password, user,
  1350.         &fields, &numFields, &sCode)) {
  1351.         glob_ErrorCode(rCode);
  1352.         if (fields) DisposeFields(fields, numFields, false);
  1353.         return false;
  1354.     }
  1355.     if (sCode != phSuccess) {
  1356.         glob_ServErrorCode(sCode);
  1357.         if (fields) DisposeFields(fields, numFields, false);
  1358.         return false;
  1359.     }
  1360.     i = GetAliasFieldIndex(fields, numFields);
  1361.     f = &(*fields)[i];
  1362.     if (!f->origSize) {
  1363.         glob_Error (servErrors, msgOpenNoAlias, nil);
  1364.         DisposeFields(fields, numFields, false);
  1365.         return false;
  1366.     }
  1367.     *alias = f->origSize;
  1368.     memcpy(alias+1, *f->original, f->origSize);
  1369.     if (w = AlreadyOpen(Server, alias)) {
  1370.         if (fields) DisposeFields(fields, numFields, false);
  1371.         SelectWindow(w);
  1372.         return true;
  1373.     }
  1374.     if (!Hero && !EqualString(alias, Alias, true, true)) {
  1375.         i = GetProxyFieldIndex(fields, numFields);
  1376.         f = &(*fields)[i];
  1377.         canPut = false;
  1378.         proxyLen = f->origSize;
  1379.         aliasLen = *Alias;
  1380.         for (j = 0; j <= proxyLen-aliasLen; j++) {
  1381.             if (!strncmp(Alias+1, *f->original+j, aliasLen)) {
  1382.                 canPut = true;
  1383.                 break;
  1384.             }
  1385.         }
  1386.         if (!canPut) {
  1387.             glob_Error(servErrors, msgNotAuth, user);
  1388.             if (fields) DisposeFields(fields, numFields, false);
  1389.             return false;
  1390.         }
  1391.     }
  1392.     NewEditWindow(fields, numFields, alias);
  1393.     SetWindowTitle(FrontWindow());
  1394.     return true;
  1395. }
  1396.  
  1397. /*_____________________________________________________________________
  1398.  
  1399.     DoOpen - Open a Ph Record
  1400. _____________________________________________________________________*/
  1401.  
  1402. static void DoOpen (void)
  1403.  
  1404. {
  1405.     Str255            user;            /* username to open */
  1406.     
  1407.     HiliteMenu(0);
  1408.     *user = 0;
  1409.     while (true) {
  1410.         if (open_DoDialog(user)) return;
  1411.         if (!*user) {
  1412.             glob_Error(servErrors, msgNoAliasIdName, nil);
  1413.             continue;
  1414.         }
  1415.         if (GetRecord(user)) break;
  1416.     }
  1417. }
  1418.  
  1419. /*_____________________________________________________________________
  1420.  
  1421.     BuildProxyMenu - Build Proxy Menu.
  1422.     
  1423.     Entry:        proxyList = handle to proxy list (a sequence of Pascal
  1424.                         strings).
  1425.                     proxyCode = server response code to proxy query.
  1426. _____________________________________________________________________*/
  1427.  
  1428. static void BuildProxyMenu (Handle proxyList, short proxyCode)
  1429.  
  1430. {
  1431.     short            nItems;        /* number of items in menu */
  1432.     short            i;                /* loop index */
  1433.     char            *p;            /* pointer into proxy list */
  1434.     char            *pEnd;        /* pointer to end of proxy list */
  1435.     short            item;            /* menu item number */
  1436.     Str255        ttl;            /* menu command */
  1437.  
  1438.     Proxy = proxyList && proxyCode == phSuccess;
  1439.     nItems = CountMItems(ProxyMenu);
  1440.     for (i = nItems; i > 0; i--) DelMenuItem(ProxyMenu, i);
  1441.     if (Proxy) {
  1442.         HLock(proxyList);
  1443.         p = *proxyList;
  1444.         pEnd = p + GetHandleSize(proxyList);
  1445.         item = 0;
  1446.         while (p < pEnd) {
  1447.             if (*p) {
  1448.                 item++;
  1449.                 AppendMenu(ProxyMenu, "\p ");
  1450.                 SetItem(ProxyMenu, item, p);
  1451.             }
  1452.             p += *p+1;
  1453.         }
  1454.     } else {
  1455.         GetIndString(ttl, stringsID, whyCmd);
  1456.         AppendMenu(ProxyMenu, ttl);
  1457.     }
  1458.     DisposHandle(proxyList);
  1459. }
  1460.  
  1461. /*_____________________________________________________________________
  1462.  
  1463.     DoNew - Create a New Ph Record.
  1464. _____________________________________________________________________*/
  1465.  
  1466. static void DoNew (void)
  1467.  
  1468. {
  1469.     OSErr                    rCode;                /* result code */
  1470.     Str255                alias;                /* alias to create */
  1471.     Str255                name;                    /* name field */
  1472.     Str255                type;                    /* type field */
  1473.     Str255                pswd1;                    /* pswd for new record */
  1474.     Str255                pswd2;                /* second pswd for new record */
  1475.     FieldInfo            **fields;            /* handle to field info */
  1476.     short                    numFields;            /* number of fields */
  1477.     short                    sCode;                /* server response code */
  1478.     short                    whichField;            /* field to hilite in dialog =
  1479.                                                         field containing illegal value */
  1480.     Str255                servErrMsg;            /* server error message */
  1481.     Str255                fName;                /* illegal field name */
  1482.     short                    inx;                    /* index in field names rsrc of field name */
  1483.     
  1484.     HiliteMenu(0);
  1485.     *alias = *name = *type = *pswd1 = *pswd2 = whichField = 0;
  1486.     while (true) {
  1487.         if (new_DoDialog(alias, name, type, pswd1, pswd2, whichField)) return;
  1488.         if (!*alias) {
  1489.             glob_Error(servErrors, msgNoAlias, nil);
  1490.             continue;
  1491.         }
  1492.         if (!EqualString(pswd1, pswd2, true, true)) {
  1493.             glob_Error(servErrors, msgPswdNotEqual, nil);
  1494.             continue;
  1495.         }
  1496.         fields = nil;
  1497.         if (rCode = serv_CreateRecord(Server, Alias, Password, alias, 
  1498.             name, type, pswd1, &fields, &numFields, &sCode, &whichField, 
  1499.             servErrMsg)) {
  1500.             glob_ErrorCode(rCode);
  1501.             if (fields) DisposeFields(fields, numFields, false);
  1502.             continue;
  1503.         }
  1504.         if (sCode != phSuccess) {
  1505.             if (whichField >= 0) {
  1506.                 switch (whichField) {
  1507.                     case 0: inx = aliasFieldName; break;
  1508.                     case 1: inx = nameFieldName; break;
  1509.                     case 2: inx = typeFieldName; break;
  1510.                     case 3: inx = pswdFieldName; break;
  1511.                 }
  1512.                 GetIndString(fName, fieldNames, inx);
  1513.                 glob_BringToFront();
  1514.                 utl_ErrorAlertRez(servErrors, msgBadVal, errorMsgID,
  1515.                     oop_ModalUpdate,
  1516.                     fName, servErrMsg, nil, nil);
  1517.             } else {
  1518.                 glob_ServErrorCode(sCode);
  1519.             }
  1520.             if (fields) DisposeFields(fields, numFields, false);
  1521.             continue;
  1522.         }
  1523.         break;
  1524.     }
  1525.     NewEditWindow(fields, numFields, alias);
  1526.     SetWindowTitle(FrontWindow());
  1527. }
  1528.  
  1529. /*_____________________________________________________________________
  1530.  
  1531.     DoLogin - Login to Server.
  1532. _____________________________________________________________________*/
  1533.  
  1534. static void DoLogin (void)
  1535.  
  1536. {
  1537.     OSErr                    rCode;                /* result code */
  1538.     Str255                server;                /* server */
  1539.     Str255                user;                    /* alias or username */
  1540.     Str255                pswd;                    /* password */
  1541.     Str255                loginAlias;            /* login alias */
  1542.     FieldInfo            **fields;            /* handle to field info */
  1543.     short                    numFields;            /* number of fields */
  1544.     Handle                proxyList;            /* handle to proxy list */
  1545.     short                    proxyCode;            /* server response code to proxy query */
  1546.     short                    sCode;                /* server response code */
  1547.     WindowPtr            w;                        /* ptr to login window */
  1548.  
  1549.     HiliteMenu(0);
  1550.     utl_CopyPString(server, DefaultServer);
  1551.     *user = *pswd = 0;
  1552.     while (true) {
  1553.         if (login_DoDialog(server, user, pswd)) return;
  1554.         if (!*server) {
  1555.             glob_Error(servErrors, msgNoServer, nil);
  1556.             continue;
  1557.         }
  1558.         if (!*user) {
  1559.             glob_Error(servErrors, msgNoAliasName, nil);
  1560.             continue;
  1561.         }
  1562.         if (!*pswd) {
  1563.             glob_Error(servErrors, msgNoPswd, nil);
  1564.             continue;
  1565.         }
  1566.         proxyList = nil;
  1567.         fields = nil;
  1568.         if (rCode = serv_Login(server, user, pswd, loginAlias,
  1569.             &fields, &numFields, &sCode, &proxyList, &proxyCode)) {
  1570.             glob_ErrorCode(rCode);
  1571.             if (proxyList) DisposHandle(proxyList);
  1572.             if (fields) DisposeFields(fields, numFields, false);
  1573.             continue;
  1574.         }
  1575.         if (sCode != phSuccess) {
  1576.             glob_ServErrorCode(sCode);
  1577.             if (proxyList) DisposHandle(proxyList);
  1578.             if (fields) DisposeFields(fields, numFields, false);
  1579.             continue;
  1580.         }
  1581.         break;
  1582.     }
  1583.     utl_CopyPString(Server, server);
  1584.     utl_CopyPString(Alias, loginAlias);
  1585.     utl_CopyPString(Password, pswd);
  1586.     Hero = GetHero(fields, numFields);
  1587.     if (LoggedIn) {
  1588.         LoggedIn = false;
  1589.         SetWindowTitle(LoginWindow);
  1590.     }
  1591.     LoggedIn = true;
  1592.     if (w = AlreadyOpen(server, loginAlias)) {
  1593.         if (fields) DisposeFields(fields, numFields, false);
  1594.         SelectWindow(w);
  1595.     } else {
  1596.         NewEditWindow(fields, numFields, loginAlias);
  1597.         w = FrontWindow();
  1598.     }
  1599.     LoginWindow = w;
  1600.     SetWindowTitle(w);
  1601.     BuildProxyMenu(proxyList, proxyCode);
  1602. }
  1603.  
  1604. /*_____________________________________________________________________
  1605.  
  1606.     DoLogout - Logout.
  1607. _____________________________________________________________________*/
  1608.  
  1609. static void DoLogout (void)
  1610.  
  1611. {
  1612.     WindowPtr            v;            /* pointer to traverse window list. */
  1613.     
  1614.     v = FrontWindow();
  1615.     while (v) {
  1616.         if (oop_GetWindKind(v) == editWind) {
  1617.             if (AlertIfDirty(v, msgClosing)) return;
  1618.             CloseEditWindow(v);
  1619.         }
  1620.         v = (WindowPtr)((WindowPeek)v)->nextWindow;
  1621.     }
  1622.     LoggedIn = false;
  1623.     LoginWindow = nil;
  1624.     Hero = false;
  1625.     memset(Server, 0, 256);
  1626.     memset(Alias, 0, 256);
  1627.     memset(Password, 0, 256);
  1628. }
  1629.  
  1630. /*_____________________________________________________________________
  1631.  
  1632.     DoChangePassword - Change Server Password.
  1633.     
  1634.     Entry:    w = pointer to window record.
  1635. _____________________________________________________________________*/
  1636.  
  1637. static void DoChangePassword (WindowPtr w)
  1638.  
  1639. {
  1640.     EditInfo            **e;                    /* handle to edit info */
  1641.     OSErr                rCode;                /* result code */
  1642.     Str255            alias;                /* alias of record to change */
  1643.     Str255            pswd1;                /* first password */
  1644.     Str255            pswd2;                /* second password */
  1645.     Str255            server;                /* login server */
  1646.     Str255            loginAlias;            /* login alias */
  1647.     Str255            loginPswd;            /* login password */
  1648.     WindowPtr        v;                        /* pointer to traverse window list */
  1649.     EditInfo            **g;                    /* handle to edit info for window v */
  1650.     short                sCode;                /* server response code */
  1651.     Str255            servErrMsg;            /* server error message */
  1652.     Boolean            emptyOK;                /* true if empty password is OK */
  1653.  
  1654.     HiliteMenu(0);
  1655.     e = GetEditInfo(w);
  1656.     utl_CopyPString(alias, (**e).alias);
  1657.     utl_CopyPString(server, (**e).server);
  1658.     utl_CopyPString(loginAlias, (**e).loginAlias);
  1659.     utl_CopyPString(loginPswd, (**e).pswd);
  1660.     emptyOK = false;
  1661.     if (Hero) {
  1662.         emptyOK = true;
  1663.         v = FrontWindow();
  1664.         while (v) {
  1665.             if (oop_GetWindKind(v) == editWind) {
  1666.                 g = GetEditInfo(v);
  1667.                 if (EqualString((**g).server, server, true, true) &&
  1668.                     EqualString((**g).loginAlias, alias, true, true)) {
  1669.                     emptyOK = false;
  1670.                     break;
  1671.                 }
  1672.             }
  1673.             v = (WindowPtr)((WindowPeek)v)->nextWindow;
  1674.         }
  1675.         if (emptyOK && EqualString(server, Server, true, true) &&
  1676.             EqualString(alias, Alias, true, true)) emptyOK = false;
  1677.     }
  1678.     *pswd1 = *pswd2 = 0;
  1679.     while (true) {
  1680.         if (pswd_DoDialog(pswd1, pswd2)) return;
  1681.         if (!emptyOK && !*pswd1 && !*pswd2) {
  1682.             glob_Error(servErrors, msgNoPswd, nil);
  1683.             continue;
  1684.         }
  1685.         if (!EqualString(pswd1, pswd2, true, true)) {
  1686.             glob_Error(servErrors, msgPswdNotEqual, nil);
  1687.             continue;
  1688.         }
  1689.         break;
  1690.     }
  1691.     rCode = serv_ChangePassword(server, loginAlias, loginPswd, alias, pswd1,
  1692.         &sCode, servErrMsg);
  1693.     SetPort(w);
  1694.     if (rCode) {
  1695.         glob_ErrorCode(rCode);
  1696.         return;
  1697.     }
  1698.     if (sCode != phSuccess) {
  1699.         if (*servErrMsg) {
  1700.             glob_Error(servErrors, msgBadPswd, servErrMsg);
  1701.         } else {
  1702.             glob_ServErrorCode(sCode);
  1703.         }
  1704.         return;
  1705.     }
  1706.     v = FrontWindow();
  1707.     while (v) {
  1708.         if (oop_GetWindKind(v) == editWind) {
  1709.             g = GetEditInfo(v);
  1710.             if (EqualString((**g).server, server, true, true) && 
  1711.                 EqualString((**g).loginAlias, alias, true, true)) {
  1712.                 utl_CopyPString((**g).pswd, pswd1);
  1713.             }
  1714.         }
  1715.         v = (WindowPtr)((WindowPeek)v)->nextWindow;
  1716.     }
  1717.     if (EqualString(server, Server, true, true) &&
  1718.         EqualString(alias, Alias, true, true))
  1719.         utl_CopyPString(Password, pswd1);
  1720. }
  1721.  
  1722. /*_____________________________________________________________________
  1723.  
  1724.     DoDelete - Delete a Ph Record.
  1725.     
  1726.     Entry:    w = pointer to window record.
  1727. _____________________________________________________________________*/
  1728.  
  1729. static void DoDelete (WindowPtr w)
  1730.  
  1731. {
  1732.     EditInfo            **e;                    /* handle to edit info */
  1733.     Str255            alias;                /* alias to delete */
  1734.     OSErr                rCode;                /* result code */
  1735.     short                sCode;                /* server response code */
  1736.     Boolean            canDelete;            /* true if record can be deleted */
  1737.     WindowPtr        v;                        /* traverses window list */
  1738.     EditInfo            **g;                    /* handle to edit info for window v */
  1739.  
  1740.     e = GetEditInfo(w);
  1741.     utl_CopyPString(alias, (**e).alias);
  1742.     canDelete = !EqualString(Alias, alias, true, true) ||
  1743.         !EqualString(Server, (**e).server, true, true);
  1744.     if (canDelete) {
  1745.         v = (WindowPtr)((WindowPeek)w)->nextWindow;
  1746.         while (v) {
  1747.             if (oop_GetWindKind(v) == editWind) {
  1748.                 g = GetEditInfo(v);
  1749.                 if (EqualString((**g).server, (**e).server, true, true) &&
  1750.                     EqualString((**g).loginAlias, alias, true, true)) {
  1751.                     canDelete = false;
  1752.                     break;
  1753.                 }
  1754.             }
  1755.             v = (WindowPtr)((WindowPeek)v)->nextWindow;
  1756.         }
  1757.     }
  1758.     if (!canDelete) {
  1759.         glob_Error(stringsID, msgCantDelete, alias);
  1760.         return;
  1761.     }
  1762.     glob_BringToFront();
  1763.     if (deleteCancel == utl_TellMeTwiceAlertRez(stringsID, msgDelete, deleteID,
  1764.         oop_ModalUpdate, alias, nil, nil, nil)) return;
  1765.     if (rCode = serv_DeleteRecord(Server, Alias, Password, alias, &sCode)) {
  1766.         glob_ErrorCode(rCode);
  1767.         return;
  1768.     }
  1769.     if (sCode != phSuccess) {
  1770.         glob_ServErrorCode(sCode);
  1771.         return;
  1772.     }
  1773.     CloseEditWindow(w);
  1774. }
  1775.  
  1776. /*_____________________________________________________________________
  1777.  
  1778.     edit_DoPeriodic - Do Periodic Tasks.
  1779.     
  1780.     Entry:    w = pointer to window record.
  1781. _____________________________________________________________________*/
  1782.  
  1783. void edit_DoPeriodic (WindowPtr w)
  1784.  
  1785. {
  1786.     EditInfo                **e;                    /* handle to edit info */
  1787.     Point                    where;                /* current mouse loc in local coords */
  1788.     Rect                    viewRect;            /* view rectangle */
  1789.     RgnHandle            ibeamRgn;            /* ibeam region */
  1790.     ControlHandle        scrollBar;            /* handle to scroll bar control */
  1791.     ControlHandle        showFieldInfoBox;    /* handle to show field info checkbox */
  1792.     ControlHandle        revertButton;        /* handle to revert field button */
  1793.     ControlHandle        revertAllButton;    /* handle to revert all fields button */
  1794.     short                    newBalloon;            /* index in STR# of balloon help msg, or 0 if
  1795.                                                         none */
  1796.     Rect                    hotRect;                /* balloon help hot rectangle */
  1797.     Point                    tip;                    /* balloon help tip location */
  1798.     HMMessageRecord    helpMsg;                /* help message record */
  1799.     
  1800.     static short        oldBalloon = 0;    /* index in STR# of previous balloon help msg,
  1801.                                                         or 0 if none */
  1802.  
  1803.     e = GetEditInfo(w);
  1804.     SetPort(w);
  1805.     GetViewRect(w, &viewRect);
  1806.     SetClip((**e).clipRgn);
  1807.     TEIdle((*(**e).fields)[(**e).curField].edit);
  1808.     SetClip(BigClipRgn);
  1809.     GetMouse(&where);
  1810.     ibeamRgn = oop_GetWindIbeamRgn(w);
  1811.     SetCursor(PtInRect(where, &viewRect) && PtInRgn(where, ibeamRgn) ? 
  1812.         *IBeamHandle : &qd.arrow);
  1813.     if (HaveBalloons && HMGetBalloons()) {
  1814.         scrollBar = (**e).scrollBar;
  1815.         showFieldInfoBox = (**e).showFieldInfoBox;
  1816.         revertButton = (**e).revertButton;
  1817.         revertAllButton = (**e).revertAllButton;
  1818.         if (PtInRect(where, &viewRect)) {
  1819.             newBalloon = hbEditFields;
  1820.             hotRect = viewRect;
  1821.         } else if (PtInRect(where, &(**scrollBar).contrlRect)) {
  1822.             newBalloon = (**scrollBar).contrlMin < (**scrollBar).contrlMax ?
  1823.                 hbScrollEnabled : hbScrollDisabled;
  1824.                 hotRect = (**scrollBar).contrlRect;
  1825.         } else if (PtInRect(where, &(**showFieldInfoBox).contrlRect)) {
  1826.             newBalloon = (**showFieldInfoBox).contrlValue ? 
  1827.                 hbEditInfoChk : hbEditInfoUnChk;
  1828.                 hotRect = (**showFieldInfoBox).contrlRect;
  1829.         } else if (PtInRect(where, &(**revertButton).contrlRect)) {
  1830.             newBalloon = (**revertButton).contrlHilite ? 
  1831.                 hbEditRvtDisabled : hbEditRvtEnabled;
  1832.                 hotRect = (**revertButton).contrlRect;
  1833.         } else if (PtInRect(where, &(**revertAllButton).contrlRect)) {
  1834.             newBalloon = (**revertAllButton).contrlHilite ? 
  1835.                 hbEditRvtAllDisabled : hbEditRvtAllEnabled;
  1836.                 hotRect = (**revertAllButton).contrlRect;
  1837.         } else {
  1838.             hotRect = w->portRect;
  1839.             hotRect.top = hotRect.bottom - sBarWidthM1;
  1840.             hotRect.left = hotRect.right - sBarWidthM1;
  1841.             if (PtInRect(where, &hotRect)) {
  1842.                 newBalloon = hbGrow;
  1843.             } else {
  1844.                 newBalloon = 0;
  1845.             }
  1846.         }
  1847.         if (!HMIsBalloon()) oldBalloon = 0;
  1848.         if (newBalloon != oldBalloon) {
  1849.             if (newBalloon) {
  1850.                 LocalToGlobal((Point*)&hotRect);
  1851.                 LocalToGlobal((Point*)&hotRect.bottom);
  1852.                 tip.h = (hotRect.left + hotRect.right) >> 1;
  1853.                 tip.v = (hotRect.top + hotRect.bottom) >> 1;
  1854.                 helpMsg.hmmHelpType = khmmStringRes;
  1855.                 helpMsg.u.hmmStringRes.hmmResID = hbStringsId;
  1856.                 helpMsg.u.hmmStringRes.hmmIndex = newBalloon;
  1857.                 if (!HMShowBalloon(&helpMsg, tip, &hotRect, 
  1858.                     nil, 0, 0, kHMRegularWindow)) oldBalloon = newBalloon;
  1859.             } else {
  1860.                 oldBalloon = 0;
  1861.             }
  1862.         }
  1863.     }
  1864. }
  1865.  
  1866. /*_____________________________________________________________________
  1867.  
  1868.     edit_DoClick - Process a Mouse Down Event.
  1869.     
  1870.     Entry:    w = pointer to window record.
  1871.                 where = mouse click location in local coordinates.
  1872.                 modifiers = modifiers from event record.
  1873. _____________________________________________________________________*/
  1874.  
  1875. void edit_DoClick (WindowPtr w, Point where, short modifiers)
  1876.  
  1877. {
  1878.     EditInfo            **e;                /* handle to edit info */
  1879.     ControlHandle    whichControl;    /* control handle returned from FindControl */
  1880.     short                oldVal;            /* old value of scroll bar */
  1881.     short                dv;                /* change in scroll bar value */
  1882.     short                partCode;        /* FindControl part code */
  1883.     short                i;                    /* loop index */
  1884.     FieldInfo        *f;                /* pointer to field info */
  1885.     TEHandle            edit;                /* handle to TextEdit record */
  1886.     Rect                viewRect;        /* view rectangle */
  1887.     Rect                fieldRect;        /* field rectangle */
  1888.     short                numFields;        /* number of fields */
  1889.  
  1890.     e = GetEditInfo(w);
  1891.     partCode = FindControl(where, w, &whichControl);
  1892.     if (!whichControl) {
  1893.         GetViewRect(w, &viewRect);
  1894.         if (!PtInRect(where, &viewRect)) return;
  1895.         numFields = (**e).numFields;
  1896.         HLock((Handle)(**e).fields);
  1897.         for (i = 0; i < numFields; i++) {
  1898.             f = &(*(**e).fields)[i];
  1899.             if (!f->canEdit) continue;
  1900.             edit = f->edit;
  1901.             fieldRect = (**edit).viewRect;
  1902.             fieldRect.left -= textMargin;
  1903.             fieldRect.right += textMargin;
  1904.             if (!PtInRect(where, &fieldRect)) continue;
  1905.             if (i != (**e).curField) {
  1906.                 ChangeCurField(e, i);
  1907.             }
  1908.             SetClip((**e).clipRgn);
  1909.             TEClick(where, modifiers & shiftKey ? true : false, edit);
  1910.             SetClip(BigClipRgn);
  1911.             return;
  1912.         }
  1913.         HUnlock((Handle)(**e).fields);
  1914.     } else if (whichControl == (**e).scrollBar) {
  1915.         if (partCode == inThumb) {
  1916.             oldVal = GetCtlValue(whichControl);
  1917.             TrackControl(whichControl, where, nil);
  1918.             dv = GetCtlValue(whichControl) - oldVal;
  1919.             if (dv) Scroll(w, -dv);
  1920.         } else {
  1921.             TrackControl(whichControl, where, (ProcPtr)ScrollAction);
  1922.         }
  1923.         AdjustScrollMax(w);
  1924.     } else {
  1925.         if (!TrackControl(whichControl, where, nil)) return;
  1926.         if (whichControl == (**e).showFieldInfoBox) {
  1927.             ToggleShowFieldInfo(w);
  1928.         } else if (whichControl == (**e).revertButton) {
  1929.             Revert(w);
  1930.         } else if (whichControl == (**e).revertAllButton) {
  1931.             RevertAll(w);
  1932.         }
  1933.     }
  1934. }
  1935.  
  1936. /*_____________________________________________________________________
  1937.  
  1938.     edit_DoKey - Process a Key Down Event.
  1939.     
  1940.     Entry:    w = pointer to window record.
  1941.                 key = ascii code of key.
  1942.                 modifiers = modifiers from event record.
  1943. _____________________________________________________________________*/
  1944.  
  1945. void edit_DoKey (WindowPtr w, char key, short modifiers)
  1946.  
  1947. {
  1948.     EditInfo            **e;                /* handle to edit info */
  1949.     TEHandle            edit;                /* handle to TextEdit record */
  1950.     short                i;                    /* loop index */
  1951.     Boolean            legal;            /* true if legal char for this field */
  1952.     short                numFields;        /* number of fields */
  1953.     ControlHandle    scrollBar;        /* handle to scroll bar */
  1954.     short                val;                /* scroll bar value */
  1955.     short                min;                /* scroll bar minimum value */
  1956.     short                max;                /* scroll bar maximum value */
  1957.  
  1958.     e = GetEditInfo(w);
  1959.     numFields = (**e).numFields;
  1960.     SetPort(w);
  1961.     if (key == tabKey) {
  1962.         i = (**e).curField;
  1963.         if (modifiers & shiftKey) {
  1964.             while (true) {
  1965.                 i--;
  1966.                 if (i < 0) i = numFields - 1;
  1967.                 if ((*(**e).fields)[i].canEdit) break;
  1968.             }
  1969.         } else {
  1970.             while (true) {
  1971.                 i++;
  1972.                 if (i >= numFields) i = 0;
  1973.                 if ((*(**e).fields)[i].canEdit) break;
  1974.             }
  1975.         }
  1976.         edit = (*(**e).fields)[i].edit;
  1977.         TESetSelect(0, 0x7fff, edit);
  1978.         AutoScroll(w, i);
  1979.         ChangeCurField(e, i);
  1980.     } else if (key == pageUpKey || key == pageDownKey ||
  1981.         key == homeKey || key == endKey) {
  1982.         scrollBar = (**e).scrollBar;
  1983.         val = (**scrollBar).contrlValue;
  1984.         min = (**scrollBar).contrlMin;
  1985.         max = (**scrollBar).contrlMax;
  1986.         if (key == pageUpKey) {
  1987.             ScrollAction(scrollBar, inPageUp);
  1988.         } else if (key == pageDownKey) {
  1989.             ScrollAction(scrollBar, inPageDown);
  1990.         } else if (key == homeKey) {
  1991.             SetCtlValue(scrollBar, min);
  1992.             Scroll(w, val-min);
  1993.         } else {
  1994.             SetCtlValue(scrollBar, max);
  1995.             Scroll(w, val-max);
  1996.         }
  1997.     } else {
  1998.         legal = utl_StandardAsciiChar(key);
  1999.         if (legal || key == deleteKey || key == leftArrow ||
  2000.             key == rightArrow || key == upArrow || key == downArrow ||
  2001.             key == returnKey) {
  2002.             if ((legal || key == returnKey) && FieldTooBig(e, 1)) return;
  2003.             SetClip((**e).clipRgn);
  2004.             TEKey(key, (*(**e).fields)[(**e).curField].edit);
  2005.             SetClip(BigClipRgn);
  2006.             ProcessFieldChange(w, legal || key == deleteKey || key == returnKey);
  2007.             AutoScroll(w, (**e).curField);
  2008.             oop_UpdateAll();
  2009.         } else {
  2010.             glob_Error(servErrors, msgBadFieldChar, nil);
  2011.         }
  2012.     }
  2013. }
  2014.  
  2015. /*_____________________________________________________________________
  2016.  
  2017.     edit_DoUpdate - Process an Update Event.
  2018.     
  2019.     Entry:    w = pointer to window record.
  2020. _____________________________________________________________________*/
  2021.  
  2022. void edit_DoUpdate (WindowPtr w)
  2023.  
  2024. {
  2025.     EditInfo        **e;                    /* handle to edit info */
  2026.     Rect            viewRect;            /* view rectangle */
  2027.     short            i;                        /* loop index */
  2028.     FieldInfo    *f;                    /* pointer to field info */
  2029.     TEHandle        edit;                    /* handle to TextEdit record */
  2030.     short            right;                /* coord of right window edge */
  2031.     char            str[80];                /* scratch string */
  2032.     short            fieldTop;            /* top coord of field */
  2033.     short            fieldBot;            /* bot coord of field */
  2034.     short            updateTop;            /* top coord of update region */
  2035.     short            updateBot;            /* bot coord of update region */
  2036.     short            v;                        /* v coord */
  2037.     Rect            r;                        /* rect to fill with light gray */
  2038.     short            numFields;            /* number of fields */
  2039.     Boolean        showFieldInfo;        /* true to show full field info */
  2040.  
  2041.     e = GetEditInfo(w);
  2042.     numFields = (**e).numFields;
  2043.     showFieldInfo = (**e).showFieldInfo;
  2044.     EraseRect(&w->portRect);
  2045.     DrawControls(w);
  2046.     GetIndString(str, stringsID, fieldChanged);
  2047.     right = w->portRect.right;
  2048.     MoveTo(right-textMargin-StringWidth(str), fChangedBase);
  2049.     DrawString(str);
  2050.     GetIndString(str, stringsID, cantChange);
  2051.     MoveTo(right-textMargin-StringWidth(str), cantChangeBase);
  2052.     DrawString(str);
  2053.     MoveTo(0, headerRule);
  2054.     Line(right, 0);
  2055.     MoveTo(0, headerRule+2);
  2056.     Line(right, 0);
  2057.     DrawGrowBox(w);
  2058.     GetViewRect(w, &viewRect);
  2059.     ClipRect(&viewRect);
  2060.     updateTop = (**w->visRgn).rgnBBox.top;
  2061.     updateBot = (**w->visRgn).rgnBBox.bottom;
  2062.     HLock((Handle)(**e).fields);
  2063.     for (i = 0; i < numFields; i++) {
  2064.         f = &(*(**e).fields)[i];
  2065.         edit = f->edit;
  2066.         fieldTop = (**edit).viewRect.top - (showFieldInfo ? infoHeight : 0);
  2067.         fieldBot = (**edit).viewRect.bottom + (showFieldInfo ? infoWhite1 : 0);
  2068.         if (fieldBot < updateTop || fieldTop > updateBot) continue;
  2069.         if (showFieldInfo) {
  2070.             v = fieldTop + infoWhite1 + 1;
  2071.             MoveTo(0, v);
  2072.             Line(right - sBarWidthM1, 0);
  2073.             v += infoWhite2 + LineHeight;
  2074.             MoveTo(textMargin, v);
  2075.             DrawString(f->name);
  2076.             DrawChar(':');
  2077.             Move(Width, 0);
  2078.             HLock(f->description);
  2079.             DrawString(*f->description);
  2080.             HUnlock(f->description);
  2081.             v += LineHeight;
  2082.             MoveTo(textMargin, v);
  2083.             HLock(f->attributes);
  2084.             DrawString(*f->attributes);
  2085.             HUnlock(f->attributes);
  2086.             if (**f->attributes) DrawString("\p, ");
  2087.             GetIndString(str, stringsID, maxSizeStr);
  2088.             DrawString(str);
  2089.             NumToString(f->maxSize, str);
  2090.             DrawString(str);
  2091.             v += infoWhite3 + 1;
  2092.             PenPat(qd.ltGray);
  2093.             MoveTo(0, v);
  2094.             Line(right - sBarWidthM1, 0);
  2095.             PenPat(qd.black);
  2096.             r = (**edit).viewRect;
  2097.             r.left = 0;
  2098.             r.right = NameRight + Width;
  2099.             r.top -= infoWhite4;
  2100.             r.bottom += infoWhite1 + 1;
  2101.             FillRect(&r, qd.ltGray);
  2102.         } else {
  2103.             v = fieldTop + Ascent + Leading;
  2104.             MoveTo(NameRight - StringWidth(f->name), v);
  2105.             DrawString(f->name);
  2106.             MoveTo(NameRight, v);
  2107.             DrawChar(':');
  2108.         }
  2109.         if (f->dirty || !f->hasChangeAttr) {
  2110.             MoveTo(TextLeft-Width, (**edit).viewRect.top + Ascent + Leading);
  2111.             if (f->dirty) {
  2112.                 DrawChar('•');
  2113.             } else if (f->canEdit) {
  2114.                 DrawChar('§');
  2115.             } else {
  2116.                 DrawChar('¬');
  2117.             }
  2118.         }
  2119.         TEUpdate(&viewRect, edit);
  2120.     }
  2121.     HUnlock((Handle)(**e).fields);
  2122.     SetClip(BigClipRgn);
  2123. }
  2124.  
  2125. /*_____________________________________________________________________
  2126.  
  2127.     edit_DoActivate - Process an Activate Event.    
  2128.     
  2129.     Entry:    w = pointer to window record.
  2130. _____________________________________________________________________*/
  2131.  
  2132. void edit_DoActivate (WindowPtr w)
  2133.  
  2134. {
  2135.     EditInfo        **e;            /* handle to edit info */
  2136.     
  2137.     e = GetEditInfo(w);
  2138.     TEActivate((*(**e).fields)[(**e).curField].edit);
  2139.     ShowControl((**e).scrollBar);
  2140.     DrawGrowBox(w);
  2141. }
  2142.  
  2143. /*_____________________________________________________________________
  2144.  
  2145.     edit_DoDeactivate - Process a Deactivate Event.    
  2146.     
  2147.     Entry:    w = pointer to window record.
  2148. _____________________________________________________________________*/
  2149.  
  2150. void edit_DoDeactivate (WindowPtr w)
  2151.  
  2152. {
  2153.     EditInfo        **e;            /* handle to edit info */
  2154.     
  2155.     e = GetEditInfo(w);
  2156.     TEDeactivate((*(**e).fields)[(**e).curField].edit);
  2157.     HideControl((**e).scrollBar);
  2158.     DrawGrowBox(w);
  2159. }
  2160.  
  2161. /*_____________________________________________________________________
  2162.  
  2163.     edit_DoGrow - Process Window Grow Operation.
  2164.     
  2165.     Entry:    w = pointer to window record.
  2166.                 where = location of mouse click in global coordinates.
  2167. _____________________________________________________________________*/
  2168.  
  2169. void edit_DoGrow(WindowPtr w, Point where)
  2170.  
  2171. {
  2172.     unsigned long            newSize;            /* new window size */
  2173.     short                        height;            /* new window height */
  2174.     short                        width;            /* new window width */
  2175.  
  2176.     SetPort(w);
  2177.     newSize = GrowWindow(w, where, &SizeRect);
  2178.     if (!newSize) return;
  2179.     height = newSize >> 16;
  2180.     if (!(height & 1)) height--;
  2181.     width = newSize & 0xffff;
  2182.     InvalScroll(w);
  2183.     SizeWindow(w, width, height, true);
  2184.     InvalScroll(w);
  2185.     ChangeSize(w, height);
  2186. }
  2187.  
  2188. /*_____________________________________________________________________
  2189.  
  2190.     edit_DoZoom - Process Window Zoom Operation.
  2191.     
  2192.     Entry:    w = pointer to window record.
  2193.                 where = location of mouse click in global coordinates.
  2194.                 partCode = inZoomIn or inZoomOut
  2195. _____________________________________________________________________*/
  2196.  
  2197. void edit_DoZoom (WindowPtr w, Point where, short partCode)
  2198.  
  2199. {
  2200.     if (!TrackBox(w, where, partCode)) return;
  2201.     SetPort(w);
  2202.     if (partCode == inZoomOut) wstm_ComputeStd(w);
  2203.     EraseRect(&w->portRect);
  2204.     ZoomWindow(w, partCode, false);
  2205.     ChangeSize(w, w->portRect.bottom - w->portRect.top);
  2206. }
  2207.  
  2208. /*_____________________________________________________________________
  2209.  
  2210.     edit_DoClose - Close Window.
  2211.     
  2212.     Entry:    w = pointer to window record.
  2213. _____________________________________________________________________*/
  2214.  
  2215. void edit_DoClose (WindowPtr w)
  2216.  
  2217. {
  2218.     if (AlertIfDirty(w, msgClosing)) return;
  2219.     CloseEditWindow(w);
  2220. }
  2221.  
  2222. /*_____________________________________________________________________
  2223.  
  2224.     edit_DoCommand - Process a Command.
  2225.     
  2226.     Entry:    top = pointer to top window record.
  2227.                 theMenu = menu number.
  2228.                 theItem = menu item number.
  2229. _____________________________________________________________________*/
  2230.  
  2231. #pragma segment command
  2232.  
  2233. Boolean edit_DoCommand (WindowPtr top, short theMenu, short theItem)
  2234.  
  2235. {
  2236.     EditInfo            **e;            /* handle to edit info */
  2237.     TEHandle            textH;        /* handle to active TextEdit record */
  2238.     Handle            scrap;        /* handle to scrap to be pasted */
  2239.     short                scrapLen;    /* length of scrap to be pasted */
  2240.     char                *p;            /* pointer to scrap char */
  2241.     Str255            user;            /* proxy record to open */
  2242.     
  2243.     if (top) e = GetEditInfo(top);
  2244.     switch (theMenu) {
  2245.         case fileID:
  2246.             switch (theItem) {
  2247.                 case newPhCmd:
  2248.                     DoNew();
  2249.                     return true;
  2250.                 case openPhCmd:
  2251.                     DoOpen();
  2252.                     return true;
  2253.                 case savePhCmd:
  2254.                     if (top) DoSave(top);
  2255.                     return true;
  2256.                 case loginCmd:
  2257.                     DoLogin();
  2258.                     return true;
  2259.                 case logoutCmd:
  2260.                     DoLogout();
  2261.                     return true;
  2262.                 case paswdCmd:
  2263.                     if (top) DoChangePassword(top);
  2264.                     return true;
  2265.                 case deletePhCmd:
  2266.                     if (top) DoDelete(top);
  2267.                     return true;
  2268.             }
  2269.             break;
  2270.         case editID:
  2271.             if (!top) break;
  2272.             textH = (*(**e).fields)[(**e).curField].edit;
  2273.             switch (theItem) {
  2274.                 case cutCmd:
  2275.                 case copyCmd:
  2276.                     if (theItem == cutCmd) {
  2277.                         SetClip((**e).clipRgn);
  2278.                         TECut(textH);
  2279.                         SetClip(BigClipRgn);
  2280.                         ProcessFieldChange(top, true);
  2281.                     } else {
  2282.                         TECopy(textH);
  2283.                     }
  2284.                     ZeroScrap();
  2285.                     TEToScrap();
  2286.                     return true;
  2287.                 case pasteCmd:
  2288.                     TEFromScrap();
  2289.                     scrap = TEScrapHandle();
  2290.                     scrapLen = GetHandleSize(scrap);
  2291.                     if (FieldTooBig(e, scrapLen)) break;
  2292.                     p = *scrap;
  2293.                     while (scrapLen--) {
  2294.                         if (!utl_StandardAsciiChar(*p) && *p != returnKey) {
  2295.                             glob_Error(servErrors, msgBadFieldChar, nil);
  2296.                             return true;
  2297.                         };
  2298.                         p++;
  2299.                     }
  2300.                     SetClip((**e).clipRgn);
  2301.                     TEPaste(textH);
  2302.                     SetClip(BigClipRgn);
  2303.                     ProcessFieldChange(top, true);
  2304.                     return true;
  2305.                 case clearCmd:
  2306.                     SetClip((**e).clipRgn);
  2307.                     TEDelete(textH);
  2308.                     SetClip(BigClipRgn);
  2309.                     ProcessFieldChange(top, true);
  2310.                     return true;
  2311.                 case selectAllCmd:
  2312.                     TESetSelect(0, 32767, textH);
  2313.                     return true;
  2314.             }
  2315.             break;
  2316.         case proxyID:
  2317.             HiliteMenu(0);
  2318.             if (Proxy) {
  2319.                 GetItem(ProxyMenu, theItem, user);
  2320.                 GetRecord(user);
  2321.             } else {
  2322.                 glob_Error(servErrors, msgNoProxy, nil);
  2323.             }
  2324.             return true;
  2325.     }
  2326.     return false;
  2327. }
  2328.  
  2329. #pragma segment edit
  2330.  
  2331. /*_____________________________________________________________________
  2332.  
  2333.     edit_Init - Initialize
  2334. _____________________________________________________________________*/
  2335.  
  2336. #pragma segment init
  2337.  
  2338. void edit_Init (void)
  2339.  
  2340. {
  2341.     WindowPtr    w;                    /* pointer to dummy window */
  2342.     
  2343.     w = GetNewWindow(editWindID, nil, (WindowPtr)-1);
  2344.     SetPort(w);
  2345.     TextFont(FontNum);
  2346.     TextSize(fontSize);
  2347.     SetRect(&SizeRect, w->portRect.right+1, minWindHeight, 
  2348.         w->portRect.right+1, 0x7fff);
  2349.     Width = CharWidth('A');
  2350.     NameRight = textMargin + maxFieldName*Width;
  2351.     TextLeft = NameRight + 2*Width;
  2352.     TextRight = w->portRect.right - textMargin - sBarWidthM1;
  2353.     DisposeWindow(w);
  2354.     oop_RegisterCommandHandler(edit_DoCommand);
  2355. }
  2356.  
  2357. #pragma segment edit
  2358.  
  2359. /*_____________________________________________________________________
  2360.  
  2361.     edit_GetLoginStatus - Get Edit Login Status
  2362.     
  2363.     Exit:        function result = status
  2364.                 server = login server, or nil if you don't care.
  2365.                 alias = login alias, or nil if you don't care.
  2366. _____________________________________________________________________*/
  2367.  
  2368. EditLoginStatus edit_GetStatus (Str255 server, Str255 alias)
  2369.  
  2370. {
  2371.     if (LoggedIn) {
  2372.         if (server) utl_CopyPString(server, Server);
  2373.         if (alias) utl_CopyPString(alias, Alias);
  2374.         return Hero ? editHero : editLoggedIn;
  2375.     } else {
  2376.         return editNotLoggedIn;
  2377.     }
  2378. }
  2379.  
  2380. /*_____________________________________________________________________
  2381.  
  2382.     edit_IsDirty - Get Edit Window Dirty Status.
  2383.     
  2384.     Entry:    w = pointer to edit window record.
  2385.     
  2386.     Exit:        function result = true if window is dirty.
  2387. _____________________________________________________________________*/
  2388.  
  2389. Boolean edit_IsDirty (WindowPtr w)
  2390.  
  2391. {
  2392.     EditInfo            **e;            /* handle to edit info */
  2393.     
  2394.     e = GetEditInfo(w);
  2395.     return (**e).dirty;
  2396. }
  2397.  
  2398. /*_____________________________________________________________________
  2399.  
  2400.     edit_Terminate - Terminate.
  2401.     
  2402.     Entry:    interactionPermitted = true if interaction is permitted.
  2403.     
  2404.     Exit:        function result = true if save changes alert canceled.
  2405. _____________________________________________________________________*/
  2406.  
  2407. Boolean edit_Terminate (Boolean interactionPermitted)
  2408.  
  2409. {
  2410.     WindowPtr        v;                        /* pointer to traverse window list */
  2411.     EditInfo            **g;                    /* handle to edit info for window v */
  2412.     short                windNum;                /* window number */
  2413.     
  2414.     v = FrontWindow();
  2415.     while (v) {
  2416.         if (oop_GetWindKind(v) == editWind) {
  2417.             if (interactionPermitted && AlertIfDirty(v, msgQuitting)) 
  2418.                 return true;
  2419.             g = GetEditInfo(v);
  2420.             windNum = (**g).windNum;
  2421.             if (windNum <= numPosSave) wstm_Save(v, &EditStates[windNum]);
  2422.         }
  2423.         v = (WindowPtr)((WindowPeek)v)->nextWindow;
  2424.     }
  2425.     return false;
  2426. }
  2427.