LCOV - code coverage report
Current view: directory - editor/txmgr/src - nsTransactionItem.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 192 139 72.4 %
Date: 2012-06-02 Functions: 26 19 73.1 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsITransaction.h"
      39                 : #include "nsTransactionStack.h"
      40                 : #include "nsTransactionManager.h"
      41                 : #include "nsTransactionItem.h"
      42                 : #include "nsCOMPtr.h"
      43                 : #include "nsAutoPtr.h"
      44                 : 
      45            4985 : nsTransactionItem::nsTransactionItem(nsITransaction *aTransaction)
      46            4985 :     : mTransaction(aTransaction), mUndoStack(0), mRedoStack(0)
      47                 : {
      48            4985 : }
      49                 : 
      50           14955 : nsTransactionItem::~nsTransactionItem()
      51                 : {
      52            4985 :   delete mRedoStack;
      53                 : 
      54            4985 :   delete mUndoStack;
      55           19940 : }
      56                 : 
      57                 : nsrefcnt
      58           37912 : nsTransactionItem::AddRef()
      59                 : {
      60           37912 :   ++mRefCnt;
      61           37912 :   NS_LOG_ADDREF(this, mRefCnt, "nsTransactionItem",
      62           37912 :                 sizeof(nsTransactionItem));
      63           37912 :   return mRefCnt;
      64                 : }
      65                 : 
      66                 : nsrefcnt
      67           37912 : nsTransactionItem::Release() {
      68           37912 :   --mRefCnt;
      69           37912 :   NS_LOG_RELEASE(this, mRefCnt, "nsTransactionItem");
      70           37912 :   if (mRefCnt == 0) {
      71            4985 :     mRefCnt = 1;
      72            4985 :     delete this;
      73            4985 :     return 0;
      74                 :   }
      75           32927 :   return mRefCnt;
      76                 : }
      77                 : 
      78            1464 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsTransactionItem)
      79                 : 
      80               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_NATIVE(nsTransactionItem)
      81               0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTransaction)
      82               0 :   if (tmp->mRedoStack) {
      83               0 :     tmp->mRedoStack->DoUnlink();
      84                 :   }
      85               0 :   if (tmp->mUndoStack) {
      86               0 :     tmp->mUndoStack->DoUnlink();
      87                 :   }
      88               0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      89                 : 
      90               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_BEGIN(nsTransactionItem)
      91               0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTransaction)
      92               0 :   if (tmp->mRedoStack) {
      93               0 :     tmp->mRedoStack->DoTraverse(cb);
      94                 :   }
      95               0 :   if (tmp->mUndoStack) {
      96               0 :     tmp->mUndoStack->DoTraverse(cb);
      97                 :   }
      98               0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      99                 : 
     100               0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTransactionItem, AddRef)
     101               0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTransactionItem, Release)
     102                 : 
     103                 : nsresult
     104            4047 : nsTransactionItem::AddChild(nsTransactionItem *aTransactionItem)
     105                 : {
     106            4047 :   NS_ENSURE_TRUE(aTransactionItem, NS_ERROR_NULL_POINTER);
     107                 : 
     108            4047 :   if (!mUndoStack) {
     109            1729 :     mUndoStack = new nsTransactionStack(nsTransactionStack::FOR_UNDO);
     110                 :   }
     111                 : 
     112            4047 :   mUndoStack->Push(aTransactionItem);
     113                 : 
     114            4047 :   return NS_OK;
     115                 : }
     116                 : 
     117                 : nsresult
     118           15247 : nsTransactionItem::GetTransaction(nsITransaction **aTransaction)
     119                 : {
     120           15247 :   NS_ENSURE_TRUE(aTransaction, NS_ERROR_NULL_POINTER);
     121                 : 
     122           15247 :   NS_IF_ADDREF(*aTransaction = mTransaction);
     123                 : 
     124           15247 :   return NS_OK;
     125                 : }
     126                 : 
     127                 : nsresult
     128               0 : nsTransactionItem::GetIsBatch(bool *aIsBatch)
     129                 : {
     130               0 :   NS_ENSURE_TRUE(aIsBatch, NS_ERROR_NULL_POINTER);
     131                 : 
     132               0 :   *aIsBatch = !mTransaction;
     133                 : 
     134               0 :   return NS_OK;
     135                 : }
     136                 : 
     137                 : nsresult
     138             698 : nsTransactionItem::GetNumberOfChildren(PRInt32 *aNumChildren)
     139                 : {
     140                 :   nsresult result;
     141                 : 
     142             698 :   NS_ENSURE_TRUE(aNumChildren, NS_ERROR_NULL_POINTER);
     143                 : 
     144             698 :   *aNumChildren = 0;
     145                 : 
     146             698 :   PRInt32 ui = 0;
     147             698 :   PRInt32 ri = 0;
     148                 : 
     149             698 :   result = GetNumberOfUndoItems(&ui);
     150                 : 
     151             698 :   NS_ENSURE_SUCCESS(result, result);
     152                 : 
     153             698 :   result = GetNumberOfRedoItems(&ri);
     154                 : 
     155             698 :   NS_ENSURE_SUCCESS(result, result);
     156                 : 
     157             698 :   *aNumChildren = ui + ri;
     158                 : 
     159             698 :   return NS_OK;
     160                 : }
     161                 : 
     162                 : nsresult
     163               0 : nsTransactionItem::GetChild(PRInt32 aIndex, nsTransactionItem **aChild)
     164                 : {
     165               0 :   NS_ENSURE_TRUE(aChild, NS_ERROR_NULL_POINTER);
     166                 : 
     167               0 :   *aChild = 0;
     168                 : 
     169               0 :   PRInt32 numItems = 0;
     170               0 :   nsresult result = GetNumberOfChildren(&numItems);
     171                 : 
     172               0 :   NS_ENSURE_SUCCESS(result, result);
     173                 : 
     174               0 :   if (aIndex < 0 || aIndex >= numItems)
     175               0 :     return NS_ERROR_FAILURE;
     176                 : 
     177                 :   // Children are expected to be in the order they were added,
     178                 :   // so the child first added would be at the bottom of the undo
     179                 :   // stack, or if there are no items on the undo stack, it would
     180                 :   // be at the top of the redo stack.
     181                 : 
     182               0 :   result = GetNumberOfUndoItems(&numItems);
     183                 : 
     184               0 :   NS_ENSURE_SUCCESS(result, result);
     185                 : 
     186               0 :   if (numItems > 0 && aIndex < numItems) {
     187               0 :     NS_ENSURE_TRUE(mUndoStack, NS_ERROR_FAILURE);
     188                 : 
     189               0 :     nsRefPtr<nsTransactionItem> child = mUndoStack->GetItem(aIndex);
     190               0 :     child.forget(aChild);
     191               0 :     return *aChild ? NS_OK : NS_ERROR_FAILURE;
     192                 :   }
     193                 : 
     194                 :   // Adjust the index for the redo stack:
     195                 : 
     196               0 :   aIndex -=  numItems;
     197                 : 
     198               0 :   result = GetNumberOfRedoItems(&numItems);
     199                 : 
     200               0 :   NS_ENSURE_SUCCESS(result, result);
     201                 : 
     202               0 :   NS_ENSURE_TRUE(mRedoStack && numItems != 0 && aIndex < numItems, NS_ERROR_FAILURE);
     203                 : 
     204               0 :   nsRefPtr<nsTransactionItem> child = mRedoStack->GetItem(aIndex);
     205               0 :   child.forget(aChild);
     206               0 :   return *aChild ? NS_OK : NS_ERROR_FAILURE;
     207                 : }
     208                 : 
     209                 : nsresult
     210            4985 : nsTransactionItem::DoTransaction()
     211                 : {
     212            4985 :   if (mTransaction)
     213            4287 :     return mTransaction->DoTransaction();
     214             698 :   return NS_OK;
     215                 : }
     216                 : 
     217                 : nsresult
     218            6228 : nsTransactionItem::UndoTransaction(nsTransactionManager *aTxMgr)
     219                 : {
     220            6228 :   nsresult result = UndoChildren(aTxMgr);
     221                 : 
     222            6228 :   if (NS_FAILED(result)) {
     223               8 :     RecoverFromUndoError(aTxMgr);
     224               8 :     return result;
     225                 :   }
     226                 : 
     227            6220 :   if (!mTransaction)
     228             765 :     return NS_OK;
     229                 : 
     230            5455 :   result = mTransaction->UndoTransaction();
     231                 : 
     232            5455 :   if (NS_FAILED(result)) {
     233               4 :     RecoverFromUndoError(aTxMgr);
     234               4 :     return result;
     235                 :   }
     236                 : 
     237            5451 :   return NS_OK;
     238                 : }
     239                 : 
     240                 : nsresult
     241            6236 : nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr)
     242                 : {
     243           12472 :   nsRefPtr<nsTransactionItem> item;
     244            6236 :   nsresult result = NS_OK;
     245            6236 :   PRInt32 sz = 0;
     246                 : 
     247            6236 :   if (mUndoStack) {
     248            2149 :     if (!mRedoStack && mUndoStack) {
     249            1283 :       mRedoStack = new nsTransactionStack(nsTransactionStack::FOR_REDO);
     250                 :     }
     251                 : 
     252                 :     /* Undo all of the transaction items children! */
     253            2149 :     sz = mUndoStack->GetSize();
     254                 : 
     255           10099 :     while (sz-- > 0) {
     256            5801 :       item = mUndoStack->Peek();
     257                 : 
     258            5801 :       if (!item) {
     259               0 :         return NS_ERROR_FAILURE;
     260                 :       }
     261                 : 
     262           11602 :       nsCOMPtr<nsITransaction> t;
     263                 : 
     264            5801 :       result = item->GetTransaction(getter_AddRefs(t));
     265                 : 
     266            5801 :       if (NS_FAILED(result)) {
     267               0 :         return result;
     268                 :       }
     269                 : 
     270            5801 :       bool doInterrupt = false;
     271                 : 
     272            5801 :       result = aTxMgr->WillUndoNotify(t, &doInterrupt);
     273                 : 
     274            5801 :       if (NS_FAILED(result)) {
     275               0 :         return result;
     276                 :       }
     277                 : 
     278            5801 :       if (doInterrupt) {
     279               0 :         return NS_OK;
     280                 :       }
     281                 : 
     282            5801 :       result = item->UndoTransaction(aTxMgr);
     283                 : 
     284            5801 :       if (NS_SUCCEEDED(result)) {
     285            5793 :         item = mUndoStack->Pop();
     286            5793 :         mRedoStack->Push(item);
     287                 :       }
     288                 : 
     289            5801 :       nsresult result2 = aTxMgr->DidUndoNotify(t, result);
     290                 : 
     291            5801 :       if (NS_SUCCEEDED(result)) {
     292            5793 :         result = result2;
     293                 :       }
     294                 :     }
     295                 :   }
     296                 : 
     297            6236 :   return result;
     298                 : }
     299                 : 
     300                 : nsresult
     301            2947 : nsTransactionItem::RedoTransaction(nsTransactionManager *aTxMgr)
     302                 : {
     303                 :   nsresult result;
     304                 : 
     305            5894 :   nsCOMPtr<nsITransaction> kungfuDeathGrip(mTransaction);
     306            2947 :   if (mTransaction) {
     307            2589 :     result = mTransaction->RedoTransaction();
     308                 : 
     309            2589 :     NS_ENSURE_SUCCESS(result, result);
     310                 :   }
     311                 : 
     312            2943 :   result = RedoChildren(aTxMgr);
     313                 : 
     314            2943 :   if (NS_FAILED(result)) {
     315               8 :     RecoverFromRedoError(aTxMgr);
     316               8 :     return result;
     317                 :   }
     318                 : 
     319            2935 :   return NS_OK;
     320                 : }
     321                 : 
     322                 : nsresult
     323            2955 : nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr)
     324                 : {
     325            5910 :   nsRefPtr<nsTransactionItem> item;
     326            2955 :   nsresult result = NS_OK;
     327                 : 
     328            2955 :   if (!mRedoStack)
     329            1956 :     return NS_OK;
     330                 : 
     331                 :   /* Redo all of the transaction items children! */
     332             999 :   PRInt32 sz = mRedoStack->GetSize();
     333                 : 
     334            4768 :   while (sz-- > 0) {
     335            2770 :     item = mRedoStack->Peek();
     336                 : 
     337            2770 :     if (!item) {
     338               0 :       return NS_ERROR_FAILURE;
     339                 :     }
     340                 : 
     341            5540 :     nsCOMPtr<nsITransaction> t;
     342                 : 
     343            2770 :     result = item->GetTransaction(getter_AddRefs(t));
     344                 : 
     345            2770 :     if (NS_FAILED(result)) {
     346               0 :       return result;
     347                 :     }
     348                 : 
     349            2770 :     bool doInterrupt = false;
     350                 : 
     351            2770 :     result = aTxMgr->WillRedoNotify(t, &doInterrupt);
     352                 : 
     353            2770 :     if (NS_FAILED(result)) {
     354               0 :       return result;
     355                 :     }
     356                 : 
     357            2770 :     if (doInterrupt) {
     358               0 :       return NS_OK;
     359                 :     }
     360                 : 
     361            2770 :     result = item->RedoTransaction(aTxMgr);
     362                 : 
     363            2770 :     if (NS_SUCCEEDED(result)) {
     364            2762 :       item = mRedoStack->Pop();
     365            2762 :       mUndoStack->Push(item);
     366                 :     }
     367                 : 
     368            2770 :     nsresult result2 = aTxMgr->DidUndoNotify(t, result);
     369                 : 
     370            2770 :     if (NS_SUCCEEDED(result)) {
     371            2762 :       result = result2;
     372                 :     }
     373                 :   }
     374                 : 
     375             999 :   return result;
     376                 : }
     377                 : 
     378                 : nsresult
     379             698 : nsTransactionItem::GetNumberOfUndoItems(PRInt32 *aNumItems)
     380                 : {
     381             698 :   NS_ENSURE_TRUE(aNumItems, NS_ERROR_NULL_POINTER);
     382                 : 
     383             698 :   if (!mUndoStack) {
     384             110 :     *aNumItems = 0;
     385             110 :     return NS_OK;
     386                 :   }
     387                 : 
     388             588 :   *aNumItems = mUndoStack->GetSize();
     389             588 :   return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
     390                 : }
     391                 : 
     392                 : nsresult
     393             698 : nsTransactionItem::GetNumberOfRedoItems(PRInt32 *aNumItems)
     394                 : {
     395             698 :   NS_ENSURE_TRUE(aNumItems, NS_ERROR_NULL_POINTER);
     396                 : 
     397             698 :   if (!mRedoStack) {
     398             698 :     *aNumItems = 0;
     399             698 :     return NS_OK;
     400                 :   }
     401                 : 
     402               0 :   *aNumItems = mRedoStack->GetSize();
     403               0 :   return *aNumItems ? NS_OK : NS_ERROR_FAILURE;
     404                 : }
     405                 : 
     406                 : nsresult
     407              12 : nsTransactionItem::RecoverFromUndoError(nsTransactionManager *aTxMgr)
     408                 : {
     409                 :   //
     410                 :   // If this method gets called, we never got to the point where we
     411                 :   // successfully called UndoTransaction() for the transaction item itself.
     412                 :   // Just redo any children that successfully called undo!
     413                 :   //
     414              12 :   return RedoChildren(aTxMgr);
     415                 : }
     416                 : 
     417                 : nsresult
     418               8 : nsTransactionItem::RecoverFromRedoError(nsTransactionManager *aTxMgr)
     419                 : {
     420                 :   //
     421                 :   // If this method gets called, we already successfully called
     422                 :   // RedoTransaction() for the transaction item itself. Undo all
     423                 :   // the children that successfully called RedoTransaction(),
     424                 :   // then undo the transaction item itself.
     425                 :   //
     426                 : 
     427                 :   nsresult result;
     428                 : 
     429               8 :   result = UndoChildren(aTxMgr);
     430                 : 
     431               8 :   if (NS_FAILED(result)) {
     432               0 :     return result;
     433                 :   }
     434                 : 
     435               8 :   if (!mTransaction)
     436               4 :     return NS_OK;
     437                 : 
     438               4 :   return mTransaction->UndoTransaction();
     439            4392 : }
     440                 : 

Generated by: LCOV version 1.7