home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Think Class Libraries / WASTE TCL 1.8 / WASTEEdit / CEditDoc.cp < prev    next >
Encoding:
Text File  |  1995-07-09  |  12.1 KB  |  502 lines  |  [TEXT/KAHL]

  1. /******************************************************************************
  2.     CEditDoc.c
  3.     
  4.     Document methods for a tiny editor.
  5.         
  6.     Copyright © 1989 Symantec Corporation. All rights reserved.
  7.  
  8.  ******************************************************************************/
  9.  
  10. #include "Global.h"
  11. #include "Commands.h"
  12. #include "CApplication.h"
  13. #include "CBartender.h"
  14. #include "CDataFile.h"
  15. #include "CDecorator.h"
  16. #include "CDesktop.h"
  17. #include "CError.h"
  18. #include "CPanorama.h"
  19. #include "CScrollPane.h"
  20. #include "TBUtilities.h"
  21. #include "CEditDoc.h"
  22. #include "CEditPane.h"
  23. #include "CWindow.h"
  24. #include <Packages.h>
  25. #include "CResFile.h"
  26.  
  27. #define    WINDculture        500        /* Resource ID for WIND template */
  28.  
  29. extern    CApplication *gApplication;    /* The application */
  30. extern    CBartender    *gBartender;    /* The menu handling object */
  31. extern    CDecorator    *gDecorator;    /* Window dressing object    */
  32. extern    CDesktop    *gDesktop;        /* The enclosure for all windows */
  33. extern    CBureaucrat    *gGopher;        /* The current boss in the chain of command */
  34. extern    OSType        gSignature;        /* The application's signature */
  35. extern    CError        *gError;        /* The error handling object */
  36.  
  37. #define kTypeSoup    'soup'
  38.  
  39. /***
  40.  * IEditDoc
  41.  *
  42.  *    This is your document's initialization method.
  43.  *    If your document has its own instance variables, initialize
  44.  *    them here.
  45.  *    The least you need to do is invoke the default method.
  46.  *
  47.  ***/
  48.  
  49. void CEditDoc::IEditDoc(CApplication *aSupervisor, Boolean printable)
  50.  
  51. {
  52.     CDocument::IDocument(aSupervisor, printable);
  53. }
  54.  
  55.  
  56. /***
  57.  * NewFile
  58.  *
  59.  *    When the user chooses New from the File menu, the CreateDocument()
  60.  *    method in your Application class will send a newly created document
  61.  *    this message. This method needs to create a new window, ready to
  62.  *    work on a new document.
  63.  *
  64.  *    Since this method and the OpenFile() method share the code for creating
  65.  *    the window, you should use an auxiliary window-building method.
  66.  *
  67.  ***/
  68. void CEditDoc::NewFile(void)
  69.  
  70. {
  71.         /**
  72.          **    BuildWindow() is the method that
  73.          **    does the work of creating a window.
  74.          **    It's parameter should be the data that
  75.          **    you want to display in the window.
  76.          **    Since this is a new window, there's nothing
  77.          **    to display.
  78.          **
  79.          **/
  80.  
  81.     BuildWindow(NULL, NULL, NULL);
  82.  
  83.         /**
  84.          **    Send the window a Select() message to make
  85.          **    it the active window.
  86.          **/
  87.     
  88.     itsWindow->Select();
  89. }
  90.  
  91.  
  92. /***
  93.  * OpenFile
  94.  *
  95.  *    When the user chooses Open… from the File menu, the OpenDocument()
  96.  *    method in your Application class will let the user choose a file
  97.  *    and then send a newly created document this message. The information
  98.  *    about the file is in the SFReply record.
  99.  *
  100.  *    In this method, you need to open the file and display its contents
  101.  *    in a window. This method uses the auxiliary window-building method.
  102.  *
  103.  ***/
  104.  
  105. void CEditDoc::OpenFile(SFReply *macSFReply)
  106.  
  107. {
  108.     CDataFile    *theFile;
  109.     Handle        theData;
  110.     Str63        theName;
  111.     OSErr        theError;
  112.     // added by DWC for style/soup support
  113.     CResFile    *resFile;
  114.     StScrpHandle stylHandle = NULL;
  115.     WESoupHandle soupHandle = NULL;
  116.     short         oldRes = CurResFile();
  117.  
  118.         /**
  119.          ** Create a file and send it a SFSpecify()
  120.          **    message to set up the name, volume, and
  121.          **    directory.
  122.          **
  123.          **/
  124.  
  125.     theFile = new(CDataFile);
  126.  
  127.         /**
  128.          **    Be sure to set the instance variable
  129.          **    so other methods can use the file if they
  130.          **    need to. This is especially important if
  131.          **    you leave the file open in this method.
  132.          **    If you close the file after reading it, you
  133.          **    should be sure to set itsFile to NULL.
  134.          **
  135.          **/
  136.  
  137.     itsFile = theFile;
  138.  
  139.     theFile->IDataFile();
  140.     theFile->SFSpecify(macSFReply);
  141.     
  142.  
  143.         /**
  144.          **    Send the file an Open() message to
  145.          **    open it. You can use the ReadSome() or
  146.          **    ReadAll() methods to get the contents of the file.
  147.          **
  148.          **/
  149.  
  150.     theFile->Open(fsRdWrPerm);
  151.     
  152.     /*** no longer needed with WASTE
  153.     if (theFile->GetLength() > 10240L)
  154.     {
  155.         ParamText( "\pCan't open a file this big.", "\p", "\p", "\p");
  156.         PositionDialog('ALRT', 128);
  157.         InitCursor();
  158.         Alert(128, NULL);
  159.         
  160.         delete this;
  161.         return;
  162.     }
  163.     ***/
  164.  
  165.     theData = theFile->ReadAll();     /* ReadAll() creates the handle */
  166.  
  167.     // •• Code added by DWC for style/soup support
  168.     // check for styl, soup resources resource
  169.     resFile = new CResFile();
  170.     resFile->SFSpecify(macSFReply);
  171.     if (resFile->HasResFork())
  172.     {
  173.         resFile->Open(fsRdPerm);
  174.         
  175.         resFile->MakeCurrent(); // Use the resource file.
  176.  
  177.         // •• style ••
  178.         stylHandle = (StScrpHandle)Get1IndResource('styl', 1); // get the resource
  179.         if (stylHandle)
  180.         {
  181.             DetachResource((Handle)stylHandle);
  182. #ifndef WASTE11
  183.             // fix height=0 lines
  184.             nStyles = (*stylHandle)->scrpNStyles;    
  185.             for(i=0; i<nStyles; i++)
  186.                 if ((*stylHandle)->scrpStyleTab[i].scrpSize==0)
  187.                     (*stylHandle)->scrpStyleTab[i].scrpSize = 12;
  188. #endif
  189.         }
  190.         // •• soup ••
  191.         soupHandle = (WESoupHandle)Get1IndResource(kTypeSoup, 1); // get the resource
  192.         if (soupHandle)
  193.         {
  194.             DetachResource((Handle)soupHandle);
  195.         }
  196.         UseResFile(oldRes); // use old resource file
  197.         resFile->Close();
  198.     }
  199.     TCLForgetObject(resFile);
  200.  
  201.     BuildWindow(theData, stylHandle, soupHandle);
  202.  
  203.         /**
  204.          **    In your application, you'll probably store
  205.          **    the data in some form as an instance variable
  206.          **    in your document class. For this example, there's
  207.          **    no need to save it, so we'll get rid of it.
  208.          **
  209.          **/
  210.  
  211.     DisposHandle(theData);
  212.     // added by DWC
  213.     DisposeHandle((Handle)stylHandle);
  214.     DisposeHandle((Handle)soupHandle);
  215.  
  216.         /**
  217.          **    In this implementation, we leave the file
  218.          **    open. You might want to close it after
  219.          **    you've read in all the data.
  220.          **
  221.          **/
  222.  
  223.     itsFile->GetName(theName);
  224.     itsWindow->SetTitle(theName);
  225.     itsWindow->Select();            /* Don't forget to make the window active */
  226. }
  227.  
  228.  
  229.  
  230. /***
  231.  * BuildWindow
  232.  *
  233.  *    This is the auxiliary window-building method that the
  234.  *    NewFile() and OpenFile() methods use to create a window.
  235.  *
  236.  *    In this implementation, the argument is the data to display.
  237.  *
  238.  ***/
  239.  
  240. void CEditDoc::BuildWindow (Handle theData, StScrpHandle stylHandle, WESoupHandle soupHandle)
  241.  
  242. {
  243.     CScrollPane        *theScrollPane;
  244.     CEditPane        *theMainPane;
  245.     Rect            margin;
  246.  
  247.         /**
  248.          **    First create the window and initialize
  249.          **    it. The first argument is the resource ID
  250.          **    of the window. The second argument specifies
  251.          **    whether the window is a floating window.
  252.          **    The third argument is the window's enclosure; it
  253.          **    should always be gDesktop. The last argument is
  254.          **    the window's supervisor in the Chain of Command;
  255.          **    it should always be the Document object.
  256.          **
  257.          **/
  258.  
  259.     itsWindow = new(CWindow);
  260.     itsWindow->IWindow(WINDculture, FALSE, gDesktop, this);
  261.     
  262.         /**
  263.          **    After you create the window, you can use the
  264.          **    SetSizeRect() message to set the window’s maximum
  265.          **    and minimum size. Be sure to set the max & min
  266.          **    BEFORE you send a PlaceNewWindow() message to the
  267.          **    decorator.
  268.          **
  269.          ** The default minimum is 100 by 100 pixels. The
  270.          **    default maximum is the bounds of GrayRgn() (The
  271.          **    entire display area on all screens.)
  272.          **
  273.          **/
  274.  
  275.     theScrollPane = new(CScrollPane);
  276.     
  277.         /**
  278.          **    You can initialize a scroll pane two ways:
  279.          **        1. You can specify all the values
  280.          **           right in your code, like this.
  281.          **        2. You can create a ScPn resource and
  282.          **           initialize the pane from the information
  283.          **           in the resource.
  284.          **
  285.          **/
  286.  
  287.     theScrollPane->IScrollPane(itsWindow, this, 10, 10, 0, 0,
  288.                                 sizELASTIC, sizELASTIC,
  289.                                 TRUE, TRUE, TRUE);
  290.  
  291.         /**
  292.          **    The FitToEnclFrame() method makes the
  293.          **    scroll pane be as large as its enclosure.
  294.          **    In this case, the enclosure is the window,
  295.          **    so the scroll pane will take up the entire
  296.          **    window.
  297.          **
  298.          **/
  299.  
  300.     theScrollPane->FitToEnclFrame(TRUE, TRUE);
  301.  
  302.  
  303.         /**
  304.          **    itsMainPane is the document's focus
  305.          **    of attention. Some of the standard
  306.          **    classes (particularly CPrinter) rely
  307.          **    on itsMainPane pointing to the main
  308.          **    pane of your window.
  309.          **
  310.          **    itsGopher specifies which object
  311.          **    should become the gopher. By default
  312.          **    the document becomes the gopher. It’s
  313.          **    likely that your main pane handles commands
  314.          **    so you’ll almost want to set itsGopher
  315.          **    to point to the same object as itsMainPane.
  316.          **
  317.          **    Note that the main pane is the
  318.          **    panorama in the scroll pane and not
  319.          **    the scroll pane itself.
  320.          **
  321.          **/
  322.  
  323.     theMainPane = new (CEditPane);
  324.  
  325.     itsMainPane = theMainPane;
  326.     itsGopher = theMainPane;
  327.  
  328.         /**
  329.          **    The IEditPane method automatically
  330.          **    fits the pane to the enclosure and
  331.          **    gives us a little margin.
  332.          **
  333.          **/
  334.  
  335.     theMainPane->IEditPane(theScrollPane, this);
  336.  
  337.         /**
  338.          **    Send the scroll pane an InstallPanorama()
  339.          **    to associate our pane with the scroll pane.
  340.          **
  341.          **/
  342.  
  343.     theScrollPane->InstallPanorama(theMainPane);
  344.  
  345.     if (theData)
  346.     {
  347.         // Modified by DWC
  348.         HLock(theData);
  349.         theMainPane->InsertWithStyleSoup(*theData, GetHandleSize(theData),
  350.             stylHandle, soupHandle, true);
  351.         HUnlock(theData);
  352.     }
  353.     
  354.         /**
  355.          **    The Decorator is a global object that takes care
  356.          **    of placing and sizing windows on the screen.
  357.          **    You don't have to use it.
  358.          **
  359.          **/
  360.  
  361.     gDecorator->PlaceNewWindow(itsWindow);
  362. }
  363.  
  364.  
  365.  
  366. /***
  367.  * DoSave
  368.  *
  369.  *    This method handles what happens when the user chooses Save from the
  370.  *    File menu. This method should return TRUE if the file save was successful.
  371.  *    If there is no file associated with the document, you should send a
  372.  *    DoSaveFileAs() message.
  373.  *
  374.  ***/
  375.  
  376. Boolean CEditDoc::DoSave(void)
  377.  
  378. {
  379.     Handle        theData;
  380.     // added by DWC
  381.     StScrpHandle stylHandle;
  382.     WESoupHandle soupHandle;
  383.     CResFile    *resFile;
  384.     short         oldRes = CurResFile();
  385.     Handle        h;
  386.     FSSpec        theSpec;
  387.  
  388.     if (itsFile == NULL)
  389.         return(DoSaveFileAs());
  390.     else {
  391.         // modified by DWC
  392.         // create handles for text, style and soup
  393.         theData = NewHandle(0);
  394.         stylHandle = (StScrpHandle)NewHandle(0);
  395.         soupHandle = (WESoupHandle)NewHandle(0);
  396.         
  397.         // get text, style and soup from edit pane
  398.         ((CEditPane *)itsMainPane)->CopyRangeWithStyleSoup(0, 0x7fffffff, theData,
  399.             stylHandle, soupHandle);
  400.         ((CDataFile *)itsFile)->WriteAll(theData);            
  401.  
  402.         // create resource fork if it doesn't exist
  403.         resFile = new CResFile();
  404.         itsFile->GetFSSpec(&theSpec);
  405.         resFile->SpecifyFSSpec(&theSpec);
  406.         if (!resFile->HasResFork())
  407.         {
  408.             resFile->CreateNew('xxxx', 'xxxx');
  409.         }
  410.         resFile->Open(fsWrPerm);
  411.         resFile->MakeCurrent(); // Use the resource file.
  412.  
  413.         // write styl resource
  414.         // see if resource already exists
  415.         h = Get1IndResource('styl', 1);
  416.         if (h==NULL) // doesn't exist
  417.         {
  418.             AddResource((Handle)stylHandle, 'styl', 128, "\p");
  419.             FailResError();
  420.         }
  421.         else
  422.         {
  423.             // change what's there
  424.             SetHandleSize(h, 0);
  425.             HLock((Handle)stylHandle);
  426.             HandAndHand((Handle)stylHandle, h);
  427.             ChangedResource(h);
  428.             DisposeHandle((Handle)stylHandle);
  429.         }
  430.         if (h) ReleaseResource(h);
  431.  
  432.         // write soup resource
  433.         // see if resource already exists
  434.         h = Get1IndResource(kTypeSoup, 1);
  435.         if (h==NULL) // doesn't exist
  436.         {
  437.             AddResource((Handle)soupHandle, kTypeSoup, 128, "\p");
  438.             FailResError();
  439.         }
  440.         else
  441.         {
  442.             // change what's there
  443.             SetHandleSize(h, 0);
  444.             HLock((Handle)soupHandle);
  445.             HandAndHand((Handle)soupHandle, h);
  446.             ChangedResource(h);
  447.             DisposeHandle((Handle)soupHandle);
  448.         }
  449.         if (h) ReleaseResource(h);
  450.  
  451.         resFile->Update();
  452.         UseResFile(oldRes);
  453.         resFile->Close();
  454.  
  455.         dirty = FALSE;                    /* Document is no longer dirty        */
  456.         gBartender->DisableCmd(cmdSave);
  457.         return(TRUE);                    /* Save was successful                */
  458.     }
  459. }
  460.  
  461.  
  462. /***
  463.  * DoSaveAs
  464.  *
  465.  *    This method handles what happens when the user chooses Save As… from
  466.  *    File menu. The default DoCommand() method for documents sends a DoSaveFileAs()
  467.  *    message which displays a standard put file dialog and sends this message.
  468.  *    The SFReply record contains all the information about the file you're about
  469.  *    to create.
  470.  *
  471.  ***/
  472.  
  473. Boolean CEditDoc::DoSaveAs(SFReply *macSFReply)
  474.  
  475. {
  476.         /**
  477.          **    If there's a file associated with this document
  478.          **    already, close it. The Dispose() method for files
  479.          **    sends a Close() message to the file before releasing
  480.          **    its memory.
  481.          **
  482.          **/
  483.          
  484.     TCLForgetObject(itsFile);
  485.  
  486.  
  487.         /**
  488.          **    Create a new file, and then save it normally.
  489.          **
  490.          **/
  491.  
  492.     itsFile = new(CDataFile);
  493.     ((CDataFile *)itsFile)->IDataFile();
  494.     itsFile->SFSpecify(macSFReply);
  495.     itsFile->CreateNew(gSignature, 'TEXT');
  496.     itsFile->Open(fsRdWrPerm);
  497.     
  498.     itsWindow->SetTitle(macSFReply->fName);
  499.  
  500.     return( DoSave() );
  501. }
  502.