home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Text / Digest-Browser-1.6 Folder / Document / CBrowserDoc.c next >
Encoding:
C/C++ Source or Header  |  1992-09-16  |  13.0 KB  |  574 lines  |  [TEXT/KAHL]

  1. /****
  2.  * CBrowserDoc.c
  3.  *
  4.  *    Document methods for the Digest Browser application.
  5.  *
  6.  *  Copyright © 1990 Symantec Corporation.  All rights reserved.
  7.  *  Copyright © 1991, 1992 Manuel A. Pérez.  All rights reserved.
  8.  *    Portions Copyright © 1992 J. Robert Boonstra, II.  All rights reserved.
  9.  *
  10.  ****/
  11.  
  12. #include "Global.h"
  13. #include "Commands.h"
  14. #include "CApplication.h"
  15. #include "CBartender.h"
  16. #include "CDecorator.h"
  17. #include "CDesktop.h"
  18. #include "CError.h"
  19. #include "CPanorama.h"
  20. #include "CBrowserScrollPane.h"    // JRB change from CScrollPane.h
  21. #include "CBrowserDoc.h"
  22. #include "TBUtilities.h"
  23. #include "CWindow.h"
  24. #include <Packages.h>
  25. #include <string.h>
  26.  
  27. #include "BrowserCmds.h"
  28.  
  29. #define    WINDBrowser        500        /* Resource ID for WIND template */
  30.  
  31.  
  32. extern    CApplication *gApplication;    /* The application */
  33. extern    CBartender    *gBartender;    /* The menu handling object */
  34. extern    CDecorator    *gDecorator;    /* Window dressing object    */
  35. extern    CDesktop    *gDesktop;        /* The enclosure for all windows */
  36. extern    CBureaucrat    *gGopher;        /* The current boss in the chain of command */
  37. extern    OSType        gSignature;        /* The application's signature */
  38. extern    CError        *gError;        /* The global error handler */
  39.  
  40.  
  41. /***
  42.  * IBrowserDoc
  43.  *
  44.  *    Does nothing, just calls the CDocument IDocument method
  45.  *
  46.  ***/
  47.  
  48. void CBrowserDoc::IBrowserDoc(CApplication *aSupervisor, Boolean printable)
  49.  
  50. {
  51.     CDocument::IDocument(aSupervisor, printable);
  52.  
  53.     /* Initialize the default index displayed when the document is first
  54.      * created.  Ideally, we should read this from a resource.
  55.      */
  56.     index_displayed = cmdIndexSubject;
  57.     itsListIndex = NULL;
  58.     itsMessage = NULL;
  59. }
  60.  
  61.  
  62. /***
  63.  * NewFile
  64.  *
  65.  * Empty implementation because we don't allow creation of new documents
  66.  ***/
  67. void CBrowserDoc::NewFile(void)
  68. { }    // This is correct, see note above.
  69.  
  70.  
  71. /***
  72.  * OpenFile
  73.  *
  74.  ***/
  75.  
  76. void CBrowserDoc::OpenFile(SFReply *macSFReply)
  77.  
  78. {
  79. Str63        theName;
  80. OSErr        theError;
  81. BrowserDirPtr    dir;
  82.  
  83.  
  84.     dir = Allocate(BrowserDir);
  85.     brInitDir(dir);
  86.  
  87.     // Copy pascal name to a c name
  88.     PtoCstr(macSFReply->fName);
  89.     strcpy(dir->fname, (char *)&macSFReply->fName);
  90.     CtoPstr(macSFReply->fName);
  91.  
  92.     // Copy the vref too
  93.     dir->vRefNum = macSFReply->vRefNum;
  94.  
  95.     // Then let this program do the work
  96.     BuildBrowserIndex(dir);        // this could fail
  97.     BuildWindow(dir);
  98.     itsWindow->SetTitle(macSFReply->fName);
  99.     itsWindow->Select();            // Don't forget to make the window active
  100. }
  101.  
  102. /***
  103.  *
  104.  * Dispose
  105.  *
  106.  ***/
  107.  
  108. void CBrowserDoc::Dispose()
  109. {
  110.  
  111.     itsListIndex->Dispose();
  112.     itsMessage->Dispose();
  113.  
  114.     inherited::Dispose();
  115. }
  116.  
  117. /***
  118.  * BuildWindow
  119.  *
  120.  *    This is the auxiliary window-building method that the
  121.  *    NewFile() and OpenFile() methods use to create a window.
  122.  *
  123.  *    In this implementation, the argument is the data to display.
  124.  *
  125.  ***/
  126.  
  127. void CBrowserDoc::BuildWindow (BrowserDirPtr dir)
  128. {
  129. // JRB change - replace CScrollPane with CBrowserScrollPane and add new parameter
  130. CBrowserScrollPane        *theScrollPane;
  131. CBrowserScrollPane        *the2ndScrollPane;
  132. LongRect        theAperture;
  133. short            w;
  134.  
  135.             // const to help us understand the code
  136. #define scrollerHeight        120
  137. #define listHeight            (scrollerHeight-16)
  138. #define contentsVLoc        (scrollerHeight+1)
  139.  
  140.     /**    First create the window and initialize it. **/
  141.  
  142.     itsWindow = new(CWindow);
  143.     itsWindow->IWindow(WINDBrowser, FALSE, gDesktop, this);
  144.     itsWindow->GetAperture(&theAperture);
  145.     w = theAperture.bottom - theAperture.top - scrollerHeight;
  146.  
  147.     /** Create a scroll pane for the index field **/
  148. // JRB change - replace ScrollPane with BrowserScrollPane and add new parameter
  149.     theScrollPane = new(CBrowserScrollPane);
  150.     theScrollPane->IBrowserScrollPane(itsWindow, this, 10, scrollerHeight, 0, 0,
  151.                                 sizELASTIC, sizFIXEDSTICKY,
  152.                                 TRUE, TRUE, TRUE,     // JRB - last arg was FALSE
  153.                                 TRUE);                // JRB, SICN size box option
  154.     theScrollPane->FitToEnclFrame(TRUE, FALSE);
  155.  
  156.  
  157.     /**
  158.      **    itsMainPane is the document's focus
  159.      **    of attention. Some of the standard
  160.      **    classes (particularly CPrinter) rely
  161.      **    on itsMainPane pointing to the main
  162.      **    pane of your window.
  163.      **
  164.      **    itsGopher specifies which object
  165.      ** should become the gopher when the document
  166.      ** becomes active. By default
  167.      **    the document becomes the gopher. It’s
  168.      **    likely that your main pane handles commands
  169.      **    so you’ll almost always want to set itsGopher
  170.      **    to point to the same object as itsMainPane.
  171.      **
  172.      **/
  173.  
  174.     /** Create a DisplayIndex (top of the window) */
  175.     itsListIndex = new(CDisplayIndex);
  176.     itsGopher = itsListIndex;
  177.  
  178.     itsListIndex->IDisplayIndex(theScrollPane, this, 0, listHeight, dir, index_displayed);
  179.     theScrollPane->InstallPanorama(itsListIndex);
  180.  
  181.  
  182.     //**
  183.     // Build the contents of the message display
  184.     //**
  185.  
  186.     the2ndScrollPane = new(CBrowserScrollPane);
  187.     the2ndScrollPane->IBrowserScrollPane(itsWindow, this,
  188.             10, w,                    // sizes
  189.             0, contentsVLoc,        // locations
  190.             sizELASTIC, sizELASTIC,    // sizes types
  191.             TRUE, TRUE, TRUE,        // horiz, vert, and size box 
  192.             FALSE);                // JRB, no SICN size box
  193.     the2ndScrollPane->FitToEnclFrame(TRUE, FALSE);        // horiz, vert
  194.  
  195.     itsMessage = new(CDisplayText);
  196.     itsMessage->IDisplayText(the2ndScrollPane, this, contentsVLoc, 1);
  197.     the2ndScrollPane->InstallPanorama(itsMessage);
  198.  
  199.     // itsMainPane is used for printing, so set the message (not the index)
  200.     // field as the main pane.
  201.     itsMainPane = itsMessage;
  202.  
  203.  
  204.     //
  205.     // Establish dependency between the two displays, by making
  206.     // the message display be dependent upon the selection on
  207.     // the index display
  208.     //
  209.     itsMessage->DependUpon(itsListIndex);
  210.  
  211. // JRB addition - following line guarantees first index is selected when doc is opened
  212.     itsListIndex->SetSelectedLine(0, true);
  213.  
  214.     gDecorator->PlaceNewWindow(itsWindow);
  215. }
  216.  
  217. /***
  218.  *
  219.  * WriteTagged
  220.  *
  221.  ***/
  222.  
  223. OSErr CBrowserDoc::WriteTagged(short fileRef)
  224. {
  225. OSErr myErr;
  226. BrowserDirPtr    dir;
  227. BrowserItemPtr    p;
  228. Handle text;
  229. long len;
  230. long offset;
  231.  
  232.     myErr = noErr;
  233.     dir = itsListIndex->GetDirectory();
  234.     for (p = dir->topItem; p != NULL; p = brGetNext(p)) {
  235.  
  236.         if (brGetMark(p)) {
  237.  
  238.             // Write this item to the file
  239.  
  240.             if (myErr == noErr) {
  241.                 len = brGetEnd(p) - brGetStart(p);
  242.                 FailNIL(text = NewHandle(len));        // fail if no memory
  243.                 HLock(text);
  244.                 fseek(brGetFP(p), brGetStart(p), 0);        // read in text
  245.                 fread(*text, 1, len, brGetFP(p));
  246.  
  247.                 offset = 0;                            // replace '\n' with '\r'
  248.                 do {
  249.                     offset = Munger(text, offset, "\n", 1, "\r", 1);
  250.                 } while (offset > 0);
  251.  
  252.                 myErr = FSWrite(fileRef, &len, *text);
  253.  
  254.                 HUnlock(text);
  255.                 DisposHandle(text);                    // release handle 
  256.             }
  257.         }
  258.     }
  259.  
  260.     return myErr;
  261. }
  262.  
  263. /***
  264.  * DoCommand {OVERRIDE}
  265.  *
  266.  *    Execute a command
  267.  *
  268.  ***/
  269.  
  270. void    CBrowserDoc::DoCommand(long theCommand)
  271. {
  272.  
  273.     switch (theCommand) {
  274.  
  275.         case cmdSaveTo:
  276.             SaveTaggedTo();
  277.             break;
  278.  
  279.         case cmdAppendTo:
  280.             AppendTaggedTo();
  281.             break;
  282.  
  283.         case cmdClearMarkedItems:
  284.             ClearTagged();
  285.             break;
  286.  
  287.         case cmdMarkItem:
  288.             TagItem();
  289.             break;
  290.  
  291.         case cmdIndexFrom:
  292.         case cmdIndexDate:
  293.         case cmdIndexSubject:
  294.         case cmdIndexComposite:        // JRB addition
  295.             if (theCommand != index_displayed) {
  296.                 // Store index in an instance variable
  297.                 index_displayed = theCommand;
  298.  
  299.                 // Set the index in the index display
  300.                 itsListIndex->SetIndex(theCommand);
  301.             }
  302.             break;
  303.  
  304.         default:
  305.             inherited::DoCommand(theCommand);
  306.             break;
  307.     }
  308. }
  309.  
  310. /***
  311.  * UpdateMenus {OVERRIDE}
  312.  *
  313.  *    Enable all Index items, and place a check mark next to the current
  314.  *  one.  Enable the save and append commands.
  315.  *
  316.  ***/
  317.  
  318. void    CBrowserDoc::UpdateMenus()
  319. {
  320. BrowserDirPtr theDir;
  321. BrowserItemPtr    selItem;
  322.  
  323.     inherited::UpdateMenus();
  324.  
  325.     // Enable saving only if the document is dirty
  326.     if (dirty) {
  327.         gBartender->EnableCmd(cmdSaveTo);
  328.         gBartender->EnableCmd(cmdAppendTo);
  329.     }
  330.  
  331.     theDir = itsListIndex->GetDirectory();
  332.     if (brMarkCount(theDir) > 0)
  333.         gBartender->EnableCmd(cmdClearMarkedItems);
  334.  
  335.     // Enable the Mark Item menu accordingly
  336.     gBartender->SetCmdText(cmdMarkItem, "\pMark Item");
  337.     if (itsListIndex->GetSelectedLine() >= 0) {
  338.         gBartender->EnableCmd(cmdMarkItem);
  339.         selItem = itsListIndex->GetSelectedItem();
  340.         if (brGetMark(selItem))
  341.             gBartender->SetCmdText(cmdMarkItem, "\pUnmark Item");
  342.     }
  343.  
  344.  
  345.     gBartender->EnableCmd(cmdIndexFrom);
  346.     gBartender->EnableCmd(cmdIndexDate);
  347.     gBartender->EnableCmd(cmdIndexSubject);
  348.     gBartender->EnableCmd(cmdIndexComposite);    // JRB addition
  349.  
  350.     gBartender->CheckMarkCmd(cmdIndexFrom, index_displayed == cmdIndexFrom);
  351.     gBartender->CheckMarkCmd(cmdIndexDate, index_displayed == cmdIndexDate);
  352.     gBartender->CheckMarkCmd(cmdIndexSubject, index_displayed == cmdIndexSubject);
  353.     // JRB addition
  354.     gBartender->CheckMarkCmd(cmdIndexComposite, index_displayed == cmdIndexComposite);
  355. }
  356.  
  357. /***
  358.  * SaveTaggedTo
  359.  ***/
  360.  
  361. void CBrowserDoc::SaveTaggedTo(void)
  362. {
  363. StandardFileReply reply;
  364. OSErr myErr;
  365. short fref;
  366. short vol;
  367. short source;
  368. Str255 prompt, name;
  369.  
  370.     GetIndString(prompt, 1026, 1);
  371.     GetIndString(name, 1026, 2);
  372.     StandardPutFile(prompt, name, &reply);
  373.     if (reply.sfGood) {
  374.         myErr = noErr;
  375.  
  376.         source = CurResFile();        /* save current resource file */
  377.         if (!reply.sfReplacing)
  378.             myErr = FSpCreate(&reply.sfFile, gSignature, 'TEXT', smSystemScript);
  379.  
  380.  
  381. #ifdef COPY_RSRC
  382.         /* Create document's resource fork and copy Finder Resources to it. */
  383.         if (myErr == noErr) {
  384.             FSpCreateResFile(&reply.sfFile, gSignature, 'TEXT', smSystemScript);
  385.             myErr = ResError();
  386.         }
  387.         
  388.         if (myErr == noErr)
  389.             fref = FSpOpenResFile(&reply.sfFile, fsWrPerm);
  390.  
  391.         if (fref > 0)
  392.             myErr = DoCopyResource('STR ', -16396, source, fref);
  393.         else
  394.             myErr = ResError();
  395.  
  396.         if (myErr == noErr)
  397.             myErr = FSClose(fref);
  398. #endif
  399.  
  400.         /* Write our data to the data fork side */
  401.         if (myErr == noErr)
  402.             myErr = FSpOpenDF(&reply.sfFile, fsWrPerm, &fref);
  403.  
  404.         if (myErr == noErr)
  405.             myErr = SetFPos(fref, fsFromStart, 0);
  406.  
  407.         if (myErr == noErr)
  408.             myErr = WriteTagged(fref);
  409.  
  410.         if (myErr == noErr)
  411.             myErr = GetVRefNum(fref, &vol);
  412.  
  413.         if (myErr == noErr)
  414.             myErr = FlushVol(NULL, vol);
  415.  
  416.         if (myErr == noErr)
  417.             myErr = FSClose(fref);
  418.  
  419.  
  420.         if (myErr == noErr)
  421.             dirty = false;
  422.     }
  423. }
  424.  
  425. OSErr CBrowserDoc::DoCopyResource(ResType theType, short theId,
  426.     short source, short dest)
  427. {
  428. Handle myHandle;
  429. Str255 myName;
  430. ResType myType;
  431. short myID;
  432. OSErr err = noErr;
  433.  
  434.     UseResFile(source);
  435.     myHandle = GetResource(theType, theId);
  436.     if (myHandle != NULL) {
  437.         GetResInfo(myHandle, &myID, &myType, myName);
  438.         DetachResource(myHandle);
  439.         UseResFile(dest);
  440.         AddResource(myHandle, theType, theId, myName);
  441.         if (ResError() == noErr)
  442.             WriteResource(myHandle);            /* write resource data */
  443.         err = ResError();
  444.         ReleaseResource(myHandle);
  445.     }
  446.     return err;
  447. }
  448.  
  449. /***
  450.  * AppendTaggedTo
  451.  ***/
  452.  
  453. void CBrowserDoc::AppendTaggedTo(void)
  454. {
  455. SFTypeList typeList;
  456. StandardFileReply reply;
  457. OSErr myErr;
  458. short fref;
  459. short vol;
  460.  
  461.     typeList[0] = 'TEXT';
  462.     StandardGetFile(NULL, 1, typeList, &reply);
  463.     if (reply.sfGood) {
  464.         
  465.         myErr = noErr;
  466.         if (myErr == noErr)
  467.             myErr = FSpOpenDF(&reply.sfFile, fsWrPerm, &fref);
  468.  
  469.         if (myErr == noErr)
  470.             myErr = SetFPos(fref, fsFromLEOF, 0);
  471.  
  472.         if (myErr == noErr)
  473.             myErr = WriteTagged(fref);
  474.  
  475.         if (myErr == noErr)
  476.             myErr = GetVRefNum(fref, &vol);
  477.  
  478.         if (myErr == noErr)
  479.             myErr = FlushVol(NULL, vol);
  480.  
  481.         if (myErr == noErr)
  482.             myErr = FSClose(fref);
  483.  
  484.         if (myErr == noErr)
  485.             dirty = false;
  486.     }
  487. }
  488.  
  489. /***
  490.  * TagItem
  491.  ***/
  492.  
  493. void CBrowserDoc::TagItem(void)
  494. {
  495. BrowserDirPtr theDir;
  496.  
  497.     itsListIndex->TagItem();
  498.     theDir = itsListIndex->GetDirectory();
  499.  
  500.     // set the dirty flag
  501.     dirty = (brMarkCount(theDir) > 0);        // dirty == marked items
  502. }
  503.  
  504. /***
  505.  * ClearTagged
  506.  ***/
  507. void CBrowserDoc::ClearTagged()
  508. {
  509. BrowserDirPtr theDir;
  510. BrowserItemPtr p;
  511. long i;
  512.  
  513.     theDir = itsListIndex->GetDirectory();
  514.  
  515.     for (i = 0, p = theDir->topItem; p != NULL; i++, p = brGetNext(p))
  516.         if (brGetMark(p)) {    // turn them all off
  517.             itsListIndex->SetSelectedLine(i, false);
  518.             itsListIndex->TagItem();
  519.         }
  520.  
  521.     // set the dirty flag
  522.     dirty = false;        // no items tagged, document is clean
  523. }
  524.  
  525. /***
  526.  *
  527.  * AdjustPaneDivider
  528.  *
  529.  ***/
  530.  
  531. // JRB addition to adjust division between panes
  532. void CBrowserDoc::AdjustPaneDivider(Point hitPt, Rect *theDragBox)    /* already in CPane coords */
  533. {
  534. RgnHandle        theRgn;
  535. LongRect        theLongFrameBox;
  536. Rect            theFrameBox,theLimitRect,changeSizeRect;
  537. long            offsetPt;
  538. short             vOffset;
  539.  
  540.     theRgn=NewRgn();
  541.     
  542.     itsWindow->Prepare();    
  543.     
  544.     itsWindow->GetFrame(&theLongFrameBox);
  545.     theFrameBox=itsMainPane->macPort->portRect;
  546.     ClipRect(&theFrameBox);
  547.  
  548.     theDragBox->left = theFrameBox.left;
  549.     theDragBox->right = theFrameBox.right;
  550.     theLimitRect = theFrameBox;
  551.     InsetRect(&theLimitRect,0,48);
  552.     
  553.     RectRgn(theRgn,theDragBox);
  554.     offsetPt=DragGrayRgn(theRgn,hitPt,&theLimitRect,&theFrameBox,vAxisOnly,0L);
  555.     DisposeRgn(theRgn);
  556.  
  557.     vOffset = ((Point *)&offsetPt)->v;
  558.     if (offsetPt!=0x80008000) {        // if user stayed within limitRect ...
  559.         
  560.         SetRect(&changeSizeRect,0,vOffset,0,0);
  561.         ((CBrowserScrollPane*)itsMessage->itsScrollPane)->ChangeSize(&changeSizeRect,true);
  562. //            ChangeSize with a CEditText instead of a CBrowserEditText caused the itsMessage
  563. //            pane to be offset and resizes the bottom of the pane as well as the top, so
  564. //            CBrowserEditText prevents this and offsets the viewRect to compensate.
  565. //            Probably my error in using the class library, but I couldn't find another way
  566. //            around it, so I subclassed CScrollPane.     -- JRB
  567.     
  568.         SetRect(&changeSizeRect,0,0,0,vOffset);
  569.         ((CBrowserScrollPane*)itsListIndex->itsScrollPane)->ChangeSize(&changeSizeRect,true);
  570.     }
  571. }
  572.                     
  573.  
  574.