Back to index

lightning-sunbird  0.9+nobinonly
SplitElementTxn.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "SplitElementTxn.h"
00039 #include "nsEditor.h"
00040 #include "nsIDOMNode.h"
00041 #include "nsISelection.h"
00042 #include "nsIDOMCharacterData.h"
00043 
00044 #ifdef NS_DEBUG
00045 static PRBool gNoisy = PR_FALSE;
00046 #endif
00047 
00048 
00049 // note that aEditor is not refcounted
00050 SplitElementTxn::SplitElementTxn()
00051   : EditTxn()
00052 {
00053 }
00054 
00055 NS_IMETHODIMP SplitElementTxn::Init(nsEditor   *aEditor,
00056                                     nsIDOMNode *aNode,
00057                                     PRInt32     aOffset)
00058 {
00059   NS_ASSERTION(aEditor && aNode, "bad args");
00060   if (!aEditor || !aNode) { return NS_ERROR_NOT_INITIALIZED; }
00061 
00062   mEditor = aEditor;
00063   mExistingRightNode = do_QueryInterface(aNode);
00064   mOffset = aOffset;
00065   return NS_OK;
00066 }
00067 
00068 SplitElementTxn::~SplitElementTxn()
00069 {
00070 }
00071 
00072 NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
00073 {
00074 #ifdef NS_DEBUG
00075   if (gNoisy) { printf("%p Do Split of node %p offset %d\n", this, mExistingRightNode.get(), mOffset); }
00076 #endif
00077 
00078   NS_ASSERTION(mExistingRightNode && mEditor, "bad state");
00079   if (!mExistingRightNode || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
00080 
00081   // create a new node
00082   nsresult result = mExistingRightNode->CloneNode(PR_FALSE, getter_AddRefs(mNewLeftNode));
00083   NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element.");
00084   if (NS_FAILED(result)) return result;
00085   if (!mNewLeftNode) return NS_ERROR_NULL_POINTER;
00086   mEditor->MarkNodeDirty(mExistingRightNode);
00087 
00088 #ifdef NS_DEBUG
00089   if (gNoisy) { printf("  created left node = %p\n", mNewLeftNode.get()); }
00090 #endif
00091 
00092   // get the parent node
00093   result = mExistingRightNode->GetParentNode(getter_AddRefs(mParent));
00094   if (NS_FAILED(result)) return result;
00095   if (!mParent) return NS_ERROR_NULL_POINTER;
00096 
00097   // insert the new node
00098   result = mEditor->SplitNodeImpl(mExistingRightNode, mOffset, mNewLeftNode, mParent);
00099   if (NS_SUCCEEDED(result) && mNewLeftNode)
00100   {
00101     nsCOMPtr<nsISelection>selection;
00102     mEditor->GetSelection(getter_AddRefs(selection));
00103     if (NS_FAILED(result)) return result;
00104     if (!selection) return NS_ERROR_NULL_POINTER;
00105     result = selection->Collapse(mNewLeftNode, mOffset);
00106   }
00107   else {
00108     result = NS_ERROR_NOT_IMPLEMENTED;
00109   }
00110   return result;
00111 }
00112 
00113 NS_IMETHODIMP SplitElementTxn::UndoTransaction(void)
00114 {
00115 #ifdef NS_DEBUG
00116   if (gNoisy) { 
00117     printf("%p Undo Split of existing node %p and new node %p offset %d\n", 
00118            this, mExistingRightNode.get(), mNewLeftNode.get(), mOffset); 
00119   }
00120 #endif
00121 
00122   NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
00123   if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
00124     return NS_ERROR_NOT_INITIALIZED;
00125   }
00126 
00127   // this assumes Do inserted the new node in front of the prior existing node
00128   nsresult result = mEditor->JoinNodesImpl(mExistingRightNode, mNewLeftNode, mParent, PR_FALSE);
00129 #ifdef NS_DEBUG
00130   if (gNoisy) 
00131   { 
00132     printf("** after join left child node %p into right node %p\n", mNewLeftNode.get(), mExistingRightNode.get());
00133     if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
00134   }
00135   if (NS_SUCCEEDED(result))
00136   {
00137     if (gNoisy) { printf("  left node = %p removed\n", mNewLeftNode.get()); }
00138   }
00139 #endif
00140 
00141   return result;
00142 }
00143 
00144 /* redo cannot simply resplit the right node, because subsequent transactions
00145  * on the redo stack may depend on the left node existing in its previous state.
00146  */
00147 NS_IMETHODIMP SplitElementTxn::RedoTransaction(void)
00148 {
00149   NS_ASSERTION(mEditor && mExistingRightNode && mNewLeftNode && mParent, "bad state");
00150   if (!mEditor || !mExistingRightNode || !mNewLeftNode || !mParent) {
00151     return NS_ERROR_NOT_INITIALIZED;
00152   }
00153 
00154 #ifdef NS_DEBUG
00155   if (gNoisy) { 
00156     printf("%p Redo Split of existing node %p and new node %p offset %d\n", 
00157            this, mExistingRightNode.get(), mNewLeftNode.get(), mOffset); 
00158     if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
00159   }
00160 #endif
00161 
00162   nsresult result;
00163   nsCOMPtr<nsIDOMNode>resultNode;
00164   // first, massage the existing node so it is in its post-split state
00165   nsCOMPtr<nsIDOMCharacterData>rightNodeAsText = do_QueryInterface(mExistingRightNode);
00166   if (rightNodeAsText)
00167   {
00168     result = rightNodeAsText->DeleteData(0, mOffset);
00169 #ifdef NS_DEBUG
00170     if (gNoisy) 
00171     { 
00172       printf("** after delete of text in right text node %p offset %d\n", rightNodeAsText.get(), mOffset);
00173       mEditor->DebugDumpContent();  // DEBUG
00174     }
00175 #endif
00176   }
00177   else
00178   {
00179     nsCOMPtr<nsIDOMNode>child;
00180     nsCOMPtr<nsIDOMNode>nextSibling;
00181     result = mExistingRightNode->GetFirstChild(getter_AddRefs(child));
00182     PRInt32 i;
00183     for (i=0; i<mOffset; i++)
00184     {
00185       if (NS_FAILED(result)) {return result;}
00186       if (!child) {return NS_ERROR_NULL_POINTER;}
00187       child->GetNextSibling(getter_AddRefs(nextSibling));
00188       result = mExistingRightNode->RemoveChild(child, getter_AddRefs(resultNode));
00189       if (NS_SUCCEEDED(result)) 
00190       {
00191         result = mNewLeftNode->AppendChild(child, getter_AddRefs(resultNode));
00192 #ifdef NS_DEBUG
00193         if (gNoisy) 
00194         { 
00195           printf("** move child node %p from right node %p to left node %p\n", child.get(), mExistingRightNode.get(), mNewLeftNode.get());
00196           if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
00197         }
00198 #endif
00199       }
00200       child = do_QueryInterface(nextSibling);
00201     }
00202   }
00203   // second, re-insert the left node into the tree 
00204   result = mParent->InsertBefore(mNewLeftNode, mExistingRightNode, getter_AddRefs(resultNode));
00205 #ifdef NS_DEBUG
00206   if (gNoisy) 
00207   { 
00208     printf("** reinsert left child node %p before right node %p\n", mNewLeftNode.get(), mExistingRightNode.get());
00209     if (gNoisy) {mEditor->DebugDumpContent(); } // DEBUG
00210   }
00211 #endif
00212   return result;
00213 }
00214 
00215 
00216 NS_IMETHODIMP SplitElementTxn::Merge(nsITransaction *aTransaction, PRBool *aDidMerge)
00217 {
00218   if (aDidMerge)
00219     *aDidMerge = PR_FALSE;
00220   return NS_OK;
00221 }
00222 
00223 NS_IMETHODIMP SplitElementTxn::GetTxnDescription(nsAString& aString)
00224 {
00225   aString.AssignLiteral("SplitElementTxn");
00226   return NS_OK;
00227 }
00228 
00229 NS_IMETHODIMP SplitElementTxn::GetNewNode(nsIDOMNode **aNewNode)
00230 {
00231   if (!aNewNode)
00232     return NS_ERROR_NULL_POINTER;
00233   if (!mNewLeftNode)
00234     return NS_ERROR_NOT_INITIALIZED;
00235   *aNewNode = mNewLeftNode;
00236   NS_ADDREF(*aNewNode);
00237   return NS_OK;
00238 }