~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/editor/libeditor/base/InsertElementTxn.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
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-1999
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *
 
24
 *
 
25
 * Alternatively, the contents of this file may be used under the terms of
 
26
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
27
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
29
 * of those above. If you wish to allow use of your version of this file only
 
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
31
 * use your version of this file under the terms of the NPL, indicate your
 
32
 * decision by deleting the provisions above and replace them with the notice
 
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
34
 * the provisions above, a recipient may use your version of this file under
 
35
 * the terms of any one of the NPL, the GPL or the LGPL.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
 
 
39
#include "InsertElementTxn.h"
 
40
#include "nsISelection.h"
 
41
#include "nsIContent.h"
 
42
#include "nsIDOMNodeList.h"
 
43
#include "nsReadableUtils.h"
 
44
#include "nsIDOMElement.h"
 
45
#include "nsIDOMDocument.h"
 
46
#include "nsIDOMNamedNodeMap.h"
 
47
#include "nsIDOMAttr.h"
 
48
#include "nsReadableUtils.h"
 
49
#include "nsUnicharUtils.h"
 
50
 
 
51
#define NVU_NS NS_LITERAL_STRING("http://disruptive-innovations.com/zoo/nvu")
 
52
 
 
53
#ifdef NS_DEBUG
 
54
static PRBool gNoisy = PR_FALSE;
 
55
#endif
 
56
 
 
57
 
 
58
InsertElementTxn::InsertElementTxn()
 
59
  : EditTxn()
 
60
{
 
61
}
 
62
 
 
63
NS_IMETHODIMP InsertElementTxn::Init(nsIDOMNode *aNode,
 
64
                                     nsIDOMNode *aParent,
 
65
                                     PRInt32     aOffset,
 
66
                                     nsIEditor  *aEditor)
 
67
{
 
68
  NS_ASSERTION(aNode && aParent && aEditor, "bad arg");
 
69
  if (!aNode || !aParent || !aEditor)
 
70
    return NS_ERROR_NULL_POINTER;
 
71
 
 
72
  mNode = do_QueryInterface(aNode);
 
73
  mParent = do_QueryInterface(aParent);
 
74
  mOffset = aOffset;
 
75
  mEditor = aEditor;
 
76
  if (!mNode || !mParent || !mEditor)
 
77
    return NS_ERROR_INVALID_ARG;
 
78
  return NS_OK;
 
79
}
 
80
 
 
81
 
 
82
InsertElementTxn::~InsertElementTxn()
 
83
{
 
84
}
 
85
 
 
86
NS_IMETHODIMP InsertElementTxn::DoTransaction(void)
 
87
{
 
88
#ifdef NS_DEBUG
 
89
  if (gNoisy) 
 
90
  { 
 
91
    nsCOMPtr<nsIContent>nodeAsContent = do_QueryInterface(mNode);
 
92
    nsCOMPtr<nsIContent>parentAsContent = do_QueryInterface(mParent);
 
93
    nsString namestr;
 
94
    mNode->GetNodeName(namestr);
 
95
    char* nodename = ToNewCString(namestr);
 
96
    printf("%p Do Insert Element of %p <%s> into parent %p at offset %d\n", 
 
97
           this, nodeAsContent.get(), nodename,
 
98
           parentAsContent.get(), mOffset); 
 
99
    nsMemory::Free(nodename);
 
100
  }
 
101
#endif
 
102
 
 
103
  if (!mNode || !mParent) return NS_ERROR_NOT_INITIALIZED;
 
104
 
 
105
  nsCOMPtr<nsIDOMNodeList> childNodes;
 
106
  nsresult result = mParent->GetChildNodes(getter_AddRefs(childNodes));
 
107
  if (NS_FAILED(result)) return result;
 
108
  nsCOMPtr<nsIDOMNode>refNode;
 
109
  if (childNodes)
 
110
  {
 
111
    PRUint32 count;
 
112
    childNodes->GetLength(&count);
 
113
    if (mOffset>(PRInt32)count) mOffset = count;
 
114
    // -1 is sentinel value meaning "append at end"
 
115
    if (mOffset == -1) mOffset = count;
 
116
    result = childNodes->Item(mOffset, getter_AddRefs(refNode));
 
117
    if (NS_FAILED(result)) return result; 
 
118
    // note, it's ok for mRefNode to be null.  that means append
 
119
  }
 
120
 
 
121
  nsCOMPtr<nsIDOMElement> elt = do_QueryInterface(mNode);
 
122
  if (elt)
 
123
  {
 
124
    nsAutoString xmlns;
 
125
    result = elt->GetAttribute(NS_LITERAL_STRING("xmlns"), xmlns);
 
126
    if (NS_SUCCEEDED(result) && xmlns.Equals(NVU_NS))
 
127
    {
 
128
      nsCOMPtr<nsIDOMDocument> domDoc;
 
129
      result = elt->GetOwnerDocument(getter_AddRefs(domDoc));
 
130
      if (NS_SUCCEEDED(result) && domDoc)
 
131
      {
 
132
        nsAutoString tagName;
 
133
        mNode->GetNodeName(tagName);
 
134
        ToLowerCase(tagName);
 
135
 
 
136
        nsCOMPtr<nsIDOMElement> newElement;
 
137
        result = domDoc->CreateElementNS(NVU_NS, tagName, getter_AddRefs(newElement));
 
138
        nsCOMPtr<nsIDOMNode> newNode = do_QueryInterface(newElement);
 
139
        if (NS_FAILED(result))
 
140
          return result;
 
141
        // move all children
 
142
        nsCOMPtr<nsIDOMNode> child;
 
143
        result = mNode->GetFirstChild(getter_AddRefs(child));
 
144
        while (child)
 
145
        {
 
146
          nsCOMPtr<nsIDOMNode> tmp, junk;
 
147
          result = child->GetNextSibling(getter_AddRefs(tmp));
 
148
          newNode->AppendChild(child, getter_AddRefs(junk));
 
149
          child = tmp;
 
150
        }
 
151
        // and copy all attributes
 
152
        nsCOMPtr<nsIDOMNamedNodeMap> sourceAttributes;
 
153
        elt->GetAttributes(getter_AddRefs(sourceAttributes));
 
154
        nsCOMPtr<nsIDOMNamedNodeMap> destAttributes;
 
155
        newElement->GetAttributes(getter_AddRefs(destAttributes));
 
156
        if (!sourceAttributes || !destAttributes)
 
157
          return NS_ERROR_FAILURE;
 
158
 
 
159
        PRUint32 sourceCount;
 
160
        sourceAttributes->GetLength(&sourceCount);
 
161
        PRUint32 i, destCount;
 
162
        destAttributes->GetLength(&destCount);
 
163
        nsCOMPtr<nsIDOMNode> attrNode;
 
164
 
 
165
        for (i = 0; i < sourceCount; i++)
 
166
        {
 
167
          if( NS_SUCCEEDED(sourceAttributes->Item(i, getter_AddRefs(attrNode))) && attrNode)
 
168
          {
 
169
            nsCOMPtr<nsIDOMAttr> sourceAttribute = do_QueryInterface(attrNode);
 
170
            if (sourceAttribute)
 
171
            {
 
172
              nsAutoString sourceAttrName;
 
173
              if (NS_SUCCEEDED(sourceAttribute->GetName(sourceAttrName)))
 
174
              {
 
175
                nsAutoString sourceAttrValue;
 
176
                if (NS_SUCCEEDED(sourceAttribute->GetValue(sourceAttrValue)))
 
177
                {
 
178
                  newElement->SetAttribute(sourceAttrName, sourceAttrValue);
 
179
                } else {
 
180
                  // do we ever end here ?...
 
181
                }
 
182
              }        
 
183
            }
 
184
          }
 
185
        }
 
186
 
 
187
        mNode = newNode;
 
188
        newNode = nsnull;
 
189
      }
 
190
    }
 
191
  }
 
192
 
 
193
  mEditor->MarkNodeDirty(mNode);
 
194
 
 
195
  nsCOMPtr<nsIDOMNode> resultNode;
 
196
  result = mParent->InsertBefore(mNode, refNode, getter_AddRefs(resultNode));
 
197
  if (NS_FAILED(result)) return result;
 
198
  if (!resultNode) return NS_ERROR_NULL_POINTER;
 
199
 
 
200
  // only set selection to insertion point if editor gives permission
 
201
  PRBool bAdjustSelection;
 
202
  mEditor->ShouldTxnSetSelection(&bAdjustSelection);
 
203
  if (bAdjustSelection)
 
204
  {
 
205
    nsCOMPtr<nsISelection> selection;
 
206
    result = mEditor->GetSelection(getter_AddRefs(selection));
 
207
    if (NS_FAILED(result)) return result;
 
208
    if (!selection) return NS_ERROR_NULL_POINTER;
 
209
    // place the selection just after the inserted element
 
210
    selection->Collapse(mParent, mOffset+1);
 
211
  }
 
212
  else
 
213
  {
 
214
    // do nothing - dom range gravity will adjust selection
 
215
  }
 
216
  return result;
 
217
}
 
218
 
 
219
NS_IMETHODIMP InsertElementTxn::UndoTransaction(void)
 
220
{
 
221
#ifdef NS_DEBUG
 
222
  if (gNoisy) { printf("%p Undo Insert Element of %p into parent %p at offset %d\n", 
 
223
                       this, mNode.get(), mParent.get(), mOffset); }
 
224
#endif
 
225
 
 
226
  if (!mNode || !mParent) return NS_ERROR_NOT_INITIALIZED;
 
227
 
 
228
  nsCOMPtr<nsIDOMNode> resultNode;
 
229
  return mParent->RemoveChild(mNode, getter_AddRefs(resultNode));
 
230
}
 
231
 
 
232
NS_IMETHODIMP InsertElementTxn::Merge(nsITransaction *aTransaction, PRBool *aDidMerge)
 
233
{
 
234
  if (aDidMerge)
 
235
    *aDidMerge = PR_FALSE;
 
236
  return NS_OK;
 
237
}
 
238
 
 
239
NS_IMETHODIMP InsertElementTxn::GetTxnDescription(nsAString& aString)
 
240
{
 
241
  aString.Assign(NS_LITERAL_STRING("InsertElementTxn"));
 
242
  return NS_OK;
 
243
}