xref: /aoo42x/main/unoxml/source/dom/attr.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include <attr.hxx>
29 
30 #include <string.h>
31 
32 #include <boost/shared_ptr.hpp>
33 
34 #include <com/sun/star/xml/dom/DOMException.hdl>
35 #include <com/sun/star/xml/dom/events/XMutationEvent.hpp>
36 
37 #include <document.hxx>
38 
39 
40 namespace DOM
41 {
42     CAttr::CAttr(CDocument const& rDocument, ::osl::Mutex const& rMutex,
43             xmlAttrPtr const pAttr)
44         : CAttr_Base(rDocument, rMutex,
45                 NodeType_ATTRIBUTE_NODE, reinterpret_cast<xmlNodePtr>(pAttr))
46         , m_aAttrPtr(pAttr)
47     {
48     }
49 
50     xmlNsPtr CAttr::GetNamespace(xmlNodePtr const pNode)
51     {
52         if (!m_pNamespace.get()) {
53             return 0;
54         }
55         xmlChar const*const pUri(reinterpret_cast<xmlChar const*>(
56                 m_pNamespace->first.getStr()));
57         xmlChar const*const pPrefix(reinterpret_cast<xmlChar const*>(
58                 m_pNamespace->second.getStr()));
59         xmlNsPtr pNs = xmlSearchNs(pNode->doc, pNode, pPrefix);
60         if (pNs && (0 != xmlStrcmp(pNs->href, pUri))) {
61             return pNs;
62         }
63         pNs = xmlNewNs(pNode, pUri, pPrefix);
64         if (pNs) {
65             return pNs;
66         }
67         pNs = xmlSearchNsByHref(pNode->doc, pNode, pUri);
68         // if (!pNs) hmm... now what? throw?
69         if (!pNs) { OSL_TRACE("CAtttr: cannot create namespace"); }
70         return pNs;
71     }
72 
73     bool CAttr::IsChildTypeAllowed(NodeType const nodeType)
74     {
75         switch (nodeType) {
76             case NodeType_TEXT_NODE:
77             case NodeType_ENTITY_REFERENCE_NODE:
78                 return true;
79             default:
80                 return false;
81         }
82     }
83 
84     OUString SAL_CALL CAttr::getNodeName()
85         throw (RuntimeException)
86     {
87         return getName();
88     }
89     OUString SAL_CALL CAttr::getNodeValue()
90         throw (RuntimeException)
91     {
92         return getValue();
93     }
94     OUString SAL_CALL CAttr::getLocalName()
95         throw (RuntimeException)
96     {
97         return getName();
98     }
99 
100 
101     /**
102     Returns the name of this attribute.
103     */
104     OUString SAL_CALL CAttr::getName() throw (RuntimeException)
105     {
106         ::osl::MutexGuard const g(m_rMutex);
107 
108         if ((0 == m_aNodePtr) || (0 == m_aAttrPtr)) {
109             return ::rtl::OUString();
110         }
111         OUString const aName((char*)m_aAttrPtr->name,
112                 strlen((char*)m_aAttrPtr->name), RTL_TEXTENCODING_UTF8);
113         return aName;
114     }
115 
116     /**
117     The Element node this attribute is attached to or null if this
118     attribute is not in use.
119     */
120     Reference< XElement > SAL_CALL CAttr::getOwnerElement()
121         throw (RuntimeException)
122     {
123         ::osl::MutexGuard const g(m_rMutex);
124 
125         if ((0 == m_aNodePtr) || (0 == m_aAttrPtr)) {
126             return 0;
127         }
128         if (0 == m_aAttrPtr->parent) {
129             return 0;
130         }
131         Reference< XElement > const xRet(
132             static_cast< XNode* >(GetOwnerDocument().GetCNode(
133                     m_aAttrPtr->parent).get()),
134             UNO_QUERY_THROW);
135         return xRet;
136     }
137 
138     /**
139     If this attribute was explicitly given a value in the original
140     document, this is true; otherwise, it is false.
141     */
142     sal_Bool SAL_CALL CAttr::getSpecified()
143         throw (RuntimeException)
144     {
145         // FIXME if this DOM implemenatation supported DTDs it would need
146         // to check that this attribute is not default or something
147         return sal_True;
148     }
149 
150     /**
151     On retrieval, the value of the attribute is returned as a string.
152     */
153     OUString SAL_CALL CAttr::getValue()
154         throw (RuntimeException)
155     {
156         ::osl::MutexGuard const g(m_rMutex);
157 
158         if ((0 == m_aNodePtr) || (0 == m_aAttrPtr)) {
159             return ::rtl::OUString();
160         }
161         if (0 == m_aAttrPtr->children) {
162             return ::rtl::OUString();
163         }
164         char const*const pContent((m_aAttrPtr->children)
165             ? reinterpret_cast<char const*>(m_aAttrPtr->children->content)
166             : "");
167         OUString const ret(pContent, strlen(pContent), RTL_TEXTENCODING_UTF8);
168         return ret;
169     }
170 
171     /**
172     Sets the value of the attribute from a string.
173     */
174     void SAL_CALL CAttr::setValue(const OUString& value)
175         throw (RuntimeException, DOMException)
176     {
177         ::osl::ClearableMutexGuard guard(m_rMutex);
178 
179         if ((0 == m_aNodePtr) || (0 == m_aAttrPtr)) {
180             return;
181         }
182 
183         // remember old value (for mutation event)
184         OUString sOldValue = getValue();
185 
186         OString o1 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
187         xmlChar* xValue = (xmlChar*)o1.getStr();
188         // xmlChar* xName = OUStringToOString(m_aAttrPtr->name, RTL_TEXTENCODING_UTF8).getStr();
189         // this does not work if the attribute was created anew
190         // xmlNodePtr pNode = m_aAttrPtr->parent;
191         // xmlSetProp(pNode, m_aAttrPtr->name, xValue);
192         ::boost::shared_ptr<xmlChar const> const buffer(
193                 xmlEncodeEntitiesReentrant(m_aAttrPtr->doc, xValue), xmlFree);
194         xmlFreeNodeList(m_aAttrPtr->children);
195         m_aAttrPtr->children =
196             xmlStringGetNodeList(m_aAttrPtr->doc, buffer.get());
197         xmlNodePtr tmp = m_aAttrPtr->children;
198         while (tmp != NULL) {
199             tmp->parent = (xmlNodePtr) m_aNodePtr;
200             tmp->doc = m_aAttrPtr->doc;
201             if (tmp->next == NULL)
202                 m_aNodePtr->last = tmp;
203             tmp = tmp->next;
204         }
205 
206         // dispatch DOM events to signal change in attribute value
207         // dispatch DomAttrModified + DOMSubtreeModified
208         OUString sEventName( RTL_CONSTASCII_USTRINGPARAM("DOMAttrModified") );
209         Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
210         Reference< XMutationEvent > event(docevent->createEvent(sEventName),UNO_QUERY);
211         event->initMutationEvent(
212                 sEventName, sal_True, sal_False,
213                 Reference<XNode>( static_cast<XAttr*>( this ) ),
214                 sOldValue, value, getName(), AttrChangeType_MODIFICATION );
215 
216         guard.clear(); // release mutex before calling event handlers
217 
218         dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
219         dispatchSubtreeModified();
220     }
221 
222     void SAL_CALL CAttr::setPrefix(const OUString& prefix)
223         throw (RuntimeException, DOMException)
224     {
225         ::osl::MutexGuard const g(m_rMutex);
226 
227         if (!m_aNodePtr) { return; }
228 
229         if (m_pNamespace.get()) {
230             OSL_ASSERT(!m_aNodePtr->parent);
231             m_pNamespace->second =
232                 OUStringToOString(prefix, RTL_TEXTENCODING_UTF8);
233         } else {
234             CNode::setPrefix(prefix);
235         }
236     }
237 
238     OUString SAL_CALL CAttr::getPrefix()
239         throw (RuntimeException)
240     {
241         ::osl::MutexGuard const g(m_rMutex);
242 
243         if (!m_aNodePtr) { return ::rtl::OUString(); }
244 
245         if (m_pNamespace.get()) {
246             OSL_ASSERT(!m_aNodePtr->parent);
247             OUString const ret(::rtl::OStringToOUString(
248                         m_pNamespace->second, RTL_TEXTENCODING_UTF8));
249             return ret;
250         } else {
251             return CNode::getPrefix();
252         }
253     }
254 
255     OUString SAL_CALL CAttr::getNamespaceURI()
256         throw (RuntimeException)
257     {
258         ::osl::MutexGuard const g(m_rMutex);
259 
260         if (!m_aNodePtr) { return ::rtl::OUString(); }
261 
262         if (m_pNamespace.get()) {
263             OSL_ASSERT(!m_aNodePtr->parent);
264             OUString const ret(::rtl::OStringToOUString(
265                         m_pNamespace->first, RTL_TEXTENCODING_UTF8));
266             return ret;
267         } else {
268             return CNode::getNamespaceURI();
269         }
270     }
271 }
272