home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / UI / Undo.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  59.0 KB  |  2,151 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Undo.cpp
  3.  
  4.     Contains:    Implementation for Undo class
  5.  
  6.     Owned by:    Nick Pilch
  7.  
  8.     Copyright:    © 1994 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <7>     8/13/96    VL        1372870: Not dispose of memory in
  13.                                     UndoAction destructor if process has gone
  14.                                     away. Added
  15.                                     SystemUndo::ShouldStackBeCleared to check
  16.                                     to see whether the first action(s) is still
  17.                                     valid.
  18.          <6>     6/18/96    NP        1267014, 1358481, 1347976, 1292558, 1266989
  19.          <5>     5/24/96    jpa        1246074: SOM_CATCH --> SOM_TRY..SOM_ENDTRY
  20.          <4>    .04.1996    NP        1316777: Machine hangs for one minute while
  21.                                     dragging. 1328995: Mem leak. 1323304:
  22.                                     actionData passed to part has _length == 0
  23.          <3>    .04.1996    NP        1316777: Partiall fix race condition with
  24.                                     the disposal notification process.
  25.  
  26.     To Do:
  27.         Remove destructors where not needed.
  28.     In Progress:
  29.         
  30. */
  31.  
  32.  
  33. #ifndef _PART_
  34. #include "Part.xh"
  35. #endif
  36.  
  37. //#ifndef _ORDCOLL_
  38. //#include "OrdColl.h"
  39. //#endif
  40.  
  41. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  42. #include "StdDefs.xh"
  43. #endif
  44.  
  45. #ifndef _SEUTILS_
  46. #include "SEUtils.h"
  47. #endif
  48.  
  49. #ifndef _ODUTILS_
  50. #include "ODUtils.h"
  51. #endif
  52.  
  53. #ifndef _ITEXT_
  54. #include "IText.h"
  55. #endif
  56.  
  57. #define ODUndo_Class_Source
  58. #define VARIABLE_MACROS
  59. #include <Undo.xih>
  60.  
  61. #ifndef _EXCEPT_
  62. #include <Except.h>
  63. #endif
  64.  
  65. #ifndef _BARRAY_
  66. #include <BArray.h>
  67. #endif
  68.  
  69. //#ifndef _ODNEW_
  70. //#include <ODNew.h>
  71. //#endif
  72.  
  73. #ifndef _ODDEBUG_
  74. #include "ODDebug.h"
  75. #endif
  76.  
  77. //#ifndef _ODTYPES_
  78. //#include "ODTypes.h"
  79. //#endif
  80.  
  81. //#ifndef _PLFMDEF_
  82. //#include "PlfmDef.h"
  83. //#endif
  84.  
  85. //#ifndef _LIST_
  86. //#include "List.h"
  87. //#endif
  88.  
  89. #ifndef _ODMEMORY_
  90. #include "ODMemory.h"
  91. #endif
  92.  
  93. #ifndef __ERRORS__
  94. #include <Errors.h>
  95. #endif
  96.  
  97. #ifndef _ODDEBUG_
  98. #include "ODDebug.h"
  99. #endif
  100.  
  101. #ifndef _TEMPOBJ_
  102. #include <TempObj.h>
  103. #endif
  104.  
  105. #pragma segment ODUndo
  106.  
  107. /*
  108. IMPLEMENTATION NOTES
  109.  
  110. System Heap allocations
  111.  
  112. Almost all memory allocations occur in the system heap.
  113.  
  114. I'm trying to use as little system heap memory as possible because putting
  115. pointers into the system heap could be a bad idea (mem fragmentation).
  116.  
  117. UNDO AND REDO STACKS
  118.  
  119. The stacks are implemented with the UndoOrderedCollection class. The first item
  120. in the collection represents the top of the stack.
  121.  
  122. MARKING
  123.  
  124. When asked to mark a stack that is empty, nothing is done. The code that removes
  125. actions from a stack up to the last mark simply stops when it comes to the end
  126. of a stack.
  127.  
  128. ADDCLIENT, ETC.
  129.  
  130. We need to use these functions to ensure the SystemUndo is freed when
  131. the last OD document is closed. The memory associated with it will have gone
  132. away.
  133. */
  134.  
  135. //==============================================================================
  136. // Special new operator for the system heap that use NewPtrSys and
  137. //    DisposePtr.
  138. //==============================================================================
  139.  
  140. enum ODUndoMemoryAllocation
  141. {
  142.     kODSystemHeap
  143. };
  144.  
  145. void* operator new(size_t size, ODUndoMemoryAllocation allocation);
  146.  
  147. void* operator new(size_t size, ODUndoMemoryAllocation allocation)
  148. {
  149.     void*    retVal;
  150.  
  151.     if (allocation == kODSystemHeap)
  152.         retVal = NewPtrSys(size);
  153.     else
  154.         THROW(kODErrNotImplemented);
  155.     
  156.     return retVal;
  157. }
  158.  
  159. boolean IsValidProcess(ProcessSerialNumber* psn);
  160.  
  161. boolean IsValidProcess(ProcessSerialNumber* psn)
  162. {
  163.     ProcessInfoRec info;
  164.     info.processInfoLength = sizeof(ProcessInfoRec);
  165.     info.processName = nil;
  166.     info.processAppSpec = nil;
  167.         
  168.     return (GetProcessInformation(psn, &info) == noErr);
  169. }
  170.  
  171.  
  172. //==============================================================================
  173. // Temporarily include new UndoOrderedCollection class that I can allocate in the
  174. //    system heap. (May be longer than temporary.)
  175. //==============================================================================
  176.  
  177.  
  178.  
  179. /////////////// BEGIN TEMP HACK
  180.  
  181.  
  182.  
  183. //==============================================================================
  184. // UndoLink
  185. //==============================================================================
  186.  
  187. class  UndoLink {
  188.     public:
  189. //        void* operator new(size_t size) {return NewPtrSys(size);}
  190.         void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  191.         UndoLink();
  192.         
  193.         UndoLink(UndoLink* next, UndoLink* previous);
  194.         
  195.         UndoLink( const UndoLink& );
  196.         
  197.         ~UndoLink();
  198.         
  199.         UndoLink* GetNext() const                    {return fNext;}
  200.         
  201.         UndoLink* GetPrevious() const                {return fPrevious;}
  202.     
  203.     // The following operations are provided for efficiency, but DO NOT USE THEM
  204.     // if there are any iterators active on a list. These operations don't bump
  205.     // the list's fSeed and the iterators will not be able to detect that they
  206.     // are out of sync!
  207.         
  208.         void  Remove( );
  209.         
  210.         void  AddBefore( UndoLink *aLink );
  211.         
  212.         void  AddAfter( UndoLink *aLink );
  213.     
  214.   //private-by-convention:
  215.           
  216.         void  SetNext(UndoLink* aLink)                {fNext = aLink;}
  217.         
  218.         void  SetPrevious(UndoLink* aLink)            {fPrevious = aLink;}
  219.  
  220.     private:
  221.     
  222.         UndoLink*        fNext;
  223.         UndoLink*        fPrevious;
  224. };
  225.  
  226.  
  227. //==============================================================================
  228. // UndoLinkedList
  229. //==============================================================================
  230.  
  231.  
  232. class UndoLinkedList {
  233.  
  234.     public:
  235.         void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  236.           UndoLinkedList();
  237.           
  238.           ~UndoLinkedList();
  239.           
  240.           void            Remove(UndoLink&);
  241.           
  242.           void            AddFirst(UndoLink* link);
  243.           
  244.           UndoLink*            RemoveFirst();
  245.           
  246.           UndoLink*            First()                                            const;
  247.           
  248. protected:
  249.  
  250.         UndoLink            fSentinel;    // Marks the head & tail
  251.         ODULong            fSeed;        // Used to detect out-of-sync iterators
  252.         
  253.         UndoLink*            GetSentinel( )
  254.                                                 {return &fSentinel;}
  255.         const UndoLink*        GetSentinel( )                                    const
  256.                                                 {return &fSentinel;}
  257.         ODBoolean        IsSentinel( const UndoLink* link )                    const
  258.                                                 {return link==this->GetSentinel();}
  259.         ODBoolean        NotSentinel( const UndoLink* link )                    const
  260.                                                 {return link!=this->GetSentinel();}
  261.  
  262. private:                  
  263.         friend class UndoLinkedListIterator;
  264. };
  265.  
  266.  
  267. //=====================================================================================
  268. // UndoLinkedListIterator
  269. //=====================================================================================
  270.  
  271. class UndoLinkedListIterator {
  272.  
  273.     public:
  274.     
  275.         UndoLinkedListIterator(UndoLinkedList*    list);
  276.         
  277.         ~UndoLinkedListIterator();
  278.         
  279.         UndoLink*            First();
  280.         
  281.         UndoLink*            Next();
  282.  
  283.         ODBoolean         IsNotComplete();
  284.         
  285.     private:
  286.     
  287.         UndoLinkedList*        fList;
  288.         UndoLink*            fCurrent;
  289.         UndoLink*            fNext;        // Used only when deleting while iterating
  290.         UndoLink*             fPrevious;    // Used only when deleting while iterating
  291.         UndoLink*            fSentinel;
  292.         ODULong            fSeed;        // Used to detect out-of-sync iterators
  293.         
  294. };
  295.  
  296. //==============================================================================
  297. // Scalar Types
  298. //==============================================================================
  299.  
  300. typedef void* ElementType;
  301.  
  302. //=====================================================================================
  303. // Class UndoValueLink - Definition
  304. //=====================================================================================
  305.  
  306. class UndoValueLink : public UndoLink {
  307.     
  308. public:
  309.                             UndoValueLink(ElementType value);        
  310.                     ~UndoValueLink();
  311.         ElementType    GetValue()                        { return fValue;}
  312.      void        SetValue(ElementType v)            { fValue = v;}
  313.  
  314. private:
  315.     ElementType         fValue;
  316. };
  317.  
  318. //=====================================================================================
  319. // Class UndoOrderedCollection
  320. //=====================================================================================
  321.  
  322. class UndoOrderedCollection
  323. {
  324.     
  325. public:
  326.     void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  327.     UndoOrderedCollection();
  328.     UndoOrderedCollection(ODUndoMemoryAllocation where);
  329.     ~UndoOrderedCollection();
  330.  
  331.      void    AddFirst(ElementType element);
  332.      ElementType    First();
  333.         // Returns kODNULL if there is no first element.
  334.      ElementType    RemoveFirst();
  335.         // Don't call if there are no elements. Crash will result.
  336.      void    Remove(ElementType existing);
  337.      void    RemoveAll();
  338.     
  339.         // Called from the destructor. Removes all elements, deleting the links
  340.         // Does not delete the elements themselves
  341.  
  342. protected:
  343.       UndoValueLink*     CreateNewLink(ElementType value) const;
  344.       ODBoolean    ElementsMatch(ElementType v1,ElementType v2) const;
  345.          // Does a pointer comparison by default 
  346.  
  347. private:
  348.     UndoLinkedList        fImplementation;
  349.     ODUndoMemoryAllocation    fHeap; // if kODNULL, use default heap.
  350.  
  351.     friend class UndoOrderedCollectionIterator;
  352.     friend class ListIterator;
  353. };
  354.  
  355. //=====================================================================================
  356. // Class UndoOrderedCollectionIterator
  357. //=====================================================================================
  358.  
  359. class UndoOrderedCollectionIterator {
  360. public:
  361.     UndoOrderedCollectionIterator(UndoOrderedCollection* collection);
  362.     ~UndoOrderedCollectionIterator();
  363.     ElementType    First();
  364.     ElementType    Next();
  365.     ODBoolean    IsNotComplete();
  366.     
  367. private:
  368.       UndoOrderedCollection*    fCollection;
  369.     UndoLinkedListIterator    fImplementation;
  370. };
  371.  
  372. //==============================================================================
  373. // UndoLink
  374. //==============================================================================
  375.  
  376.  
  377.  
  378. // Many of the simple link methods are inlines; see List.h for implementations.
  379.  
  380.  
  381. //------------------------------------------------------------------------------
  382. // UndoLink::UndoLink
  383. //
  384. // Constructor for UndoLink
  385. //------------------------------------------------------------------------------
  386.  
  387. UndoLink::UndoLink()                            
  388.     fNext = kODNULL; 
  389.     fPrevious = kODNULL;
  390. }
  391.  
  392. //------------------------------------------------------------------------------
  393. // UndoLink::UndoLink
  394. //
  395. // Constructor for UndoLink
  396. //------------------------------------------------------------------------------
  397.  
  398. UndoLink::UndoLink(UndoLink* next, UndoLink* previous)                            
  399.     fNext = next; 
  400.     fPrevious = previous;
  401. }
  402.  
  403. //------------------------------------------------------------------------------
  404. // UndoLink::UndoLink
  405. //
  406. // Copy constructor for UndoLink
  407. //------------------------------------------------------------------------------
  408.  
  409. UndoLink::UndoLink( const UndoLink &link )                            
  410.     fNext = link.fNext; 
  411.     fPrevious = link.fPrevious;
  412. }
  413.  
  414. //------------------------------------------------------------------------------
  415. // UndoLink::UndoLink
  416. //
  417. // Destructor for UndoLink
  418. //------------------------------------------------------------------------------
  419.  
  420. UndoLink::~UndoLink()                                            
  421. {
  422. }
  423.  
  424. //------------------------------------------------------------------------------
  425. // UndoLink::Remove
  426. //
  427. // Remove a link from its list (if any). DO NOT call this directly if there are
  428. // any iterators active on the list; use UndoLinkedList::Remove instead.
  429. //------------------------------------------------------------------------------
  430.  
  431. void    UndoLink::Remove( )
  432. {
  433.     if( fPrevious )
  434.         fPrevious->SetNext(fNext);
  435.     if( fNext )
  436.         fNext->SetPrevious(fPrevious);
  437.     fNext = kODNULL;
  438.     fPrevious = kODNULL;
  439. }
  440.  
  441. //------------------------------------------------------------------------------
  442. // UndoLink::AddBefore
  443. //
  444. // Add a link to a list before another link. It must not already be on any list.
  445. // DO NOT call this directly if there are any iterators active on the list;
  446. // use UndoLinkedList::Remove instead.
  447. //------------------------------------------------------------------------------
  448.  
  449. void    UndoLink::AddBefore( UndoLink *link )
  450. {
  451.     ASSERT(link!=kODNULL,paramErr);
  452.     WASSERT(fNext==kODNULL);
  453.     WASSERT(fPrevious==kODNULL);
  454.     fNext = link;
  455.     fPrevious = link->GetPrevious();
  456.     fPrevious->SetNext(this);
  457.     fNext->SetPrevious(this);
  458. }
  459.  
  460. //------------------------------------------------------------------------------
  461. // UndoLink::AddAfter
  462. //
  463. // Add a link to a list after another link. It must not already be on any list.
  464. // DO NOT call this directly if there are any iterators active on the list;
  465. // use UndoLinkedList::Remove instead.
  466. //------------------------------------------------------------------------------
  467.  
  468. void    UndoLink::AddAfter( UndoLink *link )
  469. {
  470.     ASSERT(link!=kODNULL,paramErr);
  471.     WASSERT(fNext==kODNULL);
  472.     WASSERT(fPrevious==kODNULL);
  473.     fPrevious = link;
  474.     fNext = link->GetNext();
  475.     fPrevious->SetNext(this);
  476.     fNext->SetPrevious(this);
  477. }
  478.  
  479. //======================================================================================
  480. // Class UndoLinkedList
  481. //======================================================================================
  482.  
  483. //------------------------------------------------------------------------------
  484. // UndoLinkedList::UndoLinkedList
  485. //
  486. // Constructor for UndoLinkedList
  487. //------------------------------------------------------------------------------
  488.  
  489. UndoLinkedList::UndoLinkedList()
  490.     :fSentinel(&fSentinel,&fSentinel),
  491.      fSeed(0)
  492. {
  493. }
  494.  
  495. //------------------------------------------------------------------------------
  496. // UndoLinkedList::~UndoLinkedList
  497. //
  498. // Destructor for UndoLinkedList
  499. //------------------------------------------------------------------------------
  500.  
  501. UndoLinkedList::~UndoLinkedList()
  502. {
  503.     // The list does NOT delete all its links!
  504. }
  505.  
  506. //------------------------------------------------------------------------------
  507. // UndoLinkedList::Remove
  508. //
  509. // Description
  510. //------------------------------------------------------------------------------
  511.  
  512. void    UndoLinkedList::Remove(UndoLink& aLink)
  513. {
  514.     fSeed++;
  515.     aLink.Remove();
  516. }
  517.  
  518. //------------------------------------------------------------------------------
  519. // UndoLinkedList::RemoveFirst
  520. //
  521. // Description
  522. //------------------------------------------------------------------------------
  523.  
  524. UndoLink* UndoLinkedList::RemoveFirst()
  525. {
  526.     UndoLink* old = fSentinel.GetNext();
  527.     if (this->NotSentinel(old))
  528.     {
  529.         fSeed++;
  530.         old->Remove();
  531.         return old;
  532.     }
  533.     else
  534.     {
  535.         return kODNULL;
  536.     }
  537. }
  538.  
  539. //------------------------------------------------------------------------------
  540. // UndoLinkedList::AddFirst
  541. //
  542. // Description
  543. //------------------------------------------------------------------------------
  544.  
  545. void    UndoLinkedList::AddFirst(UndoLink* link)
  546. {
  547.     link->AddAfter(this->GetSentinel());
  548.     fSeed++;
  549. }
  550.  
  551. //------------------------------------------------------------------------------
  552. // UndoLinkedList::First
  553. //
  554. // Description
  555. //------------------------------------------------------------------------------
  556.  
  557. UndoLink*    UndoLinkedList::First()  const
  558. {
  559.     return this->NotSentinel(fSentinel.GetNext()) ? fSentinel.GetNext() : (UndoLink*) kODNULL;
  560. }
  561.  
  562. //======================================================================================
  563. // Class UndoLinkedListIterator
  564. //======================================================================================
  565.  
  566. //------------------------------------------------------------------------------
  567. // UndoLinkedListIterator::UndoLinkedListIterator
  568. //
  569. // Constructor for UndoLinkedListIterator
  570. //------------------------------------------------------------------------------
  571.  
  572. UndoLinkedListIterator::UndoLinkedListIterator(UndoLinkedList* list)
  573. {
  574.     fList = list;
  575.     fCurrent = kODNULL;
  576.     fNext = kODNULL;
  577.     fPrevious = kODNULL;
  578.     fSentinel = &list->fSentinel;
  579.     fSeed = fList->fSeed;    
  580. }
  581.  
  582. //------------------------------------------------------------------------------
  583. // UndoLinkedListIterator::~UndoLinkedListIterator
  584. //
  585. // Destructor for UndoLinkedListIterator
  586. //------------------------------------------------------------------------------
  587.  
  588. UndoLinkedListIterator::~UndoLinkedListIterator()
  589. {
  590. }
  591.  
  592. //------------------------------------------------------------------------------
  593. // UndoLinkedListIterator::First
  594. //
  595. // Description
  596. //------------------------------------------------------------------------------
  597.  
  598. UndoLink* UndoLinkedListIterator::First()
  599. {
  600.     if (fList == kODNULL)
  601.         return kODNULL;
  602.         
  603.     if (fSeed != fList->fSeed)
  604.         THROW(kODErrIteratorOutOfSync);
  605.         
  606.     fCurrent = fList->First();
  607.     if (fCurrent == fSentinel)
  608.         fCurrent = kODNULL;
  609.     return fCurrent;
  610. }
  611.  
  612. //------------------------------------------------------------------------------
  613. // UndoLinkedListIterator::Next
  614. //
  615. // Description
  616. //------------------------------------------------------------------------------
  617.  
  618. UndoLink* UndoLinkedListIterator::Next()
  619. {
  620.     if (fList == kODNULL)
  621.         return kODNULL;
  622.  
  623.     if (fSeed != fList->fSeed)
  624.         THROW(kODErrIteratorOutOfSync);
  625.  
  626.     if (fCurrent == kODNULL)
  627.     {
  628.         if ((fNext == kODNULL) && (fPrevious == kODNULL))    // Just starting out
  629.         {
  630.             return this->First();
  631.         }
  632.         else    // Just deleted
  633.         {
  634.             fCurrent = fNext;
  635.             fPrevious = kODNULL;
  636.             fNext = kODNULL;
  637.         }
  638.     }
  639.     else
  640.         fCurrent = fCurrent->GetNext();
  641.     
  642.     if (fCurrent == fSentinel)
  643.         fCurrent = kODNULL;
  644.     return fCurrent;
  645. }
  646.  
  647. //------------------------------------------------------------------------------
  648. // UndoLinkedListIterator::IsNotComplete
  649. //
  650. // Description
  651. //------------------------------------------------------------------------------
  652.  
  653. ODBoolean UndoLinkedListIterator::IsNotComplete()
  654. {
  655.     return (fCurrent != kODNULL);
  656. }
  657.  
  658. //======================================================================================
  659. // Class UndoValueLink - Implementation
  660. //======================================================================================
  661.  
  662. UndoValueLink::UndoValueLink(ElementType value)
  663. {
  664.     fValue = value;
  665. }
  666.  
  667. UndoValueLink::~UndoValueLink()
  668. {
  669. }
  670.  
  671. //======================================================================================
  672. // Class UndoOrderedCollection
  673. //======================================================================================
  674.  
  675. //------------------------------------------------------------------------------
  676. // UndoOrderedCollection::UndoOrderedCollection
  677. //------------------------------------------------------------------------------
  678.  
  679. UndoOrderedCollection::UndoOrderedCollection()
  680. {
  681.     fHeap = kODSystemHeap;
  682. }
  683.  
  684. //------------------------------------------------------------------------------
  685. // UndoOrderedCollection::UndoOrderedCollection
  686. //------------------------------------------------------------------------------
  687.  
  688. UndoOrderedCollection::UndoOrderedCollection(ODUndoMemoryAllocation where)
  689. {
  690.     fHeap = where;
  691. }
  692.  
  693. // UndoOrderedCollection::~UndoOrderedCollection
  694. //------------------------------------------------------------------------------
  695.  
  696. UndoOrderedCollection::~UndoOrderedCollection()
  697. {
  698.     this->RemoveAll();
  699. }
  700.  
  701. //------------------------------------------------------------------------------
  702. // UndoOrderedCollection::AddFirst
  703. //------------------------------------------------------------------------------
  704.  
  705. void UndoOrderedCollection::AddFirst(ElementType element)
  706. {
  707.     UndoValueLink* newLink = this->CreateNewLink(element);
  708.     fImplementation.AddFirst(newLink);
  709. }
  710.  
  711. //------------------------------------------------------------------------------
  712. // UndoOrderedCollection::First
  713. //------------------------------------------------------------------------------
  714.  
  715. ElementType UndoOrderedCollection::First()
  716. {
  717.     UndoValueLink* firstLink = (UndoValueLink*) fImplementation.First();
  718.     return firstLink ? firstLink->GetValue() : (ElementType)kODNULL;
  719. }
  720.  
  721. //------------------------------------------------------------------------------
  722. // UndoOrderedCollection::RemoveFirst
  723. //------------------------------------------------------------------------------
  724.  
  725. ElementType    UndoOrderedCollection::RemoveFirst()
  726. {
  727.     UndoValueLink* aLink = (UndoValueLink*) fImplementation.RemoveFirst();
  728.     ElementType value = aLink ? aLink->GetValue() : kODNULL;
  729.     delete aLink;
  730.     return value;
  731. }
  732.  
  733. //------------------------------------------------------------------------------
  734. // UndoOrderedCollection::Remove
  735. //------------------------------------------------------------------------------
  736.  
  737. void UndoOrderedCollection::Remove(ElementType existing)
  738. {
  739.     UndoLinkedListIterator iter(&fImplementation);
  740.     UndoValueLink* aLink = (UndoValueLink*) iter.First();
  741.     while (aLink != kODNULL)
  742.     {
  743.         ElementType v = ((UndoValueLink*) aLink)->GetValue();
  744.  
  745.         if (this->ElementsMatch(v,existing))
  746.         {
  747.             fImplementation.Remove(*aLink);
  748.             delete aLink;
  749.             aLink = kODNULL;    
  750.         }
  751.         else
  752.             aLink = (UndoValueLink*) iter.Next();
  753.     }    
  754. }
  755.  
  756. //------------------------------------------------------------------------------
  757. // UndoOrderedCollection::RemoveAll
  758. //------------------------------------------------------------------------------
  759.  
  760. void UndoOrderedCollection::RemoveAll()
  761. {
  762.     UndoLink* link = fImplementation.RemoveFirst();
  763.     while (link != kODNULL)
  764.     {
  765.         delete link;
  766.         link = fImplementation.RemoveFirst();
  767.     }
  768. }
  769.  
  770. //------------------------------------------------------------------------------
  771. // UndoOrderedCollection::CreateNewLink
  772. //------------------------------------------------------------------------------
  773.  
  774. UndoValueLink*    UndoOrderedCollection::CreateNewLink(ElementType value) const
  775. {
  776.     return new (fHeap) UndoValueLink(value);
  777. }
  778.  
  779. //------------------------------------------------------------------------------
  780. // UndoOrderedCollection::ElementsMatch
  781. //------------------------------------------------------------------------------
  782.  
  783. ODBoolean    UndoOrderedCollection::ElementsMatch(ElementType v1,ElementType v2) const
  784. {
  785.     return (v1 == v2);
  786. }
  787.  
  788. //======================================================================================
  789. // UndoOrderedCollectionIterator
  790. //======================================================================================
  791.  
  792. //------------------------------------------------------------------------------
  793. // UndoOrderedCollectionIterator::UndoOrderedCollectionIterator
  794. //------------------------------------------------------------------------------
  795.  
  796. UndoOrderedCollectionIterator::UndoOrderedCollectionIterator(UndoOrderedCollection* collection)    
  797.     : fImplementation(collection ? &(collection->fImplementation) : (UndoLinkedList*)kODNULL)
  798. {
  799.     fCollection =  collection;
  800. }
  801.  
  802. //------------------------------------------------------------------------------
  803. // UndoOrderedCollectionIterator::~UndoOrderedCollectionIterator
  804. //------------------------------------------------------------------------------
  805.  
  806. UndoOrderedCollectionIterator::~UndoOrderedCollectionIterator()                        
  807. {
  808. }
  809.  
  810. //------------------------------------------------------------------------------
  811. // UndoOrderedCollectionIterator::First
  812. //------------------------------------------------------------------------------
  813.  
  814. ElementType    UndoOrderedCollectionIterator::First()
  815. {
  816.     UndoValueLink* link = (UndoValueLink*) fImplementation.First();
  817.     
  818.     return link ? link->GetValue() : (ElementType)kODNULL;
  819. }
  820.  
  821. //------------------------------------------------------------------------------
  822. // UndoOrderedCollectionIterator::Next
  823. //------------------------------------------------------------------------------
  824.  
  825. ElementType    UndoOrderedCollectionIterator::Next()
  826. {        
  827.     UndoValueLink* link = (UndoValueLink*) fImplementation.Next();
  828.     
  829.     return link ? link->GetValue() : (ElementType)kODNULL;
  830. }
  831.  
  832. //------------------------------------------------------------------------------
  833. // UndoOrderedCollectionIterator::IsNotComplete
  834. //------------------------------------------------------------------------------
  835.  
  836. ODBoolean    UndoOrderedCollectionIterator::IsNotComplete()
  837. {
  838.     return fImplementation.IsNotComplete();
  839. }
  840.  
  841.  
  842.  
  843. /////////////// END TEMP HACK
  844.  
  845.  
  846.  
  847. //==============================================================================
  848. // Constants
  849. //==============================================================================
  850.  
  851. const OSType kUndoNotifyID = 'undo';
  852. const OSType kRedoNotifyID = 'redo';
  853. const OSType kDisposeActionNotifyID = 'del ';
  854.  
  855. const AEKeyword kDataPtrKeyword = 'data';
  856. const AEKeyword kPartPtrKeyword = 'part';
  857. const AEKeyword kDoneStateKeyword = 'done';
  858.  
  859. // A number of functions can share code. They pass along this enum to know
  860. //    which course of action to take.
  861. enum ODUndoRedoType
  862. {
  863.     kUndo,
  864.     kRedo,
  865.     kDispose
  866. };
  867.  
  868. //==============================================================================
  869. // Classes used in this file
  870. //==============================================================================
  871.  
  872. class UndoAction;
  873. class SystemUndo;
  874.  
  875. //==============================================================================
  876. // Function Prototypes
  877. //==============================================================================
  878.  
  879. const ODBoolean kODBringToFront = kODTrue;
  880.  
  881. static OSErr NotifyUndoOrRedoOrDispose(UndoAction* action,
  882.                                                 ODUndoRedoType which,
  883.                                                 ODBoolean bringToFront);
  884. static OSErr NotifyUndo(UndoAction* action, ODBoolean bringToFront);
  885. static OSErr NotifyRedo(UndoAction* action, ODBoolean bringToFront);
  886. static OSErr NotifyDispose(UndoAction* action);
  887. static SystemUndo *GetSystemUndo();
  888. static ODBoolean SetSystemUndo(SystemUndo *systemUndo);
  889.  
  890. //==============================================================================
  891. // Functions
  892. //==============================================================================
  893.  
  894. // • Using ASLM we registered the system undo object with ASLM using the
  895. // arbitration mechanism provided by ASLM. To eliminate our dependency on ASLM
  896. // we are storing the system undo object in a global which is accessed by the
  897. // following two functions. This is NOT a thread safe method for accessing the
  898. // system undo!
  899.  
  900. //------------------------------------------------------------------------------
  901. // GetSystemUndo
  902. //------------------------------------------------------------------------------
  903.  
  904. #pragma lib_export on
  905. extern SystemUndo* gSystemUndo;        
  906. #pragma lib_export off
  907.  
  908. static SystemUndo *GetSystemUndo()
  909. {
  910.     return gSystemUndo;
  911. }
  912.  
  913. //------------------------------------------------------------------------------
  914. // SetSystemUndo
  915. //------------------------------------------------------------------------------
  916.  
  917. static ODBoolean SetSystemUndo(SystemUndo *systemUndo)
  918. {
  919.     gSystemUndo = systemUndo;
  920.     return kODTrue;
  921. }
  922.  
  923. //#pragma lib_export off
  924.  
  925. //==============================================================================
  926. // Local Classes
  927. //==============================================================================
  928.  
  929. //------------------------------------------------------------------------------
  930.  
  931. class UndoAction
  932. {
  933.   public:
  934.         void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  935.     UndoAction(ODPart* whichPart, ODActionData* actionData,
  936.                     ODActionType actionType, ODName* undoActionLabel,
  937.                     ODName* redoActionLabel);
  938.     ~UndoAction();
  939.  
  940.     ODPart*                fPart;
  941.     ProcessSerialNumber    fProcessNum;
  942.     ODActionData*        fActionData;
  943.     ODActionType        fActionType;
  944.     ODName*                fUndoActionLabel;
  945.     ODName*                fRedoActionLabel;
  946.     ODBoolean            fMark;
  947.     ODDoneState            fDoneState;
  948. };
  949.  
  950. //------------------------------------------------------------------------------
  951. // UndoAction::UndoAction
  952. //
  953. //    This constructor may throw an error, but it's OK because there is nothing
  954. //    to deallocate in the destructor.
  955. //------------------------------------------------------------------------------
  956.  
  957. UndoAction::UndoAction(ODPart* whichPart, 
  958.                                     ODActionData* actionData,
  959.                                     ODActionType actionType,
  960.                                     ODName* undoActionLabel,
  961.                                     ODName* redoActionLabel)
  962. {
  963.     fPart = whichPart;
  964.     THROW_IF_ERROR(GetCurrentProcess(&fProcessNum));
  965.     fActionData = actionData;
  966.     fActionType = actionType;
  967.     fUndoActionLabel = undoActionLabel;
  968.     fRedoActionLabel = redoActionLabel;
  969.     fMark = kODFalse;
  970.     fDoneState = kODDone;
  971. }
  972.  
  973. //------------------------------------------------------------------------------
  974. // UndoAction::~UndoAction
  975. //
  976. //    Notify owning part owning fActionData to dipose of any associated memory.
  977. //------------------------------------------------------------------------------
  978.  
  979. UndoAction::~UndoAction()
  980. {
  981.     // Note that we may leak memory if NotifyDispose returns anything other than
  982.     // noErr. However, it is possible that the process allocating the memory for 
  983.     // the undo action no longer exists. That's why we are trying to avoid allocation.
  984.  
  985.     if (NotifyDispose(this) != procNotFound)
  986.     {
  987.         TRY
  988.             if (fUndoActionLabel)
  989.                 DisposeIText(fUndoActionLabel);
  990.             if (fRedoActionLabel)
  991.                 DisposeIText(fRedoActionLabel);
  992.             if (fActionData)
  993.                 DisposeByteArray(fActionData);
  994.         CATCH_ALL
  995.             WARN("Error %ld encountered deleting an undo action.", ErrorCode());
  996.         ENDTRY
  997.     }
  998. }
  999.  
  1000. //------------------------------------------------------------------------------
  1001.  
  1002. class SystemUndo
  1003. {
  1004.   public:
  1005.         void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
  1006.     SystemUndo();
  1007.     ~SystemUndo();
  1008.     void    Initialize();
  1009.  
  1010.     ODSize        Purge(ODSize size);
  1011.     ODBoolean    CheckActionOK(UndoAction* action);
  1012.     void        AddActionToHistory(ODPart* whichPart, 
  1013.                                     ODActionData* actionData,
  1014.                                     ODActionType actionType,
  1015.                                     ODName* undoActionLabel,
  1016.                                     ODName* redoActionLabel);
  1017.     void    Undo();
  1018.     void    Redo();
  1019.     void    MarkActionHistory();
  1020.     void    ClearActionHistory(ODRespectMarksChoices respectMarks);
  1021.     void    ClearRedoHistory();
  1022.     ODBoolean    PeekUndoHistory(ODPart** part,
  1023.                                 ODActionData* actionData,
  1024.                                 ODActionType* actionType,
  1025.                                 ODName* actionLabel);
  1026.     ODBoolean    PeekRedoHistory(ODPart** part,
  1027.                                 ODActionData* actionData,
  1028.                                 ODActionType* actionType,
  1029.                                 ODName* actionLabel);
  1030.     void        RemoveEntriesForThisProcess();
  1031.     void        AddClient(ODUndo* docUndoObject);
  1032.     void        RemoveClient(ODUndo* docUndoObject);
  1033.     ODULong        GetNumClients();
  1034.     void        AbortCurrentTransaction();
  1035.   private:
  1036.     void        TransactionUndo(UndoAction* firstAction);
  1037.     void        TransactionRedo(UndoAction* firstAction);
  1038.     void        MarkActionOrSelf(UndoAction* action, ODBoolean* mark);
  1039.     void        ClearActionsToMark(UndoOrderedCollection* stack);
  1040.     void        ClearStack(UndoOrderedCollection* stack);
  1041.     ODBoolean    PeekHistory(ODPart** part,
  1042.                                 ODActionData* actionData,
  1043.                                 ODActionType* actionType,
  1044.                                 ODName* actionLabel,
  1045.                                 ODUndoRedoType which);
  1046.     void        MoveUndoToRedo();
  1047.     void        MoveRedoToUndo();
  1048.     ODBoolean     ShouldStackBeCleared(UndoOrderedCollection* stack);
  1049.     
  1050.     UndoOrderedCollection*        fUndoStack;
  1051.     UndoOrderedCollection*        fRedoStack;
  1052.     ODULong                        fInTransaction;
  1053.     ODBoolean                fCurrentlyUndoingOrRedoing;
  1054.     ODULong                fNumUsers;
  1055. };
  1056.  
  1057. //------------------------------------------------------------------------------
  1058. // SystemUndo::SystemUndo
  1059. //------------------------------------------------------------------------------
  1060.  
  1061. SystemUndo::SystemUndo()
  1062. {
  1063.     fUndoStack = kODNULL;
  1064.     fRedoStack = kODNULL;
  1065.     fInTransaction = 0;
  1066.     fCurrentlyUndoingOrRedoing = kODFalse;
  1067.     fNumUsers = 0;
  1068. }
  1069.  
  1070. //------------------------------------------------------------------------------
  1071. // SystemUndo::Initialize                
  1072. //------------------------------------------------------------------------------
  1073.  
  1074. void SystemUndo::Initialize ()
  1075. {
  1076.     ODUndoMemoryAllocation    heap = kODSystemHeap;
  1077.  
  1078.     fUndoStack = new (heap) UndoOrderedCollection(heap);
  1079.     fRedoStack = new (heap) UndoOrderedCollection(heap);
  1080.  
  1081. }
  1082.  
  1083. //------------------------------------------------------------------------------
  1084. // SystemUndo::~SystemUndo
  1085. //------------------------------------------------------------------------------
  1086.  
  1087. SystemUndo::~SystemUndo()
  1088. {
  1089. //    WASSERTM(0, "System Undo object being destroyed!");
  1090.     delete fUndoStack;
  1091.     delete fRedoStack;
  1092. }
  1093.  
  1094. //------------------------------------------------------------------------------
  1095. // SystemUndo::Purge
  1096. //------------------------------------------------------------------------------
  1097.         
  1098. ODSize    SystemUndo::Purge(ODSize size)
  1099. {
  1100.     ODUnused(size);
  1101.     return 0;
  1102. }
  1103.  
  1104. //------------------------------------------------------------------------------
  1105. // SystemUndo::CheckActionOK
  1106. //------------------------------------------------------------------------------
  1107.         
  1108. ODBoolean SystemUndo::CheckActionOK(UndoAction* action)
  1109. {
  1110.     if (action && !(action->fMark))
  1111.         return kODTrue;
  1112.     return kODFalse;
  1113. }
  1114.  
  1115. //------------------------------------------------------------------------------
  1116. // SystemUndo::AddClient
  1117. //------------------------------------------------------------------------------
  1118.         
  1119. void SystemUndo::AddClient(ODUndo* docUndoObject)
  1120. {
  1121.     ODUnused(docUndoObject);
  1122.     ++fNumUsers;
  1123. }
  1124.  
  1125. //------------------------------------------------------------------------------
  1126. // SystemUndo::RemoveClient
  1127. //------------------------------------------------------------------------------
  1128.         
  1129. void SystemUndo::RemoveClient(ODUndo* docUndoObject)
  1130. {
  1131.     ODUnused(docUndoObject);
  1132.     --fNumUsers;
  1133. }
  1134.  
  1135. //------------------------------------------------------------------------------
  1136. // SystemUndo::GetNumClients
  1137. //------------------------------------------------------------------------------
  1138.         
  1139. ODULong SystemUndo::GetNumClients()
  1140. {
  1141.     return fNumUsers;
  1142. }
  1143.  
  1144. //------------------------------------------------------------------------------
  1145. // SystemUndo::AddActionToHistory
  1146. //------------------------------------------------------------------------------
  1147.  
  1148. void SystemUndo::AddActionToHistory(ODPart* whichPart, 
  1149.                                     ODActionData* actionData,
  1150.                                     ODActionType actionType,
  1151.                                     ODName* undoActionLabel,
  1152.                                     ODName* redoActionLabel)
  1153. {
  1154.     if (fCurrentlyUndoingOrRedoing)
  1155.         THROW(kODErrCannotAddAction);
  1156.  
  1157. //    if (fInTransaction && actionType == kODBeginAction)
  1158. //        THROW(kODErrCannotAddAction);
  1159.  
  1160.     if (actionType == kODBeginAction)
  1161.         ++fInTransaction;
  1162.     if (actionType == kODEndAction)
  1163.         --fInTransaction;
  1164.  
  1165.     // NOT DOING THESE ALLOCATIONS IN THE SYSTEM HEAP!
  1166. //    if (undoActionLabel)
  1167.         ODIText* undoName = CopyIText(undoActionLabel);
  1168. //    if (redoActionLabel)
  1169.         ODIText* redoName = CopyIText(redoActionLabel);
  1170.  
  1171. //    if (actionData)
  1172.         ODActionData* copiedData = CopyByteArray(actionData);
  1173.  
  1174.     UndoAction* action =
  1175.                     new (kODSystemHeap) UndoAction(whichPart, copiedData,
  1176.                                                     actionType, undoName,
  1177.                                                     redoName);
  1178.     fUndoStack->AddFirst(action);
  1179.     this->ClearStack(fRedoStack);
  1180. }
  1181.  
  1182. //------------------------------------------------------------------------------
  1183. // SystemUndo::MoveUndoToRedo
  1184. //
  1185. //    Utility to move item from top of one stack to the top of another.
  1186. //------------------------------------------------------------------------------
  1187.  
  1188. void SystemUndo::MoveUndoToRedo()
  1189. {
  1190.     ElementType item = fUndoStack->RemoveFirst();
  1191.     ((UndoAction*)item)->fDoneState = kODUndone;
  1192.     fRedoStack->AddFirst(item);
  1193. }
  1194.  
  1195. //------------------------------------------------------------------------------
  1196. // SystemUndo::MoveRedoToUndo
  1197. //
  1198. //    Utility to move item from top of one stack to the top of another.
  1199. //------------------------------------------------------------------------------
  1200.  
  1201. void SystemUndo::MoveRedoToUndo()
  1202. {
  1203.     ElementType item = fRedoStack->RemoveFirst();
  1204.     ((UndoAction*)item)->fDoneState = kODRedone;
  1205.     fUndoStack->AddFirst(item);
  1206. }
  1207.  
  1208. //------------------------------------------------------------------------------
  1209. // SystemUndo::Undo
  1210. //
  1211. //    If there's an error while undoing anything, just clear the stacks and get
  1212. //    out.
  1213. //------------------------------------------------------------------------------
  1214.  
  1215. void SystemUndo::Undo()
  1216. {
  1217.     UndoAction* action = (UndoAction*)fUndoStack->First();
  1218.     if (!this->CheckActionOK(action))
  1219.         THROW(kODErrEmptyStack);
  1220.  
  1221.     fCurrentlyUndoingOrRedoing = kODTrue;
  1222.  
  1223.     TRY
  1224.         if (action->fActionType == kODEndAction) // End is at top for an Undo
  1225.             this->TransactionUndo(action);
  1226.         else
  1227.         {
  1228.             THROW_IF_ERROR(NotifyUndo(action, kODBringToFront));
  1229.             this->MoveUndoToRedo();
  1230.         }
  1231.     CATCH_ALL
  1232.         this->ClearActionHistory(kODDontRespectMarks);
  1233.         fCurrentlyUndoingOrRedoing = kODFalse;
  1234.         RERAISE;
  1235.     ENDTRY
  1236.     fCurrentlyUndoingOrRedoing = kODFalse;
  1237. }
  1238.  
  1239. //------------------------------------------------------------------------------
  1240. // SystemUndo::ShouldStackBeCleared
  1241. //------------------------------------------------------------------------------
  1242.  
  1243. ODBoolean SystemUndo::ShouldStackBeCleared(UndoOrderedCollection* stack)
  1244. {    
  1245.     UndoOrderedCollectionIterator iter(stack);
  1246.     UndoAction* action = (UndoAction*) iter.First();
  1247.     ODULong        nestedTransactionCounter = 0;
  1248.     
  1249.     if (action)
  1250.     {
  1251.         do
  1252.         {
  1253.             if (IsValidProcess(&action->fProcessNum))
  1254.             {
  1255.                 if (action->fActionType == kODBeginAction)
  1256.                     --nestedTransactionCounter;
  1257.                 else if (action->fActionType == kODEndAction)
  1258.                     ++nestedTransactionCounter;
  1259.             }
  1260.             else            
  1261.                 return kODTrue;
  1262.             action = (UndoAction*)iter.Next();
  1263.         }
  1264.         while ((nestedTransactionCounter) && action);
  1265.     }
  1266.     
  1267.     if (nestedTransactionCounter)
  1268.         return kODTrue;
  1269.         
  1270.     return kODFalse;
  1271. }
  1272.  
  1273. //------------------------------------------------------------------------------
  1274. // SystemUndo::TransactionUndo
  1275. //------------------------------------------------------------------------------
  1276.  
  1277. void SystemUndo::TransactionUndo(UndoAction* firstAction)
  1278. {
  1279.     UndoAction*    action;
  1280.     ODULong        nestedTransactionCounter = 1;
  1281.  
  1282.     THROW_IF_ERROR(NotifyUndo(firstAction, ! kODBringToFront));
  1283.     this->MoveUndoToRedo();
  1284.  
  1285.     do
  1286.     {
  1287.         action = (UndoAction*)fUndoStack->First();
  1288.         if (action == (UndoAction*)kODNULL)
  1289.             THROW(kODErrNoBeginAction);
  1290.         THROW_IF_ERROR(NotifyUndo(action, ! kODBringToFront));
  1291.         this->MoveUndoToRedo();
  1292.         if (action->fActionType == kODBeginAction)
  1293.             --nestedTransactionCounter;
  1294.         else if (action->fActionType == kODEndAction)
  1295.             ++nestedTransactionCounter;
  1296.     }
  1297.     while (nestedTransactionCounter);
  1298. }
  1299.  
  1300. //------------------------------------------------------------------------------
  1301. // SystemUndo::Redo
  1302. //------------------------------------------------------------------------------
  1303.  
  1304. void SystemUndo::Redo()
  1305. {
  1306.     UndoAction* action = (UndoAction*)fRedoStack->First();
  1307.     if (!this->CheckActionOK(action))
  1308.         THROW(kODErrEmptyStack);
  1309.  
  1310.     fCurrentlyUndoingOrRedoing = kODTrue;
  1311.  
  1312.     TRY
  1313.         if (action->fActionType == kODBeginAction)//Start is at top for an Redo
  1314.             this->TransactionRedo(action);
  1315.         else
  1316.         {
  1317.             THROW_IF_ERROR(NotifyRedo(action, kODBringToFront));
  1318.             this->MoveRedoToUndo();
  1319.         }
  1320.     CATCH_ALL
  1321.         this->ClearActionHistory(kODDontRespectMarks);
  1322.         fCurrentlyUndoingOrRedoing = kODFalse;
  1323.         RERAISE;
  1324.     ENDTRY
  1325.     fCurrentlyUndoingOrRedoing = kODFalse;
  1326. }
  1327.  
  1328. //------------------------------------------------------------------------------
  1329. // SystemUndo::TransactionRedo
  1330. //------------------------------------------------------------------------------
  1331.  
  1332. void SystemUndo::TransactionRedo(UndoAction* firstAction)
  1333. {
  1334.     UndoAction*    action;
  1335.     ODULong        nestedTransactionCounter = 1;
  1336.  
  1337.     THROW_IF_ERROR(NotifyRedo(firstAction, ! kODBringToFront));
  1338.     this->MoveRedoToUndo();
  1339.  
  1340.     do
  1341.     {
  1342.         action = (UndoAction*)fRedoStack->First();
  1343. //        if (action == (UndoAction*)kODNULL)
  1344. //            THROW(kODErrNoBeginAction);
  1345.         THROW_IF_ERROR(NotifyRedo(action, ! kODBringToFront));
  1346.         this->MoveRedoToUndo();
  1347.         if (action->fActionType == kODBeginAction)
  1348.             ++nestedTransactionCounter;
  1349.         else if (action->fActionType == kODEndAction)
  1350.             --nestedTransactionCounter;
  1351.     }
  1352.     while (nestedTransactionCounter);
  1353. }
  1354.  
  1355. //------------------------------------------------------------------------------
  1356. // SystemUndo::MarkActionHistory
  1357. //------------------------------------------------------------------------------
  1358.  
  1359. void SystemUndo::MarkActionHistory()
  1360. {
  1361.     UndoAction*    action;
  1362.  
  1363.     action = (UndoAction*)fUndoStack->First();
  1364.     if (action)
  1365.         action->fMark = kODTrue;
  1366.     action = (UndoAction*)fRedoStack->First();
  1367.     if (action)
  1368.         action->fMark = kODTrue;
  1369. }
  1370.  
  1371. //------------------------------------------------------------------------------
  1372. // SystemUndo::ClearStack
  1373. //------------------------------------------------------------------------------
  1374.  
  1375. void SystemUndo::ClearStack(UndoOrderedCollection* stack)
  1376. {
  1377.     UndoOrderedCollectionIterator    iter(stack);
  1378.     UndoAction*            action;
  1379.  
  1380.     for (action = (UndoAction*)iter.First();
  1381.             iter.IsNotComplete();
  1382.             action = (UndoAction*)iter.Next())
  1383.     {
  1384.         delete action;
  1385.     }
  1386.     
  1387.     stack->RemoveAll();
  1388. }
  1389.  
  1390. //------------------------------------------------------------------------------
  1391. // SystemUndo::ClearActionsToMark
  1392. //
  1393. //    To make more efficient, should just start removing items from the front of
  1394. //    the list til I hit the mark.
  1395. //------------------------------------------------------------------------------
  1396.  
  1397. void SystemUndo::ClearActionsToMark(UndoOrderedCollection* stack)
  1398. {
  1399.     UndoOrderedCollectionIterator    collectionIter(stack);
  1400.     UndoAction*                    action;
  1401.     UndoOrderedCollection            elementsToDelete;
  1402.  
  1403.     // ADD ELEMENTS TO REMOVE TO A LIST
  1404.     for (action = (UndoAction*)collectionIter.First();
  1405.             collectionIter.IsNotComplete();
  1406.             action = (UndoAction*)collectionIter.Next())
  1407.     {
  1408.         if (action->fMark != kODFalse)
  1409.         {
  1410.             action->fMark = kODFalse;
  1411.             break;
  1412.         }
  1413.         else
  1414.             elementsToDelete.AddFirst(action);
  1415.     }
  1416.  
  1417.     // REMOVE ELEMENTS
  1418.     UndoOrderedCollectionIterator    deleteIter(&elementsToDelete);
  1419.     for (action = (UndoAction*)deleteIter.First();
  1420.             deleteIter.IsNotComplete();
  1421.             action = (UndoAction*)deleteIter.Next())
  1422.     {
  1423.         stack->Remove(action);
  1424.         delete action;
  1425.     }
  1426. }
  1427.  
  1428. //------------------------------------------------------------------------------
  1429. // SystemUndo::ClearActionHistory
  1430. //------------------------------------------------------------------------------
  1431.  
  1432. void SystemUndo::ClearActionHistory(ODRespectMarksChoices respectMarks)
  1433. {
  1434.     if (respectMarks == kODRespectMarks)
  1435.     {
  1436.         this->ClearActionsToMark(fUndoStack);
  1437.         this->ClearActionsToMark(fRedoStack);
  1438.     }
  1439.     else
  1440.     {
  1441.         this->ClearStack(fUndoStack);
  1442.         this->ClearStack(fRedoStack);
  1443.     }
  1444. }
  1445.  
  1446. //------------------------------------------------------------------------------
  1447. // SystemUndo::ClearRedoHistory
  1448. //------------------------------------------------------------------------------
  1449.  
  1450. void SystemUndo::ClearRedoHistory()
  1451. {
  1452.     this->ClearActionsToMark(fRedoStack);
  1453. }
  1454.  
  1455. //------------------------------------------------------------------------------
  1456. // SystemUndo::AbortCurrentTransaction
  1457. //------------------------------------------------------------------------------
  1458.  
  1459. void SystemUndo::AbortCurrentTransaction()
  1460. {
  1461.     ODULong            nestingLevel = 0;
  1462.     ODActionType    actionType;
  1463.  
  1464.     if (fCurrentlyUndoingOrRedoing)
  1465.         return;
  1466.     if (!fInTransaction)
  1467.         return;
  1468.     
  1469.     UndoAction* action = (UndoAction*)fUndoStack->First();
  1470.  
  1471.     do
  1472.     {
  1473.         if (action->fActionType == kODEndAction)
  1474.             ++nestingLevel;
  1475.         fUndoStack->RemoveFirst();
  1476.         actionType = action->fActionType;
  1477.         THROW_IF_ERROR(NotifyUndo(action,  ! kODBringToFront));
  1478.         delete action;
  1479.         if (actionType == kODBeginAction && nestingLevel == 0)
  1480.             break;
  1481.         action = (UndoAction*)fUndoStack->First();//should never be NULL, right?
  1482.     }
  1483.     while (kODTrue);
  1484. }
  1485.  
  1486. //------------------------------------------------------------------------------
  1487. // SystemUndo::PeekUndoHistory
  1488. //------------------------------------------------------------------------------
  1489.  
  1490. ODBoolean SystemUndo::PeekUndoHistory(ODPart** part,
  1491.                                 ODActionData* actionData,
  1492.                                 ODActionType* actionType,
  1493.                                 ODName* actionLabel)
  1494. {
  1495.     return PeekHistory(part, actionData, actionType, actionLabel, kUndo);
  1496. }
  1497.  
  1498. //------------------------------------------------------------------------------
  1499. // SystemUndo::PeekRedoHistory
  1500. //------------------------------------------------------------------------------
  1501.  
  1502. ODBoolean SystemUndo::PeekRedoHistory(ODPart** part,
  1503.                                 ODActionData* actionData,
  1504.                                 ODActionType* actionType,
  1505.                                 ODName* actionLabel)
  1506. {
  1507.     return PeekHistory(part, actionData, actionType, actionLabel, kRedo);
  1508. }
  1509.  
  1510. //------------------------------------------------------------------------------
  1511. // SystemUndo::PeekHistory
  1512. //
  1513. //    We could choose to only fill out the pieces needed here.
  1514. //------------------------------------------------------------------------------
  1515.  
  1516. ODBoolean SystemUndo::PeekHistory(ODPart** part,
  1517.                                 ODActionData* actionData,
  1518.                                 ODActionType* actionType,
  1519.                                 ODName* actionLabel,
  1520.                                 ODUndoRedoType which)
  1521. {
  1522.     UndoOrderedCollection*    stack;
  1523.     ODIText*                iText;
  1524.     ODBoolean                createPhonyIText = kODFalse;
  1525.  
  1526.     if (which == kUndo)
  1527.         stack = fUndoStack;
  1528.     else if (which == kRedo)
  1529.         stack = fRedoStack;
  1530.  
  1531.     UndoAction*    action = (UndoAction*)stack->First();
  1532.  
  1533.     if (!this->CheckActionOK(action))
  1534.         return kODFalse;
  1535.     else
  1536.     {
  1537.         if (action->fMark != kODFalse)
  1538.             return kODFalse;
  1539.         // We need to see whether the action is still valid
  1540.         // (i.e., whether the process is still up and running).
  1541.         else if (this->ShouldStackBeCleared(stack))
  1542.         {
  1543.             this->ClearActionHistory(kODDontRespectMarks);
  1544.             return kODFalse;
  1545.         }
  1546.         else
  1547.         {
  1548.             *part = action->fPart;
  1549.             *actionType = action->fActionType;
  1550.  
  1551.             // NP: null data mods
  1552.             if (action->fActionData)
  1553.                 *actionData = CopyByteArrayStruct(action->fActionData);
  1554.             else
  1555.                 *actionData = CreateEmptyByteArrayStruct(0);
  1556.  
  1557.             if (which == kUndo)
  1558.             {
  1559.                 if (action->fUndoActionLabel)
  1560.                     iText = action->fUndoActionLabel;
  1561.                 else
  1562.                     // NP: null data mods
  1563.                     createPhonyIText = kODTrue;
  1564.             }
  1565.             else if (which == kRedo)
  1566.             {
  1567.                 if (action->fRedoActionLabel)
  1568.                     iText = action->fRedoActionLabel;
  1569.                 else
  1570.                     // NP: null data mods
  1571.                     createPhonyIText = kODTrue;
  1572.             }
  1573.  
  1574.             if (createPhonyIText)
  1575.             {
  1576.                 // NP: null data mods
  1577.                 ODIText*    emptyIText = CreateIText(0);
  1578.                 *actionLabel = CopyITextStruct(emptyIText);
  1579.                 DisposeIText(emptyIText);
  1580.             }
  1581.             else
  1582.                 *actionLabel = CopyITextStruct(iText);
  1583.  
  1584.             return kODTrue;
  1585.         }
  1586.     }
  1587. }
  1588.  
  1589. //------------------------------------------------------------------------------
  1590. // NotifyUndoOrRedoOrDispose
  1591. //
  1592. //    Notify part to Undo or Redo or Dispose its data.
  1593. //    Could fine-tune to only pack parameters needed according to "which"
  1594. //    parameter
  1595. //------------------------------------------------------------------------------
  1596.  
  1597. static OSErr NotifyUndoOrRedoOrDispose(UndoAction* action,
  1598.                                                 ODUndoRedoType which,
  1599.                                                 ODBoolean    bringToFront)
  1600. {
  1601.     AEAddressDesc        address;
  1602.     AppleEvent            message;
  1603.     AppleEvent            reply = NULL_DESCRIPTOR_DEFINITION;
  1604.     OSErr                error = noErr;
  1605.     ProcessSerialNumber    psn;
  1606.     Boolean                isSameProcess;
  1607.     DescType            eventID;
  1608. //    ProcessInfoRec        processRec;
  1609.     octet                validAddrForPhonyData;
  1610.  
  1611.     TRY
  1612. #if 0
  1613.         // MAKE SURE PROCESS IS STILL VALID. USE SIDE EFFECT OF ERROR RETURN
  1614.         //    FROM GetProcessInformation.
  1615.         processRec.processInfoLength = sizeof(ProcessInfoRec);
  1616.         processRec.processName = kODNULL;
  1617.         processRec.processAppSpec = kODNULL;
  1618.         THROW_IF_ERROR(GetProcessInformation(&action->fProcessNum, &processRec));
  1619. #endif /* 0 */
  1620.         // SOME CODE TO HANDLE THE SEND TO SELF CASE WELL. IF WE HAVE A STANDARD
  1621.         //    IDLE PROC TO USE, WE PROBABLY DON'T NEED THIS. (NP-WHAT DID I MEAN
  1622.         //    HERE?)
  1623.         THROW_IF_ERROR(GetCurrentProcess(&psn));
  1624.         THROW_IF_ERROR(SameProcess(&action->fProcessNum, &psn,
  1625.                                     &isSameProcess));
  1626.         if (isSameProcess)
  1627.         {
  1628.             psn.lowLongOfPSN = kCurrentProcess;
  1629.             psn.highLongOfPSN = 0;
  1630.         }
  1631.         else
  1632.             psn = action->fProcessNum;
  1633. #if 0
  1634.         {
  1635.             // MAKE SURE PROCESS IS STILL ALIVE.
  1636.             ODBoolean    processStillExists = kODFalse;
  1637.             
  1638.             while (kODTrue)
  1639.             {
  1640.                 if (GetNextProcess(&psn) != noErr)
  1641.                     break;
  1642.                 THROW_IF_ERROR(SameProcess(&action->fProcessNum, &psn,
  1643.                                             &isSameProcess));
  1644.                 if (isSameProcess)
  1645.                 {
  1646.                     processStillExists = kODTrue;
  1647.                     break;
  1648.                 }
  1649.             }
  1650.             
  1651.             if (!processStillExists)
  1652.                 THROW(procNotFound);
  1653.         }
  1654. #endif /* 0 */
  1655.         THROW_IF_ERROR(AECreateDesc(typeProcessSerialNumber,
  1656.                                     (Ptr)&psn, sizeof(psn), &address));
  1657.  
  1658.         TempAEDesc tempAddress(&address);
  1659.         if (which == kUndo)
  1660.             eventID = kUndoNotifyID;
  1661.         else if (which == kRedo)
  1662.             eventID = kRedoNotifyID;
  1663.         else if (which == kDispose)
  1664.             eventID = kDisposeActionNotifyID;
  1665.  
  1666.         THROW_IF_ERROR(AECreateAppleEvent(kODShellSignature, eventID,
  1667.                         &address, kAutoGenerateReturnID, kAnyTransactionID,
  1668.                         &message));
  1669.         TempAEDesc tempMessage(&message); // DMc make sure it is disposed
  1670.     
  1671.         // NP: null data mods
  1672.         if (!action->fActionData)
  1673.         {
  1674.             action->fActionData->_length = 0;
  1675.             action->fActionData->_buffer = &validAddrForPhonyData;
  1676.         }
  1677.         THROW_IF_ERROR(AEPutParamPtr(&message, kDataPtrKeyword, typeChar,
  1678.                                     action->fActionData->_buffer,
  1679.                                     action->fActionData->_length));
  1680.         
  1681.         THROW_IF_ERROR(AEPutParamPtr(&message, kPartPtrKeyword, typeInteger,
  1682.                                     (Ptr)&action->fPart,
  1683.                                     sizeof(action->fPart)));
  1684.         
  1685.         THROW_IF_ERROR(AEPutParamPtr(&message, kDoneStateKeyword, typeInteger,
  1686.                                     (Ptr)&action->fDoneState,
  1687.                                     sizeof(action->fDoneState)));
  1688.         
  1689.         if (bringToFront)
  1690.             SetFrontProcess(&psn);
  1691.  
  1692.         THROW_IF_ERROR(AESend(&message, &reply,
  1693.                                 (which == kDispose ? kAENoReply : kAEWaitReply)
  1694.                                     + kAECanInteract + kAECanSwitchLayer + kAEDontRecord,
  1695.                                 kAENormalPriority,
  1696.                                 kAEDefaultTimeout,
  1697.                                 (AEIdleUPP)kODNULL, (AEFilterUPP)kODNULL));
  1698.  
  1699.         AEDisposeDesc(&reply); // DMc
  1700.     CATCH_ALL
  1701.         error = ErrorCode();
  1702.     ENDTRY
  1703.     
  1704.     return error;
  1705. }
  1706.  
  1707. //------------------------------------------------------------------------------
  1708. // NotifyUndo
  1709. //
  1710. //    Call ODPart::Undo.
  1711. //------------------------------------------------------------------------------
  1712.  
  1713. static OSErr NotifyUndo(UndoAction* action, ODBoolean bringToFront)
  1714. {
  1715.     return NotifyUndoOrRedoOrDispose(action, kUndo, bringToFront);
  1716. }
  1717.  
  1718. //------------------------------------------------------------------------------
  1719. // NotifyRedo
  1720. //
  1721. //    Call ODPart::Redo.
  1722. //------------------------------------------------------------------------------
  1723.  
  1724. static OSErr NotifyRedo(UndoAction* action, ODBoolean bringToFront)
  1725. {
  1726.     return NotifyUndoOrRedoOrDispose(action, kRedo, bringToFront);
  1727. }
  1728.  
  1729. //------------------------------------------------------------------------------
  1730. // NotifyDispose
  1731. //
  1732. //    Call ODPart::DiposeActionState.
  1733. //------------------------------------------------------------------------------
  1734.  
  1735. static OSErr NotifyDispose(UndoAction* action)
  1736. {
  1737.     return NotifyUndoOrRedoOrDispose(action, kDispose, ! kODBringToFront);
  1738. }
  1739.  
  1740. //==============================================================================
  1741. // ODUndo
  1742. //==============================================================================
  1743.  
  1744. //------------------------------------------------------------------------------
  1745. // HandleUndoOrRedoOrDisposeNotify
  1746. //
  1747. //    Could fine-tune to only unpack parameters needed according to "which"
  1748. //    parameter
  1749. //------------------------------------------------------------------------------
  1750.  
  1751. static OSErr HandleUndoOrRedoOrDisposeNotify(AppleEvent* message,
  1752.                                                 AppleEvent* reply,
  1753.                                                 long refCon,
  1754.                                                 ODUndoRedoType which)
  1755. {
  1756.     ODUnused(reply);
  1757.     ODUnused(refCon);
  1758.  
  1759.     OSErr            error = noErr;
  1760.     DescType        gotType;
  1761. //    ODActionData*    data;
  1762.     ODPart*            part;
  1763.     ODDoneState        doneState;
  1764.     Size            actualSize;
  1765. //    Size            maximumDataSize;
  1766.     Size            maximumPartSize = sizeof(part);
  1767.     Size            maximumDoneStateSize = sizeof(doneState);
  1768.  
  1769.     TRY
  1770. #if 0
  1771.         gotType = typeChar;
  1772.         THROW_IF_ERROR(AESizeOfParam(message, kDataPtrKeyword, &gotType,
  1773.                                         &actualSize));
  1774.         if (gotType != typeChar)
  1775.             THROW(errAECorruptData);
  1776.         maximumDataSize = actualSize;
  1777.         data = CreateEmptyByteArray(actualSize);
  1778.         THROW_IF_ERROR(AEGetParamPtr(message, kDataPtrKeyword, typeChar,
  1779.                                         &gotType, data->_buffer, maximumDataSize,
  1780.                                         &actualSize));
  1781.         if (actualSize != maximumDataSize)
  1782.             THROW(errAECorruptData);
  1783. #endif /* 0 */        
  1784.         TempODByteArray data = ODAEGetByteArray(message, kDataPtrKeyword,
  1785.                                                 typeChar);
  1786.  
  1787.         THROW_IF_ERROR(AEGetParamPtr(message, kPartPtrKeyword, typeInteger,
  1788.                                     &gotType, (Ptr)&part, maximumPartSize,
  1789.                                     &actualSize));
  1790.         if (gotType != typeInteger || actualSize != maximumPartSize)
  1791.             THROW(errAECorruptData);
  1792.         
  1793.         THROW_IF_ERROR(AEGetParamPtr(message, kDoneStateKeyword, typeInteger,
  1794.                                     &gotType, (Ptr)&doneState,
  1795.                                     maximumDoneStateSize,
  1796.                                     &actualSize));
  1797.         if (gotType != typeInteger || actualSize != maximumDoneStateSize)
  1798.             THROW(errAECorruptData);
  1799.         
  1800.         Environment*    ev = somGetGlobalEnvironment();
  1801.         if (which == kUndo)
  1802.         {
  1803.             part->UndoAction(ev, data);
  1804.             error = ODGetSOMException(ev);
  1805.         }
  1806.         else if (which == kRedo)
  1807.         {
  1808.             part->RedoAction(ev, data);
  1809.             error = ODGetSOMException(ev);
  1810.         }
  1811.         else if (which == kDispose)
  1812.         {
  1813.             part->DisposeActionState(ev, data, doneState);
  1814.             error = ODGetSOMException(ev);
  1815.         }
  1816.         
  1817. //        DisposeByteArray(data);
  1818.         
  1819.     CATCH_ALL
  1820.         error = ErrorCode();
  1821.     ENDTRY
  1822.  
  1823.     return error;
  1824. }
  1825.  
  1826. //------------------------------------------------------------------------------
  1827. // HandleUndoNotify                
  1828. //------------------------------------------------------------------------------
  1829.  
  1830. static pascal OSErr HandleUndoNotify(AppleEvent* message, AppleEvent* reply,
  1831.                                         long refCon)
  1832. {
  1833.     return HandleUndoOrRedoOrDisposeNotify(message, reply, refCon, kUndo);
  1834. }
  1835.  
  1836. //------------------------------------------------------------------------------
  1837. // HandleRedoNotify                
  1838. //------------------------------------------------------------------------------
  1839.  
  1840. static pascal OSErr HandleRedoNotify(AppleEvent* message, AppleEvent* reply,
  1841.                                         long refCon)
  1842. {
  1843.     return HandleUndoOrRedoOrDisposeNotify(message, reply, refCon, kRedo);
  1844. }
  1845.  
  1846. //------------------------------------------------------------------------------
  1847. // HandleDisposeNotify                
  1848. //------------------------------------------------------------------------------
  1849.  
  1850. static pascal OSErr HandleDisposeNotify(AppleEvent* message, AppleEvent* reply,
  1851.                                         long refCon)
  1852. {
  1853.     return HandleUndoOrRedoOrDisposeNotify(message, reply, refCon, kDispose);
  1854. }
  1855.  
  1856. //------------------------------------------------------------------------------
  1857. // ODUndo::InitUndo
  1858. //------------------------------------------------------------------------------
  1859.  
  1860. SOM_Scope void  SOMLINK ODUndoInitUndo(ODUndo *somSelf, Environment *ev)
  1861. {
  1862.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1863.     ODUndoMethodDebug("ODUndo","ODUndoInitUndo");
  1864.  
  1865.     /* Moved from somInit. SOM itself sets fields to zero
  1866.     _fSystemUndo = kODNULL;
  1867.     */
  1868.  
  1869.     TRY
  1870.         somSelf->InitObject(ev);
  1871.  
  1872.         _fSystemUndo = GetSystemUndo();
  1873.         if (!_fSystemUndo)
  1874.         {
  1875.             _fSystemUndo = new (kODSystemHeap) SystemUndo();
  1876.             if (_fSystemUndo)
  1877.             {
  1878.                 _fSystemUndo->Initialize();
  1879.                 SetSystemUndo(_fSystemUndo);
  1880.             }
  1881.         }
  1882.         THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
  1883.                                     kUndoNotifyID,
  1884.                                     NewAEEventHandlerProc(HandleUndoNotify),
  1885.                                     (long)somSelf, !kIsSysHandler));
  1886.         THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
  1887.                                     kRedoNotifyID,
  1888.                                     NewAEEventHandlerProc(HandleRedoNotify),
  1889.                                     (long)somSelf, !kIsSysHandler));
  1890.         THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
  1891.                                     kDisposeActionNotifyID,
  1892.                                     NewAEEventHandlerProc(HandleDisposeNotify),
  1893.                                     (long)somSelf, !kIsSysHandler));
  1894.         _fSystemUndo->AddClient(somSelf);
  1895.     CATCH_ALL
  1896.         ODDeleteObject(_fSystemUndo);
  1897.         ODSetSOMException(ev, ErrorCode());
  1898.     ENDTRY
  1899. }
  1900.  
  1901. //------------------------------------------------------------------------------
  1902. // ODUndo::~ODUndo
  1903. //------------------------------------------------------------------------------
  1904.  
  1905. SOM_Scope void  SOMLINK ODUndosomUninit(ODUndo *somSelf)
  1906. {
  1907.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1908.     ODUndoMethodDebug("ODUndo","ODUndosomUninit");
  1909.  
  1910.     if (_fSystemUndo)
  1911.     {
  1912.         _fSystemUndo->RemoveClient(somSelf);
  1913.         
  1914.         if (_fSystemUndo->GetNumClients() == 0) // reclaim space.
  1915.         {
  1916.     //        WARN("Deleting system undo object.");
  1917.             ODDeleteObject(_fSystemUndo);
  1918.             SetSystemUndo(kODNULL);
  1919.         }
  1920.     }
  1921.     ODUndo_parents_somUninit(somSelf);
  1922. }
  1923. #if 0
  1924. //------------------------------------------------------------------------------
  1925. // ODUndo::Purge
  1926. //------------------------------------------------------------------------------
  1927.  
  1928. SOM_Scope ODSize  SOMLINK ODUndoPurge(ODUndo *somSelf, Environment *ev,
  1929.         ODSize size)
  1930. {
  1931.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1932.     ODUndoMethodDebug("ODUndo","ODUndoPurge");
  1933.  
  1934.     ODSize purged = 0;
  1935.     ODVolatile(purged);
  1936.     
  1937.     SOM_TRY
  1938.         if (_fSystemUndo) {
  1939.             purged =  _fSystemUndo->Purge(size);
  1940.         }
  1941.         else
  1942.             purged =  0;
  1943.  
  1944.         purged += parent_Purge(somSelf,ev,size);
  1945.     SOM_CATCH_ALL
  1946.         WARN("Error %ld trying to purge in ODUndoPurge",ErrorCode());
  1947.         SetErrorCode(kODNoError);        // dh - Eat the exception; Purge should not 
  1948.                                         // propagate it because clients function
  1949.                                         // fine whether memory was purged or not.
  1950.     SOM_ENDTRY
  1951.  
  1952.     return purged;
  1953. }
  1954. #endif /* 0 */
  1955. //------------------------------------------------------------------------------
  1956. // ODUndo::AddActionToHistory
  1957. //------------------------------------------------------------------------------
  1958.  
  1959. SOM_Scope void  SOMLINK ODUndoAddActionToHistory(ODUndo *somSelf, Environment *ev,
  1960.         ODPart* whichPart,
  1961.         ODActionData* actionData,
  1962.         ODActionType actionType,
  1963.         ODName* undoActionLabel,
  1964.         ODName* redoActionLabel)
  1965. {
  1966.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1967.     ODUndoMethodDebug("ODUndo","ODUndoAddActionToHistory");
  1968.  
  1969.     SOM_TRY
  1970.  
  1971.     if (_fSystemUndo)
  1972.         _fSystemUndo->AddActionToHistory(whichPart, actionData, actionType,
  1973.                                         undoActionLabel, redoActionLabel);
  1974.     else
  1975.         THROW(kODErrOutOfMemory);
  1976.  
  1977.     SOM_CATCH_ALL
  1978.     SOM_ENDTRY
  1979. }
  1980.  
  1981. //------------------------------------------------------------------------------
  1982. // ODUndo::Undo
  1983. //------------------------------------------------------------------------------
  1984.  
  1985. SOM_Scope void  SOMLINK ODUndoUndo(ODUndo *somSelf, Environment *ev)
  1986. {
  1987.     ODUndoData *somThis = ODUndoGetData(somSelf);
  1988.     ODUndoMethodDebug("ODUndo","ODUndoUndo");
  1989.  
  1990.     SOM_TRY
  1991.  
  1992.     if (_fSystemUndo)
  1993.         _fSystemUndo->Undo();
  1994.     else
  1995.         THROW(kODErrEmptyStack);
  1996.  
  1997.     SOM_CATCH_ALL
  1998.     SOM_ENDTRY
  1999. }
  2000.  
  2001. //------------------------------------------------------------------------------
  2002. // ODUndo::Redo
  2003. //------------------------------------------------------------------------------
  2004.  
  2005. SOM_Scope void  SOMLINK ODUndoRedo(ODUndo *somSelf, Environment *ev)
  2006. {
  2007.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2008.     ODUndoMethodDebug("ODUndo","ODUndoRedo");
  2009.  
  2010.     SOM_TRY
  2011.  
  2012.     if (_fSystemUndo)
  2013.         _fSystemUndo->Redo();
  2014.     else
  2015.         THROW(kODErrEmptyStack);
  2016.  
  2017.     SOM_CATCH_ALL
  2018.     SOM_ENDTRY
  2019. }
  2020.  
  2021. //------------------------------------------------------------------------------
  2022. // ODUndo::MarkActionHistory
  2023. //------------------------------------------------------------------------------
  2024.  
  2025. SOM_Scope void  SOMLINK ODUndoMarkActionHistory(ODUndo *somSelf, Environment *ev)
  2026. {
  2027.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2028.     ODUndoMethodDebug("ODUndo","ODUndoMarkActionHistory");
  2029.  
  2030.     SOM_TRY
  2031.  
  2032.     if (_fSystemUndo)
  2033.         _fSystemUndo->MarkActionHistory();
  2034.     else
  2035.         THROW(kODErrCannotMarkAction);
  2036.  
  2037.     SOM_CATCH_ALL
  2038.     SOM_ENDTRY
  2039. }
  2040.  
  2041. //------------------------------------------------------------------------------
  2042. // ODUndo::ClearActionHistory
  2043. //------------------------------------------------------------------------------
  2044.  
  2045. SOM_Scope void  SOMLINK ODUndoClearActionHistory(ODUndo *somSelf, Environment *ev,
  2046.         ODRespectMarksChoices respectMarks)
  2047. {
  2048.     ODUndoMethodDebug("ODUndo","ODUndoClearActionHistory");
  2049.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2050.  
  2051.     SOM_TRY
  2052.  
  2053.     if (_fSystemUndo)
  2054.         _fSystemUndo->ClearActionHistory(respectMarks);
  2055.  
  2056.     SOM_CATCH_ALL
  2057.     SOM_ENDTRY
  2058. }
  2059.  
  2060. //------------------------------------------------------------------------------
  2061. // ODUndo::ClearRedoHistory
  2062. //------------------------------------------------------------------------------
  2063.  
  2064. SOM_Scope void  SOMLINK ODUndoClearRedoHistory(ODUndo *somSelf, Environment *ev)
  2065. {
  2066.     ODUndoMethodDebug("ODUndo","ODUndoClearRedoHistory");
  2067.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2068.  
  2069.     SOM_TRY
  2070.  
  2071.     if (_fSystemUndo)
  2072.         _fSystemUndo->ClearRedoHistory();
  2073.  
  2074.     SOM_CATCH_ALL
  2075.     SOM_ENDTRY
  2076. }
  2077.  
  2078. //------------------------------------------------------------------------------
  2079. // ODUndo::PeekUndoHistory
  2080. //------------------------------------------------------------------------------
  2081.  
  2082. SOM_Scope ODBoolean  SOMLINK ODUndoPeekUndoHistory(ODUndo *somSelf, Environment *ev,
  2083.         ODPart** part,
  2084.         ODActionData* actionData,
  2085.         ODActionType* actionType,
  2086.         ODName* actionLabel)
  2087. {
  2088.     ODUndoMethodDebug("ODUndo","ODUndoPeekUndoHistory");
  2089.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2090.  
  2091.     SOM_TRY
  2092.  
  2093.     if (_fSystemUndo)
  2094.         return _fSystemUndo->PeekUndoHistory(part, actionData, actionType,
  2095.                                                 actionLabel);
  2096.     else
  2097.         return kODFalse;
  2098.  
  2099.     SOM_CATCH_ALL
  2100.     SOM_ENDTRY
  2101.     return kODFalse;
  2102. }
  2103.  
  2104. //------------------------------------------------------------------------------
  2105. // ODUndo::PeekRedoHistory
  2106. //------------------------------------------------------------------------------
  2107.  
  2108. SOM_Scope ODBoolean  SOMLINK ODUndoPeekRedoHistory(ODUndo *somSelf, Environment *ev,
  2109.         ODPart** part,
  2110.         ODActionData* actionData,
  2111.         ODActionType* actionType,
  2112.         ODName* actionLabel)
  2113. {
  2114.     ODUndoMethodDebug("ODUndo","ODUndoPeekRedoHistory");
  2115.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2116.  
  2117.     SOM_TRY
  2118.  
  2119.     if (_fSystemUndo)
  2120.         return _fSystemUndo->PeekRedoHistory(part, actionData, actionType,
  2121.                                                 actionLabel);
  2122.     else
  2123.         return kODFalse;
  2124.  
  2125.     SOM_CATCH_ALL
  2126.     SOM_ENDTRY
  2127.     return kODFalse;
  2128. }
  2129.  
  2130. //------------------------------------------------------------------------------
  2131. // ODUndo::AbortCurrentTransaction
  2132. //------------------------------------------------------------------------------
  2133.  
  2134. SOM_Scope void  SOMLINK ODUndoAbortCurrentTransaction(ODUndo *somSelf, Environment *ev)
  2135. {
  2136.     ODUndoMethodDebug("ODUndo","ODUndoAbortCurrentTransaction");
  2137.     ODUndoData *somThis = ODUndoGetData(somSelf);
  2138.  
  2139.     SOM_TRY
  2140.  
  2141.     if (_fSystemUndo)
  2142.         _fSystemUndo->AbortCurrentTransaction();
  2143.  
  2144.     SOM_CATCH_ALL
  2145.     SOM_ENDTRY
  2146. }
  2147.  
  2148.