LCOV - code coverage report
Current view: top level - editor/txmgr - nsTransactionItem.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 21 175 12.0 %
Date: 2017-07-14 16:53:18 Functions: 8 24 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/mozalloc.h"
       7             : #include "nsCOMPtr.h"
       8             : #include "nsDebug.h"
       9             : #include "nsError.h"
      10             : #include "nsISupportsImpl.h"
      11             : #include "nsITransaction.h"
      12             : #include "nsTransactionItem.h"
      13             : #include "nsTransactionManager.h"
      14             : #include "nsTransactionStack.h"
      15             : 
      16           3 : nsTransactionItem::nsTransactionItem(nsITransaction *aTransaction)
      17           3 :     : mTransaction(aTransaction), mUndoStack(0), mRedoStack(0)
      18             : {
      19           3 : }
      20             : 
      21           9 : nsTransactionItem::~nsTransactionItem()
      22             : {
      23           3 :   delete mRedoStack;
      24           3 :   delete mUndoStack;
      25           9 : }
      26             : 
      27             : void
      28           3 : nsTransactionItem::CleanUp()
      29             : {
      30           3 :   mData.Clear();
      31           3 :   mTransaction = nullptr;
      32           3 :   if (mRedoStack) {
      33           0 :     mRedoStack->DoUnlink();
      34             :   }
      35           3 :   if (mUndoStack) {
      36           0 :     mUndoStack->DoUnlink();
      37             :   }
      38           3 : }
      39             : 
      40           6 : NS_IMPL_CYCLE_COLLECTING_NATIVE_ADDREF(nsTransactionItem)
      41           6 : NS_IMPL_CYCLE_COLLECTING_NATIVE_RELEASE_WITH_LAST_RELEASE(nsTransactionItem,
      42             :                                                           CleanUp())
      43             : 
      44             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsTransactionItem)
      45             : 
      46           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsTransactionItem)
      47           0 :   tmp->CleanUp();
      48           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      49             : 
      50           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTransactionItem)
      51           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
      52           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
      53           0 :   if (tmp->mRedoStack) {
      54           0 :     tmp->mRedoStack->DoTraverse(cb);
      55             :   }
      56           0 :   if (tmp->mUndoStack) {
      57           0 :     tmp->mUndoStack->DoTraverse(cb);
      58             :   }
      59           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      60             : 
      61           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTransactionItem, AddRef)
      62           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTransactionItem, Release)
      63             : 
      64             : nsresult
      65           0 : nsTransactionItem::AddChild(nsTransactionItem *aTransactionItem)
      66             : {
      67           0 :   NS_ENSURE_TRUE(aTransactionItem, NS_ERROR_NULL_POINTER);
      68             : 
      69           0 :   if (!mUndoStack) {
      70           0 :     mUndoStack = new nsTransactionStack(nsTransactionStack::FOR_UNDO);
      71             :   }
      72             : 
      73           0 :   mUndoStack->Push(aTransactionItem);
      74           0 :   return NS_OK;
      75             : }
      76             : 
      77             : already_AddRefed<nsITransaction>
      78           3 : nsTransactionItem::GetTransaction()
      79             : {
      80           6 :   nsCOMPtr<nsITransaction> txn = mTransaction;
      81           6 :   return txn.forget();
      82             : }
      83             : 
      84             : nsresult
      85           0 : nsTransactionItem::GetIsBatch(bool *aIsBatch)
      86             : {
      87           0 :   NS_ENSURE_TRUE(aIsBatch, NS_ERROR_NULL_POINTER);
      88           0 :   *aIsBatch = !mTransaction;
      89           0 :   return NS_OK;
      90             : }
      91             : 
      92             : nsresult
      93           0 : nsTransactionItem::GetNumberOfChildren(int32_t *aNumChildren)
      94             : {
      95           0 :   NS_ENSURE_TRUE(aNumChildren, NS_ERROR_NULL_POINTER);
      96             : 
      97           0 :   *aNumChildren = 0;
      98             : 
      99           0 :   int32_t ui = 0;
     100           0 :   nsresult rv = GetNumberOfUndoItems(&ui);
     101           0 :   NS_ENSURE_SUCCESS(rv, rv);
     102             : 
     103           0 :   int32_t ri = 0;
     104           0 :   rv = GetNumberOfRedoItems(&ri);
     105           0 :   NS_ENSURE_SUCCESS(rv, rv);
     106             : 
     107           0 :   *aNumChildren = ui + ri;
     108           0 :   return NS_OK;
     109             : }
     110             : 
     111             : nsresult
     112           0 : nsTransactionItem::GetChild(int32_t aIndex, nsTransactionItem **aChild)
     113             : {
     114           0 :   NS_ENSURE_TRUE(aChild, NS_ERROR_NULL_POINTER);
     115             : 
     116           0 :   *aChild = 0;
     117             : 
     118           0 :   int32_t numItems = 0;
     119           0 :   nsresult rv = GetNumberOfChildren(&numItems);
     120           0 :   NS_ENSURE_SUCCESS(rv, rv);
     121           0 :   if (aIndex < 0 || aIndex >= numItems) {
     122           0 :     return NS_ERROR_FAILURE;
     123             :   }
     124             : 
     125             :   // Children are expected to be in the order they were added,
     126             :   // so the child first added would be at the bottom of the undo
     127             :   // stack, or if there are no items on the undo stack, it would
     128             :   // be at the top of the redo stack.
     129           0 :   rv = GetNumberOfUndoItems(&numItems);
     130           0 :   NS_ENSURE_SUCCESS(rv, rv);
     131             : 
     132           0 :   if (numItems > 0 && aIndex < numItems) {
     133           0 :     NS_ENSURE_TRUE(mUndoStack, NS_ERROR_FAILURE);
     134             : 
     135           0 :     RefPtr<nsTransactionItem> child = mUndoStack->GetItem(aIndex);
     136           0 :     child.forget(aChild);
     137           0 :     return *aChild ? NS_OK : NS_ERROR_FAILURE;
     138             :   }
     139             : 
     140             :   // Adjust the index for the redo stack:
     141           0 :   aIndex -=  numItems;
     142             : 
     143           0 :   rv = GetNumberOfRedoItems(&numItems);
     144           0 :   NS_ENSURE_SUCCESS(rv, rv);
     145           0 :   NS_ENSURE_TRUE(mRedoStack && numItems != 0 && aIndex < numItems, NS_ERROR_FAILURE);
     146             : 
     147           0 :   RefPtr<nsTransactionItem> child = mRedoStack->GetItem(aIndex);
     148           0 :   child.forget(aChild);
     149           0 :   return *aChild ? NS_OK : NS_ERROR_FAILURE;
     150             : }
     151             : 
     152             : nsresult
     153           3 : nsTransactionItem::DoTransaction()
     154             : {
     155           3 :   if (mTransaction) {
     156           3 :     return mTransaction->DoTransaction();
     157             :   }
     158           0 :   return NS_OK;
     159             : }
     160             : 
     161             : nsresult
     162           0 : nsTransactionItem::UndoTransaction(nsTransactionManager *aTxMgr)
     163             : {
     164           0 :   nsresult rv = UndoChildren(aTxMgr);
     165           0 :   if (NS_FAILED(rv)) {
     166           0 :     RecoverFromUndoError(aTxMgr);
     167           0 :     return rv;
     168             :   }
     169             : 
     170           0 :   if (!mTransaction) {
     171           0 :     return NS_OK;
     172             :   }
     173             : 
     174           0 :   rv = mTransaction->UndoTransaction();
     175           0 :   if (NS_FAILED(rv)) {
     176           0 :     RecoverFromUndoError(aTxMgr);
     177           0 :     return rv;
     178             :   }
     179             : 
     180           0 :   return NS_OK;
     181             : }
     182             : 
     183             : nsresult
     184           0 : nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
     185             : {
     186           0 :   if (mUndoStack) {
     187           0 :     if (!mRedoStack && mUndoStack) {
     188           0 :       mRedoStack = new nsTransactionStack(nsTransactionStack::FOR_REDO);
     189             :     }
     190             : 
     191             :     /* Undo all of the transaction items children! */
     192           0 :     int32_t sz = mUndoStack->GetSize();
     193             : 
     194           0 :     nsresult rv = NS_OK;
     195           0 :     while (sz-- > 0) {
     196           0 :       RefPtr<nsTransactionItem> item = mUndoStack->Peek();
     197           0 :       if (!item) {
     198           0 :         return NS_ERROR_FAILURE;
     199             :       }
     200             : 
     201           0 :       nsCOMPtr<nsITransaction> t = item->GetTransaction();
     202           0 :       bool doInterrupt = false;
     203           0 :       rv = aTxMgr->WillUndoNotify(t, &doInterrupt);
     204           0 :       if (NS_FAILED(rv)) {
     205           0 :         return rv;
     206             :       }
     207           0 :       if (doInterrupt) {
     208           0 :         return NS_OK;
     209             :       }
     210             : 
     211           0 :       rv = item->UndoTransaction(aTxMgr);
     212           0 :       if (NS_SUCCEEDED(rv)) {
     213           0 :         item = mUndoStack->Pop();
     214           0 :         mRedoStack->Push(item.forget());
     215             :       }
     216             : 
     217           0 :       nsresult rv2 = aTxMgr->DidUndoNotify(t, rv);
     218           0 :       if (NS_SUCCEEDED(rv)) {
     219           0 :         rv = rv2;
     220             :       }
     221             :     }
     222             :     // XXX NS_OK if there is no Undo items or all methods work fine, otherwise,
     223             :     //     the result of the last item's UndoTransaction() or
     224             :     //     DidUndoNotify() if UndoTransaction() succeeded.
     225           0 :     return rv;
     226             :   }
     227             : 
     228           0 :   return NS_OK;
     229             : }
     230             : 
     231             : nsresult
     232           0 : nsTransactionItem::RedoTransaction(nsTransactionManager *aTxMgr)
     233             : {
     234           0 :   nsCOMPtr<nsITransaction> transaction(mTransaction);
     235           0 :   if (transaction) {
     236           0 :     nsresult rv = transaction->RedoTransaction();
     237           0 :     NS_ENSURE_SUCCESS(rv, rv);
     238             :   }
     239             : 
     240           0 :   nsresult rv = RedoChildren(aTxMgr);
     241           0 :   if (NS_FAILED(rv)) {
     242           0 :     RecoverFromRedoError(aTxMgr);
     243           0 :     return rv;
     244             :   }
     245             : 
     246           0 :   return NS_OK;
     247             : }
     248             : 
     249             : nsresult
     250           0 : nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
     251             : {
     252           0 :   if (!mRedoStack) {
     253           0 :     return NS_OK;
     254             :   }
     255             : 
     256             :   /* Redo all of the transaction items children! */
     257           0 :   int32_t sz = mRedoStack->GetSize();
     258             : 
     259           0 :   nsresult rv = NS_OK;
     260           0 :   while (sz-- > 0) {
     261           0 :     RefPtr<nsTransactionItem> item = mRedoStack->Peek();
     262           0 :     if (!item) {
     263           0 :       return NS_ERROR_FAILURE;
     264             :     }
     265             : 
     266           0 :     nsCOMPtr<nsITransaction> t = item->GetTransaction();
     267           0 :     bool doInterrupt = false;
     268           0 :     rv = aTxMgr->WillRedoNotify(t, &doInterrupt);
     269           0 :     if (NS_FAILED(rv)) {
     270           0 :       return rv;
     271             :     }
     272           0 :     if (doInterrupt) {
     273           0 :       return NS_OK;
     274             :     }
     275             : 
     276           0 :     rv = item->RedoTransaction(aTxMgr);
     277           0 :     if (NS_SUCCEEDED(rv)) {
     278           0 :       item = mRedoStack->Pop();
     279           0 :       mUndoStack->Push(item.forget());
     280             :     }
     281             : 
     282             :     // XXX Shouldn't this DidRedoNotify()? (bug 1311626)
     283           0 :     nsresult rv2 = aTxMgr->DidUndoNotify(t, rv);
     284           0 :     if (NS_SUCCEEDED(rv)) {
     285           0 :       rv = rv2;
     286             :     }
     287             :   }
     288             :   // XXX NS_OK if there is no Redo items or all methods work fine, otherwise,
     289             :   //     the result of the last item's RedoTransaction() or
     290             :   //     DidUndoNotify() if UndoTransaction() succeeded.
     291           0 :   return rv;
     292             : }
     293             : 
     294             : nsresult
     295           0 : nsTransactionItem::GetNumberOfUndoItems(int32_t *aNumItems)
     296             : {
     297           0 :   NS_ENSURE_TRUE(aNumItems, NS_ERROR_NULL_POINTER);
     298             : 
     299           0 :   if (!mUndoStack) {
     300           0 :     *aNumItems = 0;
     301           0 :     return NS_OK;
     302             :   }
     303             : 
     304           0 :   *aNumItems = mUndoStack->GetSize();
     305           0 :   return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
     306             : }
     307             : 
     308             : nsresult
     309           0 : nsTransactionItem::GetNumberOfRedoItems(int32_t *aNumItems)
     310             : {
     311           0 :   NS_ENSURE_TRUE(aNumItems, NS_ERROR_NULL_POINTER);
     312             : 
     313           0 :   if (!mRedoStack) {
     314           0 :     *aNumItems = 0;
     315           0 :     return NS_OK;
     316             :   }
     317             : 
     318           0 :   *aNumItems = mRedoStack->GetSize();
     319           0 :   return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
     320             : }
     321             : 
     322             : nsresult
     323           0 : nsTransactionItem::RecoverFromUndoError(nsTransactionManager *aTxMgr)
     324             : {
     325             :   // If this method gets called, we never got to the point where we
     326             :   // successfully called UndoTransaction() for the transaction item itself.
     327             :   // Just redo any children that successfully called undo!
     328           0 :   return RedoChildren(aTxMgr);
     329             : }
     330             : 
     331             : nsresult
     332           0 : nsTransactionItem::RecoverFromRedoError(nsTransactionManager *aTxMgr)
     333             : {
     334             :   // If this method gets called, we already successfully called
     335             :   // RedoTransaction() for the transaction item itself. Undo all
     336             :   // the children that successfully called RedoTransaction(),
     337             :   // then undo the transaction item itself.
     338           0 :   nsresult rv = UndoChildren(aTxMgr);
     339           0 :   if (NS_FAILED(rv)) {
     340           0 :     return rv;
     341             :   }
     342             : 
     343           0 :   if (!mTransaction) {
     344           0 :     return NS_OK;
     345             :   }
     346             : 
     347           0 :   return mTransaction->UndoTransaction();
     348             : }
     349             : 

Generated by: LCOV version 1.13