Back to index

lightning-sunbird  0.9+nobinonly
SetDocTitleTxn.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  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "SetDocTitleTxn.h"
00040 #include "nsIDOMNode.h"
00041 #include "nsIDOMNodeList.h"
00042 #include "nsIDOMDocument.h"
00043 #include "nsIDOMHTMLDocument.h"
00044 #include "nsIDOMText.h"
00045 #include "nsIDOMElement.h"
00046 
00047 // note that aEditor is not refcounted
00048 SetDocTitleTxn::SetDocTitleTxn()
00049   : EditTxn()
00050 , mIsTransient(PR_FALSE)
00051 {
00052 }
00053 
00054 NS_IMETHODIMP SetDocTitleTxn::Init(nsIHTMLEditor *aEditor,
00055                                    const nsAString *aValue)
00056 
00057 {
00058   NS_ASSERTION(aEditor && aValue, "null args");
00059   if (!aEditor || !aValue) { return NS_ERROR_NULL_POINTER; }
00060 
00061   mEditor = aEditor;
00062   mValue = *aValue;
00063 
00064   return NS_OK;
00065 }
00066 
00067 SetDocTitleTxn::~SetDocTitleTxn()
00068 {
00069 }
00070 
00071 NS_IMETHODIMP SetDocTitleTxn::DoTransaction(void)
00072 {
00073   nsresult res = SetDomTitle(mValue);
00074   if (NS_FAILED(res)) return res;
00075 
00076   return SetDocTitle(mValue);
00077 }
00078 
00079 NS_IMETHODIMP SetDocTitleTxn::UndoTransaction(void)
00080 {
00081   return SetDocTitle(mUndoValue);
00082 }
00083 
00084 NS_IMETHODIMP SetDocTitleTxn::RedoTransaction(void)
00085 {
00086   return SetDocTitle(mValue);
00087 }
00088 
00089 nsresult SetDocTitleTxn::SetDocTitle(const nsAString& aTitle)
00090 {
00091   NS_ASSERTION(mEditor, "bad state");
00092   if (!mEditor) return NS_ERROR_NOT_INITIALIZED;
00093 
00094   nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
00095   if (!editor) return NS_ERROR_FAILURE;
00096   nsCOMPtr<nsIDOMDocument> domDoc;
00097   nsresult rv = editor->GetDocument(getter_AddRefs(domDoc));
00098   if (NS_FAILED(rv)) return rv;
00099   nsCOMPtr<nsIDOMHTMLDocument> HTMLDoc = do_QueryInterface(domDoc);
00100   if (!HTMLDoc) return NS_ERROR_FAILURE;
00101 
00102   return HTMLDoc->SetTitle(aTitle);
00103 }
00104 
00105 nsresult SetDocTitleTxn::SetDomTitle(const nsAString& aTitle)
00106 {
00107   nsCOMPtr<nsIEditor> editor = do_QueryInterface(mEditor);
00108   if (!editor) return NS_ERROR_FAILURE;
00109   nsCOMPtr<nsIDOMDocument> domDoc;
00110   nsresult res = editor->GetDocument(getter_AddRefs(domDoc));
00111   if (!domDoc) return NS_ERROR_FAILURE;
00112 
00113   nsCOMPtr<nsIDOMNodeList> titleList;
00114   res = domDoc->GetElementsByTagName(NS_LITERAL_STRING("title"), getter_AddRefs(titleList));
00115   if (NS_FAILED(res)) return res;
00116 
00117   // First assume we will NOT really do anything
00118   // (transaction will not be pushed on stack)
00119   mIsTransient = PR_TRUE;
00120 
00121   nsCOMPtr<nsIDOMNode>titleNode;
00122   if(titleList)
00123   {
00124     res = titleList->Item(0, getter_AddRefs(titleNode));
00125     if (NS_FAILED(res)) return res;
00126     if (titleNode)
00127     {
00128       // Delete existing child textnode of title node
00129       // (Note: all contents under a TITLE node are always in a single text node)
00130       nsCOMPtr<nsIDOMNode> child;
00131       res = titleNode->GetFirstChild(getter_AddRefs(child));
00132       if(NS_FAILED(res)) return res;
00133       if(child)
00134       {
00135         // Save current text as the undo value
00136         nsCOMPtr<nsIDOMCharacterData> textNode = do_QueryInterface(child);
00137         if(textNode)
00138         {
00139           textNode->GetData(mUndoValue);
00140 
00141           // If title text is identical to what already exists,
00142           // quit now (mIsTransient is now TRUE)
00143           if (mUndoValue == aTitle)
00144             return NS_OK;
00145         }
00146         res = editor->DeleteNode(child);
00147         if(NS_FAILED(res)) return res;
00148       }
00149     }
00150   }
00151 
00152   // We didn't return above, thus we really will be changing the title
00153   mIsTransient = PR_FALSE;
00154 
00155   // Get the <HEAD> node, create a <TITLE> and insert it under the HEAD
00156   nsCOMPtr<nsIDOMNodeList> headList;
00157   res = domDoc->GetElementsByTagName(NS_LITERAL_STRING("head"),getter_AddRefs(headList));
00158   if (NS_FAILED(res)) return res;
00159   if (!headList) return NS_ERROR_FAILURE;
00160   
00161   nsCOMPtr<nsIDOMNode>headNode;
00162   headList->Item(0, getter_AddRefs(headNode));
00163   if (!headNode) return NS_ERROR_FAILURE;
00164 
00165   PRBool   newTitleNode = PR_FALSE;
00166   PRUint32 newTitleIndex = 0;
00167 
00168   if (!titleNode)
00169   {
00170     // Didn't find one above: Create a new one
00171     nsCOMPtr<nsIDOMElement>titleElement;
00172     res = domDoc->CreateElement(NS_LITERAL_STRING("title"), getter_AddRefs(titleElement));
00173     if (NS_FAILED(res)) return res;
00174     if (!titleElement) return NS_ERROR_FAILURE;
00175 
00176     titleNode = do_QueryInterface(titleElement);
00177     newTitleNode = PR_TRUE;
00178 
00179     // Get index so we append new title node 
00180     // after all existing HEAD children
00181     nsCOMPtr<nsIDOMNodeList> children;
00182     res = headNode->GetChildNodes(getter_AddRefs(children));
00183     if (NS_FAILED(res)) return res;
00184     if (children)
00185       children->GetLength(&newTitleIndex);
00186   }
00187 
00188   // Append a text node under the TITLE
00189   //  only if the title text isn't empty
00190   if (titleNode && !aTitle.IsEmpty())
00191   {
00192     nsCOMPtr<nsIDOMText> textNode;
00193     res = domDoc->CreateTextNode(aTitle, getter_AddRefs(textNode));
00194     if (NS_FAILED(res)) return res;
00195     nsCOMPtr<nsIDOMNode> newNode = do_QueryInterface(textNode);
00196     if (!newNode) return NS_ERROR_FAILURE;
00197 
00198     if (newTitleNode)
00199     {
00200       // Not undoable: We will insert newTitleNode below
00201       nsCOMPtr<nsIDOMNode> resultNode;
00202       res = titleNode->AppendChild(newNode, getter_AddRefs(resultNode));
00203     } 
00204     else 
00205     {
00206       // This is an undoable transaction
00207       res = editor->InsertNode(newNode, titleNode, 0);
00208     }
00209     if (NS_FAILED(res)) return res;
00210   }
00211 
00212   if (newTitleNode)
00213   {
00214     // Undoable transaction to insert title+text together
00215     res = editor->InsertNode(titleNode, headNode, newTitleIndex);
00216   }
00217   return res;
00218 }
00219 
00220 NS_IMETHODIMP SetDocTitleTxn::Merge(nsITransaction *aTransaction, PRBool *aDidMerge)
00221 {
00222   if (aDidMerge)
00223     *aDidMerge = PR_FALSE;
00224   return NS_OK;
00225 }
00226 
00227 NS_IMETHODIMP SetDocTitleTxn::GetTxnDescription(nsAString& aString)
00228 {
00229   aString.AssignLiteral("SetDocTitleTxn: ");
00230   aString += mValue;
00231   return NS_OK;
00232 }
00233 
00234 NS_IMETHODIMP SetDocTitleTxn::GetIsTransient(PRBool *aIsTransient)
00235 {
00236   if (!aIsTransient) return NS_ERROR_NULL_POINTER;  
00237   *aIsTransient = mIsTransient;
00238   return NS_OK;
00239 }
00240