home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 October: Mac OS SDK / Dev.CD Oct 00 SDK1.toast / Development Kits / Mac OS / MLTE SDK / TEtoMLTESample / MLTESources / MLTESample.cp < prev    next >
Encoding:
Text File  |  2000-03-02  |  13.3 KB  |  463 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    MultiFinder-Aware Simple TextEdit Sample Application
  6. #
  7. #    CPlusTESample
  8. #
  9. #    TESample.cp    -    C++ source
  10. #
  11. #    Copyright © 1989 Apple Computer, Inc.
  12. #    All rights reserved.
  13. #
  14. #    Versions:    
  15. #            1.20                    10/91
  16. #            1.10                     07/89
  17. #            1.00                     04/89
  18. #
  19. #    Components:
  20. #            CPlusTESample.make        July 9, 1989
  21. #            TApplicationCommon.h    July 9, 1989
  22. #            TApplication.h            July 9, 1989
  23. #            TDocument.h                July 9, 1989
  24. #            TECommon.h                July 9, 1989
  25. #            TESample.h                July 9, 1989
  26. #            TEDocument.h            July 9, 1989
  27. #            TESample.cp                July 9, 1989
  28. #            TESample.r                July 9, 1989
  29. #
  30. #    CPlusTESample is an example application that demonstrates
  31. #    how to initialize the commonly used toolbox managers,
  32. #    operate successfully under MultiFinder, handle desk
  33. #    accessories and create, grow, and zoom windows. The
  34. #    fundamental TextEdit toolbox calls and TextEdit autoscroll
  35. #    are demonstrated. It also shows how to create and maintain
  36. #    scrollbar controls. 
  37. #
  38. #    This version of TESample has been substantially reworked in
  39. #    C++ to show how a "typical" object oriented program could
  40. #    be written. To this end, what was once a single source code
  41. #    file has been restructured into a set of classes which
  42. #    demonstrate the advantages of object-oriented programming.
  43. #
  44. ------------------------------------------------------------------------------*/
  45.  
  46.  
  47. /*
  48. Segmentation strategy:
  49.  
  50.     This program has only one segment, since the issues
  51.     surrounding segmentation within a class's methods have
  52.     not been investigated yet. We DO unload the data
  53.     initialization segment at startup time, which frees up
  54.     some memory 
  55.  
  56. SetPort strategy:
  57.  
  58.     Toolbox routines do not change the current port. In
  59.     spite of this, in this program we use a strategy of
  60.     calling SetPort whenever we want to draw or make calls
  61.     which depend on the current port. This makes us less
  62.     vulnerable to bugs in other software which might alter
  63.     the current port (such as the bug (feature?) in many
  64.     desk accessories which change the port on OpenDeskAcc).
  65.     Hopefully, this also makes the routines from this
  66.     program more self-contained, since they don't depend on
  67.     the current port setting. 
  68.  
  69. Clipboard strategy:
  70.  
  71.     This program does not maintain a private scrap.
  72.     Whenever a cut, copy, or paste occurs, we import/export
  73.     from the public scrap to TextEdit's scrap right away,
  74.     using the TEToScrap and TEFromScrap routines. If we did
  75.     use a private scrap, the import/export would be in the
  76.     activate/deactivate event and suspend/resume event
  77.     routines. 
  78. */
  79.  
  80. #include <Types.h>
  81. #include <Quickdraw.h>
  82. #include <Fonts.h>
  83. #include <Controls.h>
  84. #include <Windows.h>
  85. #include <TextEdit.h>
  86. #include <Dialogs.h>
  87. #include <Menus.h>
  88. #include <Devices.h>
  89. #include <Events.h> 
  90. #include <Scrap.h>
  91. #include <ToolUtils.h>
  92. #include <Memory.h>
  93. #include <SegLoad.h>
  94. #include <Files.h>
  95. #include <OSUtils.h>
  96. #include <Traps.h>
  97.  
  98. // our class definitions
  99. #include "MLTEDocument.h"
  100. #include "MLTESample.h"
  101.  
  102. // ExtremeNeg and ExtremePos are used to set up wide open rectangles and regions.
  103. const short kExtremeNeg = -32768;
  104. const short kExtremePos = 32767 - 1; // required to address an old region bug
  105.  
  106. // kMaxOpenDocuments is used to determine whether a new document can be opened
  107. // or created. We keep track of the number of open documents, and disable the
  108. // menu items that create a new document when the maximum is reached. If the
  109. // number of documents falls below the maximum, the items are enabled again. */
  110. const short    kMaxOpenDocuments = 1;
  111.     
  112. // Define max and min macros for efficiency.
  113. #define max(a,b)        ((a) > (b) ? (a) : (b))
  114. #define min(a,b)        ((a) < (b) ? (a) : (b))
  115.  
  116. // Our application object, initialized in main(). We make it
  117. // global so our functions which don't belong to any class
  118. // can find the active document.
  119.     TESample *gTheApplication;
  120.  
  121.  
  122.  
  123. /***********************************************************************/
  124. //
  125. // TESample
  126. //
  127. /***********************************************************************/
  128.  
  129. //-----------------------------------------------------------------------
  130. // main -    main is the entrypoint to the program
  131. // 
  132.     int main( void )
  133.     {
  134.         // Create our application object. This MUST be the FIRST thing
  135.         // done in main(), since it initializes the Toolbox for us.
  136.             gTheApplication = new TESample;
  137.             if (gTheApplication == nil)                        // if we couldn't allocate object (impossible!?)
  138.                 return 0;                                    // go back to Finder
  139.         
  140.         // Start our main event loop running. This won't return until user quits
  141.             gTheApplication->EventLoop();
  142.     
  143.         // We always return a value, like good little ANSI worshippers
  144.             return 0;
  145.             
  146.     } /* main */
  147.  
  148.  
  149.  
  150. /***********************************************************************/
  151. //
  152. // TESample class declarations
  153. //
  154. /***********************************************************************/
  155.  
  156. //-----------------------------------------------------------------------
  157. // TESample::TESample -    the constructor for our class, called automatically when we create
  158. //                         an instance of this class. In this particular case, we only want
  159. //                         one instance since the constructor does all the menu setups and
  160. //                         creates our (untitled) document.
  161. //
  162.     TESample::TESample( void )
  163.     {
  164.         Handle        menuBar;
  165.         OSStatus    status;
  166.     
  167.         // change initialize MLTE
  168.         status = TXNInitTextension (NULL, 0, kNilOptions);
  169.         if ( status != NULL )
  170.             BigBadError( kErrStrings,eWrongMachine );
  171.  
  172.         // read menus into menu bar
  173.             menuBar = GetNewMBar(rMenuBar);
  174.             
  175.         // install menus
  176.             SetMenuBar(menuBar);
  177.             DisposeHandle(menuBar);
  178.             
  179.         // add DA names to Apple menu
  180.             AppendResMenu(GetMenuHandle(mApple), 'DRVR');
  181.             DrawMenuBar();
  182.     
  183.         // create empty mouse region
  184.             fMouseRgn = NewRgn();
  185.             
  186.         // create a single empty document
  187.             DoNew();
  188.         
  189.         // make sure we have a valid cursor region
  190.             AdjustCursor();
  191.             
  192.     } /* TESample (constructor) */
  193.  
  194.  
  195. //-----------------------------------------------------------------------
  196. // TESample::HeapNeeded -    Tell TApplication class how much heap we need
  197. //
  198.     long TESample::HeapNeeded( void )
  199.     {
  200.         return ( kMinSize * 1024 );
  201.         
  202.     } /* TESample::HeapNeeded */
  203.  
  204.  
  205. //-----------------------------------------------------------------------
  206. // TESample::HeapNeeded -    Calculate a sleep value for WaitNextEvent. This
  207. //                            takes into account the things that DoIdle does
  208. //                            with idle time.
  209. //
  210.     unsigned long TESample::SleepVal( void )
  211.     {
  212.         unsigned long sleep;
  213.     
  214.         sleep = kMaxSleepTime;                // default value for sleep
  215.         
  216.         // if we aren't in background, let document tell us how long to sleep
  217.             if (( !fInBackground ) && ( fCurDoc != nil ))
  218.                 sleep = min( sleep, fCurDoc->CalcIdle());
  219.                 
  220.             return sleep;
  221.         
  222.     } /* TESample::SleepVal */
  223.  
  224.  
  225. //-----------------------------------------------------------------------
  226. // TESample::DoIdle -    This is called whenever we get a null event et al.
  227. //                         It takes care of necessary periodic actions. For this program,
  228. //                         it calls TEIdle.
  229. //
  230.     void TESample::DoIdle( void )
  231.     {
  232.         TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  233.     
  234.         if ( fTECurDoc != nil )
  235.             fTECurDoc->DoIdle();
  236.           
  237.     } /* TESample::DoIdle */
  238.  
  239.  
  240. //-----------------------------------------------------------------------
  241. // TESample::AdjustCursor -    This is called whenever we get a null event et al.
  242. //                             Change the cursor's shape, depending on its position.
  243. //                            This also calculates a region that includes the
  244. //                            cursor for WaitNextEvent.
  245. //
  246.     void TESample::AdjustCursor( void )
  247.     {
  248.         TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  249.     
  250.         // notice that we don't change cursor if front window isn't ours
  251.             if (( !fInBackground ) && ( fTECurDoc != nil ))
  252.               {
  253.                   //change remove everything in here and replace it with
  254.                   // TXNAdjustCursor we pass NULL for the cursor region
  255.                   // because we are letting MLTE handle all of that.
  256.                 TXNAdjustCursor    (fTECurDoc->GetMLTEObject(), fMouseRgn);
  257.               }
  258.     } /* TESample::AdjustCursor */
  259.  
  260.  
  261. //-----------------------------------------------------------------------
  262. // TESample::AdjustMenus -    Enable and disable menus based on the current state.
  263. //                             The user can only select enabled menu items. We set
  264. //                            up all the menu items before calling MenuSelect or
  265. //                            MenuKey, since these are the only times that a menu
  266. //                            item can be selected. Note that MenuSelect is also
  267. //                            the only time the user will see menu items. This
  268. //                            approach to deciding what enable/disable state a
  269. //                            menu item has the advantage of concentrating all the
  270. //                            decision-making in one routine, as opposed to being
  271. //                            spread throughout the application. Other application
  272. //                            designs may take a different approach that may or may
  273. //                            not be as valid. 
  274. //
  275.     void TESample::AdjustMenus( void )
  276.     {
  277.         WindowPtr    frontmost;
  278.         MenuHandle    menu;
  279.         Boolean        undo;
  280.         Boolean        cutCopyClear;
  281.         Boolean        paste;
  282.         TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  283.     
  284.         frontmost = FrontWindow();
  285.     
  286.         menu = GetMenuHandle( mFile );
  287.         if ( fDocList->NumDocs() < kMaxOpenDocuments )    // New is enabled when we can open more documents 
  288.             EnableItem( menu, iNew );                    
  289.         else
  290.             DisableItem( menu, iNew );
  291.         
  292.         if ( frontmost != (WindowPtr) nil )                // Close is enabled when there is a window to close 
  293.             EnableItem( menu, iClose );
  294.         else
  295.             DisableItem( menu, iClose );
  296.     
  297.         menu = GetMenuHandle( mEdit );
  298.         undo = false;
  299.         cutCopyClear = false;
  300.         paste = false;
  301.         
  302.         if ( frontmost != nil )
  303.         {
  304.             if ( fTECurDoc == nil )
  305.             {
  306.                 undo = true;                            // all editing is enabled for DA windows 
  307.                 cutCopyClear = true;
  308.                 paste = true;
  309.             }
  310.             else
  311.             {
  312.                 // Cut, Copy, and Clear is enabled for app. windows with selections 
  313.                     if ( fTECurDoc->HaveSelection())
  314.                         cutCopyClear = true;
  315.                     
  316.                 // If we have any TEXT in the scrap, enable paste
  317.                 // change switch from GetScrap to TXNIsScrapPastable
  318.                     if ( TXNIsScrapPastable())
  319.                         paste = true; 
  320.             }
  321.         }
  322.         
  323.         if ( undo )
  324.             EnableItem( menu, iUndo );
  325.         else
  326.             DisableItem( menu, iUndo );
  327.             
  328.         if ( cutCopyClear )
  329.         {
  330.             EnableItem( menu, iCut );
  331.             EnableItem( menu, iCopy );
  332.             EnableItem( menu, iClear );
  333.         } 
  334.         else
  335.         {
  336.             DisableItem( menu, iCut );
  337.             DisableItem( menu, iCopy );
  338.             DisableItem( menu, iClear );
  339.         }
  340.         
  341.         if ( paste )
  342.             EnableItem( menu, iPaste );
  343.         else
  344.             DisableItem( menu, iPaste );
  345.             
  346.     } /* TESample::AdjustMenus */
  347.  
  348.  
  349. //-----------------------------------------------------------------------
  350. // TESample::DoMenuCommand -    This is called when an item is chosen from the 
  351. //                                menu bar (after calling MenuSelect or MenuKey).
  352. //                                It does the right thing for each command.
  353. //
  354.     void TESample::DoMenuCommand( short menuID, short menuItem )
  355.     {
  356.         short        itemHit;
  357.         Str255        daName;
  358.         short        daRefNum;
  359.         WindowPtr    window;
  360.         TEDocument* fTECurDoc = (TEDocument*) fCurDoc;
  361.     
  362.         window = FrontWindow();
  363.         switch ( menuID )
  364.         {
  365.             case mApple:    switch ( menuItem )
  366.                             {
  367.                                 case iAbout:    itemHit = Alert( rAboutAlert, nil );                    // bring up alert for About 
  368.                                                 break;
  369.                                     
  370.                                 default:        GetMenuItemText( GetMenuHandle(mApple), menuItem, daName );        // all non-About items in this menu are DAs et al 
  371.                                                 daRefNum = OpenDeskAcc( daName );
  372.                                                 break;
  373.                             }
  374.                             break;
  375.                             
  376.             case mFile:        switch ( menuItem )
  377.                             {
  378.                                 case iNew:        DoNew();
  379.                                                 break;
  380.                                                 
  381.                                 case iClose:    if (fTECurDoc != nil)
  382.                                                 {
  383.                                                     fDocList->RemoveDoc( fTECurDoc );
  384.                                                     fTECurDoc->DoClose();
  385.                                                 }
  386.                                                 else
  387.                                                     CloseDeskAcc(((WindowPeek) fWhichWindow)->windowKind );
  388.                                                     
  389.                                                 // make sure our current document/window references are valid
  390.                                                     fWhichWindow = FrontWindow();
  391.                                                     if ( fWhichWindow != nil )
  392.                                                     {
  393.                                                         fCurDoc = fDocList->FindDoc( fWhichWindow );
  394.                                                         SetPort( fWhichWindow );
  395.                                                     }
  396.                                                     else
  397.                                                         fCurDoc = nil;
  398.                                                 break;
  399.                                                 
  400.                                 case iQuit:        Terminate();
  401.                                                 break;
  402.                             }
  403.                             break;
  404.                             
  405.             case mEdit:        if ( !SystemEdit( menuItem-1 ))                            // call SystemEdit for DA editing & MultiFinder 
  406.                             {
  407.                                 switch ( menuItem )
  408.                                 {
  409.                                     case iCut:        fTECurDoc->DoCut();
  410.                                                     break;
  411.                                                 
  412.                                     case iCopy:        fTECurDoc->DoCopy();
  413.                                                     break;
  414.                                                 
  415.                                     case iPaste:    fTECurDoc->DoPaste();
  416.                                                     break;
  417.                                                     
  418.                                     case iClear:    fTECurDoc->DoClear();
  419.                                                     break;
  420.                                 }
  421.                             }
  422.                             break;
  423.             
  424.             case mDebug:    
  425.                             DebugStr ((ConstStr255Param) "\pEntering Debugger...");
  426.                             break;
  427.                             
  428.         }
  429.         HiliteMenu( 0 );    // unhighlight what MenuSelect (or MenuKey) hilited 
  430.         
  431.     } /* TESample::DoMenuCommand */
  432.  
  433.  
  434. //-----------------------------------------------------------------------
  435. // TESample::DoNew -    Create a new document and window. 
  436. //
  437.     void TESample::DoNew( void )
  438.     {
  439.         TEDocument* tDoc;
  440.     
  441.         tDoc = new TEDocument( rDocWindow );
  442.         
  443.         // if we didn't get an allocation error, add it to list
  444.             if ( tDoc != nil )
  445.                 fDocList->AddDoc( tDoc );
  446.             else
  447.                 AlertUser( kTEDocErrStrings, eNoWindow );
  448.             
  449.     } /* TESample::DoNew */
  450.  
  451.  
  452. //-----------------------------------------------------------------------
  453. // TESample::Terminate -    Clean up the application and exits. You might
  454. //                            want to close all of your documents (and ask
  455. //                            the user to save them) here.
  456. //
  457.     void TESample::Terminate( void )
  458.     {
  459.         ExitLoop();
  460.         
  461.     } /* TESample::Terminate */
  462.  
  463.