home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / NewsView 1.0.0 / source / Displayer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-13  |  23.8 KB  |  849 lines  |  [TEXT/KAHL]

  1. /* Displayer.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Offline USENET News Viewer                                             */
  5. /*    Written by Thomas R. Lawrence, 1993 - 1994.                            */
  6. /*                                                                           */
  7. /*    This software is Public Domain; it may be used for any purpose         */
  8. /*    whatsoever without restriction.                                        */
  9. /*                                                                           */
  10. /*    This package is distributed in the hope that it will be useful,        */
  11. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  12. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                   */
  13. /*                                                                           */
  14. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  15. /*                                                                           */
  16. /*****************************************************************************/
  17.  
  18. #include "MiscInfo.h"
  19. #include "Audit.h"
  20. #include "Debug.h"
  21. #include "Definitions.h"
  22.  
  23. #include "Displayer.h"
  24. #include "WindowDispatcher.h"
  25. #include "Array.h"
  26. #include "StringList.h"
  27. #include "Files.h"
  28. #include "Memory.h"
  29. #include "Alert.h"
  30. #include "EditWindowRec.h"
  31. #include "Main.h"
  32. #include "DataMunging.h"
  33.  
  34.  
  35. #define MAXARTICLENAMELENGTH (256)
  36.  
  37. #define INPUTBUFFERSIZE (4096)
  38.  
  39.  
  40. typedef struct
  41.     {
  42.         long                                FileStartPosition;
  43.         long                                BlockLength;
  44.         char*                                ArticleName;
  45.     } ArticleAttribRec;
  46.  
  47.  
  48. struct DisplayWindowRec
  49.     {
  50.         WinType*                        ScreenID;
  51.         StringListRec*            GroupList;
  52.         ArrayRec*                        GroupAttributesList; /* array of ArticleAttribRec's */
  53.         ArrayRec*                        WindowList; /* array of EditWindowRec's */
  54.         FileType*                        DataFile;
  55.         GenericWindowRec*        GenericWindow;
  56.         char*                                StaticLineFeed;
  57.     };
  58.  
  59.  
  60. static ArrayRec*                    OpenWindowList = NIL;
  61.  
  62.  
  63. /* initialize the window crud */
  64. MyBoolean                        InitializeDisplayer(void)
  65.     {
  66.         OpenWindowList = NewArray();
  67.         if (OpenWindowList == NIL)
  68.             {
  69.              FailurePoint1:
  70.                 return False;
  71.             }
  72.         if (!InitializeEditWindow())
  73.             {
  74.              FailurePoint2:
  75.                 DisposeArray(OpenWindowList);
  76.                 goto FailurePoint1;
  77.             }
  78.         return True;
  79.     }
  80.  
  81.  
  82. /* clean up internal structures */
  83. void                                KillWindowStuff(void)
  84.     {
  85.         ERROR(ArrayGetLength(OpenWindowList) != 0,PRERR(AllowResume,
  86.             "KillWindowStuff:  window list isn't empty"));
  87.         DisposeArray(OpenWindowList);
  88.         ShutdownEditWindow();
  89.     }
  90.  
  91.  
  92. /* close all of the currently open things.  returns True if user didn't cancel. */
  93. MyBoolean                        DoCloseAllQuitPending(void)
  94.     {
  95.         long                            Limit;
  96.         long                            Scan;
  97.  
  98.         Limit = ArrayGetLength(OpenWindowList);
  99.         for (Scan = 0; Scan < Limit; Scan += 1)
  100.             {
  101.                 DisposeDisplayWindow(ArrayGetElement(OpenWindowList,Scan));
  102.             }
  103.         return True;
  104.     }
  105.  
  106.  
  107. /* states for parsing articles */
  108. typedef enum
  109.     {
  110.         eRootState EXECUTE(= -13412),
  111.         eRootStateGotSubject,
  112.         eLineFeedState,
  113.         eLineFeedStateGotSubject,
  114.         eStateS,
  115.         eStateU,
  116.         eStateB,
  117.         eStateJ,
  118.         eStateE,
  119.         eStateC,
  120.         eStateT,
  121.         eStateLineFeedPeriod,
  122.         eStateDone
  123.     } States;
  124.  
  125.  
  126. #define ReadCharacter(Buffer,File,CharacterOut,BufferPosition) \
  127.                     (\
  128.                         ((*(BufferPosition) % INPUTBUFFERSIZE) == 0)\
  129.                     ?\
  130.                         (ReadCharacterHard((Buffer),(File),(CharacterOut),(BufferPosition)))\
  131.                     :\
  132.                         ((*(CharacterOut)) = (Buffer)[(((*(BufferPosition))++)\
  133.                         % INPUTBUFFERSIZE)],True)\
  134.                     )
  135.  
  136. /* returns False if it fails */
  137. static MyBoolean        ReadCharacterHard(char Buffer[INPUTBUFFERSIZE], FileType* File,
  138.                                             unsigned char* CharacterOut, unsigned long* BufferPosition)
  139.     {
  140.         if ((*BufferPosition % INPUTBUFFERSIZE) == 0)
  141.             {
  142.                 long                    BytesNotRead;
  143.  
  144.                 BytesNotRead = ReadFromFile(File,Buffer,INPUTBUFFERSIZE);
  145.                 if (BytesNotRead != 0)
  146.                     {
  147.                         if ((GetFileLength(File) != GetFilePosition(File))
  148.                             || (*BufferPosition > GetFileLength(File)))
  149.                             {
  150.                                 return False;
  151.                             }
  152.                     }
  153.             }
  154.         *CharacterOut = Buffer[(((*BufferPosition)++) % INPUTBUFFERSIZE)];
  155.         return True;
  156.     }
  157.  
  158.  
  159. /* open a new display */
  160. void                                OpenDisplayWindow(FileSpec* TheFile)
  161.     {
  162.         DisplayWindowRec*    Window;
  163.         unsigned long            FileLength;
  164.         unsigned long            FilePosition;
  165.         char*                            ErrorMessage = NIL;
  166.         char                            Buffer[INPUTBUFFERSIZE];
  167.  
  168.         CheckPtrExistence(TheFile);
  169.         Window = (DisplayWindowRec*)AllocPtrCanFail(sizeof(DisplayWindowRec),"DisplayWindowRec");
  170.         if (Window == NIL)
  171.             {
  172.                 ErrorMessage = "There is not enough memory available to open the news file.";
  173.              FailurePoint1:
  174.                 AlertHalt(ErrorMessage,NIL);
  175.                 DisposeFileSpec(TheFile);
  176.                 return;
  177.             }
  178.  
  179.         /* create display elements */
  180.         Window->ScreenID = MakeNewWindow(eDocumentWindow,eWindowClosable,eWindowZoomable,
  181.             eWindowResizable,2 + WindowOtherEdgeWidths(eDocumentWindow),2
  182.             + WindowTitleBarHeight(eDocumentWindow),(GetScreenWidth() * 3) / 4,
  183.             (GetScreenHeight() * 3) / 4,(void (*)(void*))&DisplayWindowDoUpdate,Window);
  184.         if (Window->ScreenID == NIL)
  185.             {
  186.                 ErrorMessage = "There is not enough memory available to open the news file.";
  187.              FailurePoint2:
  188.                 ReleasePtr((char*)Window);
  189.                 goto FailurePoint1;
  190.             }
  191.         Window->GroupList = NewStringList(Window->ScreenID,-1,-1,
  192.             GetWindowWidth(Window->ScreenID) + 2,GetWindowHeight(Window->ScreenID) + 2,
  193.             GetMonospacedFont(),9,StringListDontAllowMultipleSelection,NIL);
  194.         if (Window->GroupList == NIL)
  195.             {
  196.                 ErrorMessage = "There is not enough memory available to open the news file.";
  197.              FailurePoint3:
  198.                 KillWindow(Window->ScreenID);
  199.                 goto FailurePoint2;
  200.             }
  201.         Window->GroupAttributesList = NewArray();
  202.         if (Window->GroupAttributesList == NIL)
  203.             {
  204.                 ErrorMessage = "There is not enough memory available to open the news file.";
  205.              FailurePoint4:
  206.                 DisposeStringList(Window->GroupList);
  207.                 goto FailurePoint3;
  208.             }
  209.         Window->WindowList = NewArray();
  210.         if (Window->WindowList == NIL)
  211.             {
  212.                 ErrorMessage = "There is not enough memory available to open the news file.";
  213.              FailurePoint5:
  214.                 DisposeArray(Window->GroupAttributesList);
  215.                 goto FailurePoint4;
  216.             }
  217.         if (!OpenFile(TheFile,&(Window->DataFile),eReadOnly))
  218.             {
  219.                 ErrorMessage = "The news file could not be opened.";
  220.              FailurePoint6:
  221.                 DisposeArray(Window->WindowList);
  222.                 goto FailurePoint5;
  223.             }
  224.         Window->GenericWindow = CheckInNewWindow(Window->ScreenID,Window,
  225.             (void (*)(void*,MyBoolean,OrdType,OrdType,ModifierFlags))&DisplayWindowDoIdle,
  226.             (void (*)(void*))&DisplayWindowBecomeActive,
  227.             (void (*)(void*))&DisplayWindowBecomeInactive,
  228.             (void (*)(void*))&DisplayWindowResized,
  229.             (void (*)(OrdType,OrdType,ModifierFlags,void*))&DisplayWindowDoMouseDown,
  230.             (void (*)(unsigned char,ModifierFlags,void*))&DisplayWindowDoKeyDown,
  231.             (void (*)(void*))&DisplayWindowClose,
  232.             (void (*)(void*))&DisplayWindowMenuSetup,
  233.             (void (*)(void*,MenuItemType*))&DisplayWindowDoMenuCommand);
  234.         if (Window->GenericWindow == NIL)
  235.             {
  236.                 ErrorMessage = "There is not enough memory available to open the news file.";
  237.              FailurePoint7:
  238.                 CloseFile(Window->DataFile);
  239.                 goto FailurePoint6;
  240.             }
  241.         if (!ArrayAppendElement(OpenWindowList,Window))
  242.             {
  243.                 ErrorMessage = "There is not enough memory available to open the news file.";
  244.              FailurePoint8:
  245.                 CheckOutDyingWindow(Window->GenericWindow);
  246.                 goto FailurePoint7;
  247.             }
  248.  
  249.         /* create group attribute list & fill in scrolling string list with names */
  250.         Window->StaticLineFeed = NIL;
  251.         FileLength = GetFileLength(Window->DataFile);
  252.         FilePosition = 0;
  253.         while (FilePosition < FileLength)
  254.             {
  255.                 long                            ArticleNameLength;
  256.                 char                            ArticleNameBuffer[MAXARTICLENAMELENGTH];
  257.                 unsigned char            Character;
  258.                 MyBoolean                    LoopFlag;
  259.                 long                            ArticleStartPosition;
  260.                 States                        SubjState;
  261.                 ArticleAttribRec*    Attributes;
  262.                 char*                            TempStringThang;
  263.  
  264.                 /* get the news group name for the current article */
  265.                 ArticleNameLength = 0;
  266.                 LoopFlag = True;
  267.                 while (LoopFlag)
  268.                     {
  269.                         if (!ReadCharacter(Buffer,Window->DataFile,&Character,&FilePosition))
  270.                             {
  271.                                 ErrorMessage = "A disk error occurred while reading the file.";
  272.                              FileReadFailurePoint1:
  273.                                 while (ArrayGetLength(Window->GroupAttributesList))
  274.                                     {
  275.                                         ArticleAttribRec*    AttrPtr;
  276.  
  277.                                         AttrPtr = ArrayGetElement(Window->GroupAttributesList,0);
  278.                                         CheckPtrExistence(AttrPtr);
  279.                                         ReleasePtr(AttrPtr->ArticleName);
  280.                                         ReleasePtr((char*)AttrPtr);
  281.                                         ArrayDeleteElement(Window->GroupAttributesList,0);
  282.                                     }
  283.                                 ArrayDeleteElement(OpenWindowList,
  284.                                     ArrayFindElement(OpenWindowList,Window));
  285.                                 goto FailurePoint8;
  286.                             }
  287.                         if (Character == 13)
  288.                             {
  289.                                 Window->StaticLineFeed = "\x0d";
  290.                                 LoopFlag = False;
  291.                             }
  292.                         else if (Character == 10)
  293.                             {
  294.                                 Window->StaticLineFeed = "\x0a";
  295.                                 LoopFlag = False;
  296.                             }
  297.                         else
  298.                             {
  299.                                 ArticleNameBuffer[ArticleNameLength] = Character;
  300.                                 ArticleNameLength += 1;
  301.                             }
  302.                     }
  303.                 if (ArticleNameLength < MAXARTICLENAMELENGTH)
  304.                     {
  305.                         ArticleNameBuffer[ArticleNameLength] = ':';
  306.                         ArticleNameLength += 1;
  307.                     }
  308.                 if (ArticleNameLength < MAXARTICLENAMELENGTH)
  309.                     {
  310.                         ArticleNameBuffer[ArticleNameLength] = ' ';
  311.                         ArticleNameLength += 1;
  312.                     }
  313.                 if (ArticleNameLength < MAXARTICLENAMELENGTH)
  314.                     {
  315.                         ArticleNameBuffer[ArticleNameLength] = ' ';
  316.                         ArticleNameLength += 1;
  317.                     }
  318.  
  319.                 /* find out where the article actually begins */
  320.                 ArticleStartPosition = FilePosition;
  321.  
  322.                 /* extract the "Subject: " header field and then end of article */
  323.                 SubjState = eLineFeedState;
  324.                 while (SubjState != eStateDone)
  325.                     {
  326.                         if (!ReadCharacter(Buffer,Window->DataFile,&Character,&FilePosition))
  327.                             {
  328.                                 ErrorMessage = "A disk error occurred while reading the file.";
  329.                                 goto FileReadFailurePoint1;
  330.                             }
  331.                         switch (SubjState)
  332.                             {
  333.                                 default:
  334.                                     EXECUTE(PRERR(ForceAbort,"OpenDisplayWindow:  bad state"));
  335.                                     break;
  336.                                 case eRootState:
  337.                                     if ((Character == 10) || (Character == 13))
  338.                                         {
  339.                                             SubjState = eLineFeedState;
  340.                                         }
  341.                                     break;
  342.                                 case eRootStateGotSubject:
  343.                                     if ((Character == 10) || (Character == 13))
  344.                                         {
  345.                                             SubjState = eLineFeedStateGotSubject;
  346.                                         }
  347.                                     break;
  348.                                 case eLineFeedState:
  349.                                     if ((Character == 10) || (Character == 13))
  350.                                         {
  351.                                             SubjState = eLineFeedState;
  352.                                         }
  353.                                     else if ((Character == 'S') || (Character == 's'))
  354.                                         {
  355.                                             SubjState = eStateS;
  356.                                         }
  357.                                     else if (Character == '.')
  358.                                         {
  359.                                             SubjState = eStateLineFeedPeriod;
  360.                                         }
  361.                                     else
  362.                                         {
  363.                                             SubjState = eRootState;
  364.                                         }
  365.                                     break;
  366.                                 case eLineFeedStateGotSubject:
  367.                                     if ((Character == 10) || (Character == 13))
  368.                                         {
  369.                                             SubjState = eLineFeedStateGotSubject;
  370.                                         }
  371.                                     else if (Character == '.')
  372.                                         {
  373.                                             SubjState = eStateLineFeedPeriod;
  374.                                         }
  375.                                     else
  376.                                         {
  377.                                             SubjState = eRootStateGotSubject;
  378.                                         }
  379.                                     break;
  380.                                 case eStateS:
  381.                                     if ((Character == 10) || (Character == 13))
  382.                                         {
  383.                                             SubjState = eLineFeedState;
  384.                                         }
  385.                                     else if ((Character == 'U') || (Character == 'u'))
  386.                                         {
  387.                                             SubjState = eStateU;
  388.                                         }
  389.                                     else
  390.                                         {
  391.                                             SubjState = eRootState;
  392.                                         }
  393.                                     break;
  394.                                 case eStateU:
  395.                                     if ((Character == 10) || (Character == 13))
  396.                                         {
  397.                                             SubjState = eLineFeedState;
  398.                                         }
  399.                                     else if ((Character == 'B') || (Character == 'b'))
  400.                                         {
  401.                                             SubjState = eStateB;
  402.                                         }
  403.                                     else
  404.                                         {
  405.                                             SubjState = eRootState;
  406.                                         }
  407.                                     break;
  408.                                 case eStateB:
  409.                                     if ((Character == 10) || (Character == 13))
  410.                                         {
  411.                                             SubjState = eLineFeedState;
  412.                                         }
  413.                                     else if ((Character == 'J') || (Character == 'j'))
  414.                                         {
  415.                                             SubjState = eStateJ;
  416.                                         }
  417.                                     else
  418.                                         {
  419.                                             SubjState = eRootState;
  420.                                         }
  421.                                     break;
  422.                                 case eStateJ:
  423.                                     if ((Character == 10) || (Character == 13))
  424.                                         {
  425.                                             SubjState = eLineFeedState;
  426.                                         }
  427.                                     else if ((Character == 'E') || (Character == 'e'))
  428.                                         {
  429.                                             SubjState = eStateE;
  430.                                         }
  431.                                     else
  432.                                         {
  433.                                             SubjState = eRootState;
  434.                                         }
  435.                                     break;
  436.                                 case eStateE:
  437.                                     if ((Character == 10) || (Character == 13))
  438.                                         {
  439.                                             SubjState = eLineFeedState;
  440.                                         }
  441.                                     else if ((Character == 'C') || (Character == 'c'))
  442.                                         {
  443.                                             SubjState = eStateC;
  444.                                         }
  445.                                     else
  446.                                         {
  447.                                             SubjState = eRootState;
  448.                                         }
  449.                                     break;
  450.                                 case eStateC:
  451.                                     if ((Character == 10) || (Character == 13))
  452.                                         {
  453.                                             SubjState = eLineFeedState;
  454.                                         }
  455.                                     else if ((Character == 'T') || (Character == 't'))
  456.                                         {
  457.                                             SubjState = eStateT;
  458.                                         }
  459.                                     else
  460.                                         {
  461.                                             SubjState = eRootState;
  462.                                         }
  463.                                     break;
  464.                                 case eStateT:
  465.                                     if ((Character == 10) || (Character == 13))
  466.                                         {
  467.                                             SubjState = eLineFeedState;
  468.                                         }
  469.                                     else if (Character == ':')
  470.                                         {
  471.                                             while (SubjState != eRootStateGotSubject)
  472.                                                 {
  473.                                                     if (!ReadCharacter(Buffer,Window->DataFile,
  474.                                                         &Character,&FilePosition))
  475.                                                         {
  476.                                                             ErrorMessage = "A disk error occurred while reading "
  477.                                                                 "the file.";
  478.                                                             goto FileReadFailurePoint1;
  479.                                                         }
  480.                                                     if ((Character == 10) || (Character == 13))
  481.                                                         {
  482.                                                             SubjState = eRootStateGotSubject;
  483.                                                         }
  484.                                                     else
  485.                                                         {
  486.                                                             if (ArticleNameLength < MAXARTICLENAMELENGTH)
  487.                                                                 {
  488.                                                                     ArticleNameBuffer[ArticleNameLength] = Character;
  489.                                                                     ArticleNameLength += 1;
  490.                                                                 }
  491.                                                         }
  492.                                                 }
  493.                                             /* invariant:  SubjState == eRootStateGotSubject */
  494.                                         }
  495.                                     else
  496.                                         {
  497.                                             SubjState = eRootState;
  498.                                         }
  499.                                     break;
  500.                                 case eStateLineFeedPeriod:
  501.                                     if ((Character == 10) || (Character == 13))
  502.                                         {
  503.                                             SubjState = eStateDone;
  504.                                         }
  505.                                     else
  506.                                         {
  507.                                             SubjState = eRootState;
  508.                                         }
  509.                                     break;
  510.                             }
  511.                     }
  512.  
  513.                 /* construct the attributes record */
  514.                 Attributes = (ArticleAttribRec*)AllocPtrCanFail(sizeof(ArticleAttribRec),
  515.                     "ArticleAttribRec");
  516.                 if (Attributes == NIL)
  517.                     {
  518.                         ErrorMessage = "There is not enough memory available to open the news file.";
  519.                         goto FileReadFailurePoint1;
  520.                     }
  521.                 Attributes->ArticleName = BlockFromRaw(ArticleNameBuffer,ArticleNameLength);
  522.                 if (Attributes->ArticleName == NIL)
  523.                     {
  524.                         ErrorMessage = "There is not enough memory available to open the news file.";
  525.                      FileReadFailurePoint2:
  526.                         ReleasePtr((char*)Attributes);
  527.                         goto FileReadFailurePoint1;
  528.                     }
  529.                 Attributes->FileStartPosition = ArticleStartPosition;
  530.                 Attributes->BlockLength = FilePosition - ArticleStartPosition;
  531.  
  532.                 /* add thing to list */
  533.                 if (!ArrayAppendElement(Window->GroupAttributesList,Attributes))
  534.                     {
  535.                         ErrorMessage = "There is not enough memory available to open the news file.";
  536.                      FileReadFailurePoint3:
  537.                         ReleasePtr(Attributes->ArticleName);
  538.                         goto FileReadFailurePoint2;
  539.                     }
  540.                 TempStringThang = BlockToStringCopy(Attributes->ArticleName);
  541.                 if (TempStringThang == NIL)
  542.                     {
  543.                         ErrorMessage = "There is not enough memory available to open the news file.";
  544.                      FileReadFailurePoint4:
  545.                         ArrayDeleteElement(Window->GroupAttributesList,
  546.                             ArrayFindElement(Window->GroupAttributesList,Attributes));
  547.                         goto FileReadFailurePoint3;
  548.                     }
  549.                 if (!InsertStringListElement(Window->GroupList,TempStringThang,NIL,
  550.                     Attributes,False/*don'tredrawrightaway*/))
  551.                     {
  552.                         ErrorMessage = "There is not enough memory available to open the news file.";
  553.                      FileReadFailurePoint5:
  554.                         ReleasePtr(TempStringThang);
  555.                         goto FileReadFailurePoint4;
  556.                     }
  557.                 ReleasePtr(TempStringThang);
  558.  
  559.                 /* let the user do some other crud */
  560.                 RelinquishCPUJudiciouslyCheckCancel();
  561.             }
  562.         RedrawStringList(Window->GroupList);
  563.         if (Window->StaticLineFeed == NIL)
  564.             {
  565.                 Window->StaticLineFeed = SYSTEMLINEFEED;
  566.             }
  567.         DisposeFileSpec(TheFile);
  568.     }
  569.  
  570.  
  571. /* dispose of a window */
  572. void                                DisposeDisplayWindow(DisplayWindowRec* Window)
  573.     {
  574.         CheckPtrExistence(Window);
  575.         DisposeStringList(Window->GroupList);
  576.         CheckOutDyingWindow(Window->GenericWindow);
  577.         CloseFile(Window->DataFile);
  578.         while (ArrayGetLength(Window->WindowList) != 0)
  579.             {
  580.                 DisposeEditWindow(ArrayGetElement(Window->WindowList,0));
  581.             }
  582.         DisposeArray(Window->WindowList);
  583.         while (ArrayGetLength(Window->GroupAttributesList))
  584.             {
  585.                 ArticleAttribRec*    AttrPtr;
  586.  
  587.                 AttrPtr = ArrayGetElement(Window->GroupAttributesList,0);
  588.                 CheckPtrExistence(AttrPtr);
  589.                 ReleasePtr(AttrPtr->ArticleName);
  590.                 ReleasePtr((char*)AttrPtr);
  591.                 ArrayDeleteElement(Window->GroupAttributesList,0);
  592.             }
  593.         DisposeArray(Window->GroupAttributesList);
  594.         KillWindow(Window->ScreenID);
  595.         ArrayDeleteElement(OpenWindowList,ArrayFindElement(OpenWindowList,Window));
  596.         ReleasePtr((char*)Window);
  597.     }
  598.  
  599.  
  600. /* register a new article window */
  601. MyBoolean                        DisplayWindowNewArticleWindow(DisplayWindowRec* Window,
  602.                                             struct EditWindowRec* NewWindow)
  603.     {
  604.         CheckPtrExistence(Window);
  605.         return ArrayAppendElement(Window->WindowList,NewWindow);
  606.     }
  607.  
  608.  
  609. /* article window calls this when it is going bye-bye */
  610. void                                DisplayWindowArticleDead(DisplayWindowRec* Window,
  611.                                             struct EditWindowRec* DeadWindow)
  612.     {
  613.         CheckPtrExistence(Window);
  614.         ArrayDeleteElement(Window->WindowList,ArrayFindElement(Window->WindowList,DeadWindow));
  615.     }
  616.  
  617.  
  618. void                                DisplayWindowDoIdle(DisplayWindowRec* Window,
  619.                                             MyBoolean CheckCursorFlag, OrdType XLoc, OrdType YLoc,
  620.                                             ModifierFlags Modifiers)
  621.     {
  622.         CheckPtrExistence(Window);
  623.         if (CheckCursorFlag)
  624.             {
  625.                 SetArrowCursor();
  626.             }
  627.     }
  628.  
  629.  
  630. void                                DisplayWindowBecomeActive(DisplayWindowRec* Window)
  631.     {
  632.         CheckPtrExistence(Window);
  633.         EnableStringList(Window->GroupList);
  634.     }
  635.  
  636.  
  637. void                                DisplayWindowBecomeInactive(DisplayWindowRec* Window)
  638.     {
  639.         CheckPtrExistence(Window);
  640.         DisableStringList(Window->GroupList);
  641.     }
  642.  
  643.  
  644. void                                DisplayWindowResized(DisplayWindowRec* Window)
  645.     {
  646.         CheckPtrExistence(Window);
  647.         SetStringListLoc(Window->GroupList,-1,-1,GetWindowWidth(Window->ScreenID) + 2,
  648.             GetWindowHeight(Window->ScreenID) + 2);
  649.     }
  650.  
  651.  
  652. static void                    OpenANewArticle(DisplayWindowRec* Window)
  653.     {
  654.         ArrayRec*                    Selection;
  655.         long                            Limit;
  656.         long                            Scan;
  657.         char*                            ErrorMessage = NIL;
  658.  
  659.         Selection = GetListOfSelectedItems(Window->GroupList);
  660.         if (Selection == NIL)
  661.             {
  662.                 ErrorMessage = "There is not enough memory available to display the article.";
  663.              FailurePoint0:
  664.                 AlertHalt(ErrorMessage,NIL);
  665.                 return;
  666.             }
  667.         Limit = ArrayGetLength(Selection);
  668.         for (Scan = 0; Scan < Limit; Scan += 1)
  669.             {
  670.                 char*                            Buffer;
  671.                 ArticleAttribRec*    AttrPtr;
  672.                 EditWindowRec*        EditWindow;
  673.  
  674.                 AttrPtr = ArrayGetElement(Selection,Scan);
  675.                 CheckPtrExistence(AttrPtr);
  676.                 Buffer = AllocPtrCanFail(AttrPtr->BlockLength,"ArticleBuffer");
  677.                 if (Buffer == NIL)
  678.                     {
  679.                         ErrorMessage = "There is not enough memory available to "
  680.                             "display the article.";
  681.                      FailurePoint1:
  682.                         DisposeArray(Selection);
  683.                         goto FailurePoint0;
  684.                     }
  685.                 if (!SetFilePosition(Window->DataFile,AttrPtr->FileStartPosition))
  686.                     {
  687.                         ErrorMessage = "The article could not be read from the file.";
  688.                      FailurePoint2:
  689.                         ReleasePtr(Buffer);
  690.                         goto FailurePoint1;
  691.                     }
  692.                 if (0 != ReadFromFile(Window->DataFile,Buffer,AttrPtr->BlockLength))
  693.                     {
  694.                         ErrorMessage = "The article could not be read from the file.";
  695.                      FailurePoint3:
  696.                         goto FailurePoint2;
  697.                     }
  698.                 EditWindow = NewEditWindow(Buffer,Window->StaticLineFeed,
  699.                     AttrPtr->ArticleName,Window);
  700.                 if (EditWindow == NIL)
  701.                     {
  702.                         ErrorMessage = "There is not enough memory available to "
  703.                             "display the article.";
  704.                      FailurePoint4:
  705.                         goto FailurePoint3;
  706.                     }
  707.                 ReleasePtr(Buffer);
  708.             }
  709.         DisposeArray(Selection);
  710.     }
  711.  
  712.  
  713. void                                DisplayWindowDoMouseDown(OrdType XLoc, OrdType YLoc,
  714.                                             ModifierFlags Modifiers, DisplayWindowRec* Window)
  715.     {
  716.         OrdType                        XSize;
  717.         OrdType                        YSize;
  718.  
  719.         CheckPtrExistence(Window);
  720.         XSize = GetWindowWidth(Window->ScreenID);
  721.         YSize = GetWindowHeight(Window->ScreenID);
  722.         if (((Modifiers & eCommandKey) != 0) && (XLoc >= XSize - 15)
  723.             && (YLoc >= YSize - 15) && (XLoc < XSize) && (YLoc < YSize))
  724.             {
  725.                 UserGrowWindow(Window->ScreenID,XLoc,YLoc);
  726.                 DisplayWindowResized(Window);
  727.             }
  728.         else if (StringListHitTest(Window->GroupList,XLoc,YLoc))
  729.             {
  730.                 if (StringListMouseDown(Window->GroupList,XLoc,YLoc,Modifiers))
  731.                     {
  732.                         OpenANewArticle(Window);
  733.                     }
  734.             }
  735.     }
  736.  
  737.  
  738. void                                DisplayWindowDoKeyDown(unsigned char KeyCode,
  739.                                             ModifierFlags Modifiers, DisplayWindowRec* Window)
  740.     {
  741.         ArrayRec*                    Selection;
  742.  
  743.         CheckPtrExistence(Window);
  744.         switch (KeyCode)
  745.             {
  746.                 case 13:  /* return key opens up the selected article */
  747.                     OpenANewArticle(Window);
  748.                     break;
  749.                 case eUpArrow:  /* up arrow selects the previous thing */
  750.                     if (ArrayGetLength(Window->GroupAttributesList) != 0)
  751.                         {
  752.                             Selection = GetListOfSelectedItems(Window->GroupList);
  753.                             if (Selection != NIL)
  754.                                 {
  755.                                     ArticleAttribRec*    Attr;
  756.  
  757.                                     if (ArrayGetLength(Selection) == 0)
  758.                                         {
  759.                                             Attr = ArrayGetElement(Window->GroupAttributesList,
  760.                                                 ArrayGetLength(Window->GroupAttributesList) - 1);
  761.                                         }
  762.                                      else
  763.                                         {
  764.                                             long                            Index;
  765.  
  766.                                             Index = ArrayFindElement(Window->GroupAttributesList,
  767.                                                 ArrayGetElement(Selection,0)) - 1;
  768.                                             if (Index < 0)
  769.                                                 {
  770.                                                     Index = ArrayGetLength(Window->GroupAttributesList) - 1;
  771.                                                 }
  772.                                             Attr = ArrayGetElement(Window->GroupAttributesList,Index);
  773.                                         }
  774.                                     SelectStringListElement(Window->GroupList,Attr);
  775.                                     MakeStringListSelectionVisible(Window->GroupList);
  776.                                     DisposeArray(Selection);
  777.                                 }
  778.                         }
  779.                     break;
  780.                 case eDownArrow:  /* up arrow selects the previous thing */
  781.                     if (ArrayGetLength(Window->GroupAttributesList) != 0)
  782.                         {
  783.                             Selection = GetListOfSelectedItems(Window->GroupList);
  784.                             if (Selection != NIL)
  785.                                 {
  786.                                     ArticleAttribRec*    Attr;
  787.  
  788.                                     if (ArrayGetLength(Selection) == 0)
  789.                                         {
  790.                                             Attr = ArrayGetElement(Window->GroupAttributesList,0);
  791.                                         }
  792.                                      else
  793.                                         {
  794.                                             long                            Index;
  795.  
  796.                                             Index = ArrayFindElement(Window->GroupAttributesList,
  797.                                                 ArrayGetElement(Selection,0)) + 1;
  798.                                             if (Index >= ArrayGetLength(Window->GroupAttributesList))
  799.                                                 {
  800.                                                     Index = 0;
  801.                                                 }
  802.                                             Attr = ArrayGetElement(Window->GroupAttributesList,Index);
  803.                                         }
  804.                                     SelectStringListElement(Window->GroupList,Attr);
  805.                                     MakeStringListSelectionVisible(Window->GroupList);
  806.                                     DisposeArray(Selection);
  807.                                 }
  808.                         }
  809.                     break;
  810.             }
  811.     }
  812.  
  813.  
  814. void                                DisplayWindowClose(DisplayWindowRec* Window)
  815.     {
  816.         CheckPtrExistence(Window);
  817.         DisposeDisplayWindow(Window);
  818.     }
  819.  
  820.  
  821. void                                DisplayWindowMenuSetup(DisplayWindowRec* Window)
  822.     {
  823.         CheckPtrExistence(Window);
  824.         EnableMenuItem(mCloseFile);
  825.         ChangeItemName(mCloseFile,"Close News File");
  826.     }
  827.  
  828.  
  829. void                                DisplayWindowDoMenuCommand(DisplayWindowRec* Window,
  830.                                             struct MenuItemType* MenuItem)
  831.     {
  832.         CheckPtrExistence(Window);
  833.         if (mCloseFile == MenuItem)
  834.             {
  835.                 DisposeDisplayWindow(Window);
  836.             }
  837.         else
  838.             {
  839.                 EXECUTE(PRERR(AllowResume,"DisplayWindowDoMenuCommand:  unknown menu command"));
  840.             }
  841.     }
  842.  
  843.  
  844. void                                DisplayWindowDoUpdate(DisplayWindowRec* Window)
  845.     {
  846.         CheckPtrExistence(Window);
  847.         RedrawStringList(Window->GroupList);
  848.     }
  849.