Back to index

lightning-sunbird  0.9+nobinonly
CreateElementTxn.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 "CreateElementTxn.h"
00039 #include "nsEditor.h"
00040 #include "nsIDOMDocument.h"
00041 #include "nsIDOMNodeList.h"
00042 #include "nsISelection.h"
00043 #include "nsIDOMText.h"
00044 #include "nsIDOMElement.h"
00045 #include "nsReadableUtils.h"
00046 
00047 //included for new nsEditor::CreateContent()
00048 #include "nsIContent.h"
00049 
00050 #ifdef NS_DEBUG
00051 static PRBool gNoisy = PR_FALSE;
00052 #endif
00053 
00054 CreateElementTxn::CreateElementTxn()
00055   : EditTxn()
00056 {
00057 }
00058 
00059 NS_IMETHODIMP CreateElementTxn::Init(nsEditor      *aEditor,
00060                                      const nsAString &aTag,
00061                                      nsIDOMNode     *aParent,
00062                                      PRUint32        aOffsetInParent)
00063 {
00064   NS_ASSERTION(aEditor&&aParent, "null args");
00065   if (!aEditor || !aParent) { return NS_ERROR_NULL_POINTER; }
00066 
00067   mEditor = aEditor;
00068   mTag = aTag;
00069   mParent = do_QueryInterface(aParent);
00070   mOffsetInParent = aOffsetInParent;
00071 #ifdef NS_DEBUG
00072   {
00073     nsCOMPtr<nsIDOMNodeList> testChildNodes;
00074     nsresult testResult = mParent->GetChildNodes(getter_AddRefs(testChildNodes));
00075     NS_ASSERTION(testChildNodes, "bad parent type, can't have children.");
00076     NS_ASSERTION(NS_SUCCEEDED(testResult), "bad result.");
00077   }
00078 #endif
00079   return NS_OK;
00080 }
00081 
00082 
00083 CreateElementTxn::~CreateElementTxn()
00084 {
00085 }
00086 
00087 NS_IMETHODIMP CreateElementTxn::DoTransaction(void)
00088 {
00089 #ifdef NS_DEBUG
00090   if (gNoisy)
00091   {
00092     char* nodename = ToNewCString(mTag);
00093     printf("Do Create Element parent = %p <%s>, offset = %d\n", 
00094            mParent.get(), nodename, mOffsetInParent);
00095     nsMemory::Free(nodename);
00096   }
00097 #endif
00098 
00099   NS_ASSERTION(mEditor && mParent, "bad state");
00100   if (!mEditor || !mParent) return NS_ERROR_NOT_INITIALIZED;
00101   // create a new node
00102   nsAutoString textNodeTag;
00103   nsresult result = nsEditor::GetTextNodeTag(textNodeTag);
00104   if (NS_FAILED(result)) { return result; }
00105 
00106   if (textNodeTag == mTag) 
00107   {
00108     nsCOMPtr<nsIDOMDocument>doc;
00109     result = mEditor->GetDocument(getter_AddRefs(doc));
00110     if (NS_FAILED(result)) return result;
00111     if (!doc) return NS_ERROR_NULL_POINTER;
00112 
00113     const nsString stringData;
00114     nsCOMPtr<nsIDOMText>newTextNode;
00115     result = doc->CreateTextNode(stringData, getter_AddRefs(newTextNode));
00116     if (NS_FAILED(result)) return result;
00117     if (!newTextNode) return NS_ERROR_NULL_POINTER;
00118     mNewNode = do_QueryInterface(newTextNode);
00119   }
00120   else 
00121   {
00122     nsCOMPtr<nsIContent> newContent;
00123  
00124     //new call to use instead to get proper HTML element, bug# 39919
00125     result = mEditor->CreateHTMLContent(mTag, getter_AddRefs(newContent));
00126     if (NS_FAILED(result)) return result;
00127     nsCOMPtr<nsIDOMElement>newElement = do_QueryInterface(newContent);
00128     if (!newElement) return NS_ERROR_NULL_POINTER;
00129     mNewNode = do_QueryInterface(newElement);
00130     // Try to insert formatting whitespace for the new node:
00131     mEditor->MarkNodeDirty(mNewNode);
00132   }
00133   NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewNode)), "could not create element.");
00134   if (!mNewNode) return NS_ERROR_NULL_POINTER;
00135 
00136 #ifdef NS_DEBUG
00137   if (gNoisy) { printf("  newNode = %p\n", mNewNode.get()); }
00138 #endif
00139 
00140   // insert the new node
00141   nsCOMPtr<nsIDOMNode> resultNode;
00142   if (CreateElementTxn::eAppend==(PRInt32)mOffsetInParent)
00143   {
00144     result = mParent->AppendChild(mNewNode, getter_AddRefs(resultNode));
00145   }
00146   else
00147   {
00148     nsCOMPtr<nsIDOMNodeList> childNodes;
00149     result = mParent->GetChildNodes(getter_AddRefs(childNodes));
00150     if ((NS_SUCCEEDED(result)) && (childNodes))
00151     {
00152       PRUint32 count;
00153       childNodes->GetLength(&count);
00154       if (mOffsetInParent>count)
00155         mOffsetInParent = count;
00156       result = childNodes->Item(mOffsetInParent, getter_AddRefs(mRefNode));
00157       if (NS_FAILED(result)) return result; // note, it's ok for mRefNode to be null.  that means append
00158 
00159       result = mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
00160       if (NS_FAILED(result)) return result; 
00161 
00162       // only set selection to insertion point if editor gives permission
00163       PRBool bAdjustSelection;
00164       mEditor->ShouldTxnSetSelection(&bAdjustSelection);
00165       if (bAdjustSelection)
00166       {
00167         nsCOMPtr<nsISelection> selection;
00168         result = mEditor->GetSelection(getter_AddRefs(selection));
00169         if (NS_FAILED(result)) return result;
00170         if (!selection) return NS_ERROR_NULL_POINTER;
00171 
00172         PRInt32 offset=0;
00173         result = nsEditor::GetChildOffset(mNewNode, mParent, offset);
00174         if (NS_FAILED(result)) return result;
00175 
00176         result = selection->Collapse(mParent, offset+1);
00177         NS_ASSERTION((NS_SUCCEEDED(result)), "selection could not be collapsed after insert.");
00178        }
00179       else
00180       {
00181         // do nothing - dom range gravity will adjust selection
00182       }
00183     }
00184   }
00185   return result;
00186 }
00187 
00188 NS_IMETHODIMP CreateElementTxn::UndoTransaction(void)
00189 {
00190 #ifdef NS_DEBUG
00191   if (gNoisy) { printf("Undo Create Element, mParent = %p, node = %p\n",
00192                         mParent.get(), mNewNode.get()); }
00193 #endif
00194 
00195   NS_ASSERTION(mEditor && mParent, "bad state");
00196   if (!mEditor || !mParent) return NS_ERROR_NOT_INITIALIZED;
00197 
00198   nsCOMPtr<nsIDOMNode> resultNode;
00199   return mParent->RemoveChild(mNewNode, getter_AddRefs(resultNode));
00200 }
00201 
00202 NS_IMETHODIMP CreateElementTxn::RedoTransaction(void)
00203 {
00204 #ifdef NS_DEBUG
00205   if (gNoisy) { printf("Redo Create Element\n"); }
00206 #endif
00207 
00208   NS_ASSERTION(mEditor && mParent, "bad state");
00209   if (!mEditor || !mParent) return NS_ERROR_NOT_INITIALIZED;
00210 
00211   // first, reset mNewNode so it has no attributes or content
00212   nsCOMPtr<nsIDOMCharacterData>nodeAsText = do_QueryInterface(mNewNode);
00213   if (nodeAsText)
00214   {
00215     nsAutoString nullString;
00216     nodeAsText->SetData(nullString);
00217   }
00218   
00219   // now, reinsert mNewNode
00220   nsCOMPtr<nsIDOMNode> resultNode;
00221   return mParent->InsertBefore(mNewNode, mRefNode, getter_AddRefs(resultNode));
00222 }
00223 
00224 NS_IMETHODIMP CreateElementTxn::Merge(nsITransaction *aTransaction, PRBool *aDidMerge)
00225 {
00226   if (aDidMerge)
00227     *aDidMerge=PR_FALSE;
00228   return NS_OK;
00229 }
00230 
00231 NS_IMETHODIMP CreateElementTxn::GetTxnDescription(nsAString& aString)
00232 {
00233   aString.AssignLiteral("CreateElementTxn: ");
00234   aString += mTag;
00235   return NS_OK;
00236 }
00237 
00238 NS_IMETHODIMP CreateElementTxn::GetNewNode(nsIDOMNode **aNewNode)
00239 {
00240   if (!aNewNode)
00241     return NS_ERROR_NULL_POINTER;
00242   if (!mNewNode)
00243     return NS_ERROR_NOT_INITIALIZED;
00244   *aNewNode = mNewNode;
00245   NS_ADDREF(*aNewNode);
00246   return NS_OK;
00247 }