xref: /aoo41x/main/unoxml/source/dom/elementlist.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 "elementlist.hxx"
29 
30 #include <string.h>
31 
32 #include <element.hxx>
33 #include <document.hxx>
34 
35 
36 namespace DOM
37 {
38 
39     static xmlChar* lcl_initXmlString(::rtl::OUString const& rString)
40     {
41         ::rtl::OString const os =
42             ::rtl::OUStringToOString(rString, RTL_TEXTENCODING_UTF8);
43         xmlChar *const pRet = new xmlChar[os.getLength() + 1];
44         strcpy(reinterpret_cast<char*>(pRet), os.getStr());
45         return pRet;
46     }
47 
48     CElementList::CElementList(::rtl::Reference<CElement> const& pElement,
49             ::osl::Mutex & rMutex,
50             OUString const& rName, OUString const*const pURI)
51         : m_pElement(pElement)
52         , m_rMutex(rMutex)
53         , m_pName(lcl_initXmlString(rName))
54         , m_pURI((pURI) ? lcl_initXmlString(*pURI) : 0)
55         , m_bRebuild(true)
56     {
57         if (m_pElement.is()) {
58             registerListener(*m_pElement);
59         }
60     }
61 
62     void CElementList::registerListener(CElement & rElement)
63     {
64         try {
65             Reference< XEventTarget > const xTarget(
66                     static_cast<XElement*>(& rElement), UNO_QUERY_THROW);
67             OUString aType = OUString::createFromAscii("DOMSubtreeModified");
68             sal_Bool capture = sal_False;
69             xTarget->addEventListener(aType,
70                     Reference< XEventListener >(this), capture);
71         } catch (Exception &e){
72             OString aMsg("Exception caught while registering NodeList as listener:\n");
73             aMsg += OUStringToOString(e.Message, RTL_TEXTENCODING_ASCII_US);
74             OSL_ENSURE(sal_False, aMsg.getStr());
75         }
76     }
77 
78     void CElementList::buildlist(xmlNodePtr pNode, sal_Bool start)
79     {
80         // bail out if no rebuild is needed
81         if (start) {
82             if (!m_bRebuild)
83             {
84                 return;
85             } else {
86                 m_nodevector.erase(m_nodevector.begin(), m_nodevector.end());
87                 m_bRebuild = false; // don't rebuild until tree is mutated
88             }
89         }
90 
91         while (pNode != NULL )
92         {
93             if (pNode->type == XML_ELEMENT_NODE &&
94                 (strcmp((char*)pNode->name, (char*)m_pName.get()) == 0))
95             {
96                 if (!m_pURI) {
97                     m_nodevector.push_back(pNode);
98                 } else {
99                     if (pNode->ns != NULL && (0 ==
100                          strcmp((char*)pNode->ns->href, (char*)m_pURI.get())))
101                     {
102                         m_nodevector.push_back(pNode);
103                     }
104                 }
105             }
106             if (pNode->children != NULL) buildlist(pNode->children, sal_False);
107 
108             if (!start) pNode = pNode->next;
109             else break; // fold back
110         }
111     }
112 
113     /**
114     The number of nodes in the list.
115     */
116     sal_Int32 SAL_CALL CElementList::getLength() throw (RuntimeException)
117     {
118         ::osl::MutexGuard const g(m_rMutex);
119 
120         if (!m_pElement.is()) { return 0; }
121 
122         // this has to be 'live'
123         buildlist(m_pElement->GetNodePtr());
124         return m_nodevector.size();
125     }
126     /**
127     Returns the indexth item in the collection.
128     */
129     Reference< XNode > SAL_CALL CElementList::item(sal_Int32 index)
130         throw (RuntimeException)
131     {
132         if (index < 0) throw RuntimeException();
133 
134         ::osl::MutexGuard const g(m_rMutex);
135 
136         if (!m_pElement.is()) { return 0; }
137 
138         buildlist(m_pElement->GetNodePtr());
139         if (m_nodevector.size() <= static_cast<size_t>(index)) {
140             throw RuntimeException();
141         }
142         Reference< XNode > const xRet(
143             m_pElement->GetOwnerDocument().GetCNode(m_nodevector[index]).get());
144         return xRet;
145     }
146 
147     // tree mutations can change the list
148     void SAL_CALL CElementList::handleEvent(Reference< XEvent > const&)
149         throw (RuntimeException)
150     {
151         ::osl::MutexGuard const g(m_rMutex);
152 
153         m_bRebuild = true;
154     }
155 }
156