/src/libreoffice/unoxml/source/dom/elementlist.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include "elementlist.hxx" |
21 | | |
22 | | #include <string.h> |
23 | | #include <string_view> |
24 | | |
25 | | #include <cppuhelper/implbase.hxx> |
26 | | #include <o3tl/safeint.hxx> |
27 | | #include <utility> |
28 | | #include <comphelper/diagnose_ex.hxx> |
29 | | #include <unotools/weakref.hxx> |
30 | | |
31 | | #include "element.hxx" |
32 | | #include "document.hxx" |
33 | | |
34 | | using namespace css::uno; |
35 | | using namespace css::xml::dom; |
36 | | using namespace css::xml::dom::events; |
37 | | namespace DOM { class CElementListImpl; } |
38 | | |
39 | | namespace DOM |
40 | | { |
41 | | class WeakEventListener : public ::cppu::WeakImplHelper<css::xml::dom::events::XEventListener> |
42 | | { |
43 | | private: |
44 | | unotools::WeakReference<DOM::CElementListImpl> mxOwner; |
45 | | |
46 | | public: |
47 | | explicit WeakEventListener(const rtl::Reference<DOM::CElementListImpl>& rOwner) |
48 | 0 | : mxOwner(rOwner) |
49 | 0 | { |
50 | 0 | } |
51 | | |
52 | | virtual void SAL_CALL handleEvent(const css::uno::Reference<css::xml::dom::events::XEvent>& rEvent) override |
53 | 0 | { |
54 | 0 | rtl::Reference<DOM::CElementListImpl> xOwner(mxOwner); |
55 | 0 | if (xOwner) |
56 | 0 | xOwner->handleEvent(rEvent); |
57 | 0 | } |
58 | | }; |
59 | | } |
60 | | |
61 | | namespace DOM |
62 | | { |
63 | | |
64 | | static xmlChar* lcl_initXmlString(std::u16string_view rString) |
65 | 0 | { |
66 | 0 | OString const os = |
67 | 0 | OUStringToOString(rString, RTL_TEXTENCODING_UTF8); |
68 | 0 | xmlChar *const pRet = new xmlChar[os.getLength() + 1]; |
69 | 0 | strcpy(reinterpret_cast<char*>(pRet), os.getStr()); |
70 | 0 | return pRet; |
71 | 0 | } |
72 | | |
73 | | CElementList::CElementList(::rtl::Reference<CElement> const& pElement, |
74 | | ::osl::Mutex & rMutex, |
75 | | std::u16string_view rName, OUString const*const pURI) |
76 | 0 | : m_xImpl(new CElementListImpl(pElement, rMutex, rName, pURI)) |
77 | 0 | { |
78 | 0 | if (pElement.is()) { |
79 | 0 | m_xImpl->registerListener(*pElement); |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | | CElementListImpl::CElementListImpl(::rtl::Reference<CElement> pElement, |
84 | | ::osl::Mutex & rMutex, |
85 | | std::u16string_view rName, OUString const*const pURI) |
86 | 0 | : m_pElement(std::move(pElement)) |
87 | 0 | , m_rMutex(rMutex) |
88 | 0 | , m_pName(lcl_initXmlString(rName)) |
89 | 0 | , m_pURI(pURI ? lcl_initXmlString(*pURI) : nullptr) |
90 | 0 | , m_bRebuild(true) |
91 | 0 | { |
92 | 0 | } |
93 | | |
94 | | CElementListImpl::~CElementListImpl() |
95 | 0 | { |
96 | 0 | if (m_xEventListener.is() && m_pElement.is()) |
97 | 0 | m_pElement->removeEventListener(u"DOMSubtreeModified"_ustr, m_xEventListener, false/*capture*/); |
98 | 0 | } |
99 | | |
100 | | void CElementListImpl::registerListener(CElement & rElement) |
101 | 0 | { |
102 | 0 | try { |
103 | 0 | Reference< XEventTarget > const xTarget( |
104 | 0 | static_cast<XElement*>(& rElement), UNO_QUERY_THROW); |
105 | 0 | m_xEventListener = new WeakEventListener(this); |
106 | 0 | xTarget->addEventListener(u"DOMSubtreeModified"_ustr, m_xEventListener, false/*capture*/); |
107 | 0 | } catch (const Exception &){ |
108 | 0 | TOOLS_WARN_EXCEPTION( "unoxml", "Exception caught while registering NodeList as listener"); |
109 | 0 | } |
110 | 0 | } |
111 | | |
112 | | void CElementListImpl::buildlist(xmlNodePtr pNode, bool start) |
113 | 0 | { |
114 | | // bail out if no rebuild is needed |
115 | 0 | if (start) { |
116 | 0 | if (!m_bRebuild) |
117 | 0 | { |
118 | 0 | return; |
119 | 0 | } else { |
120 | 0 | m_nodevector.clear(); |
121 | 0 | m_bRebuild = false; // don't rebuild until tree is mutated |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | 0 | while (pNode != nullptr ) |
126 | 0 | { |
127 | 0 | if (pNode->type == XML_ELEMENT_NODE && |
128 | 0 | (strcmp(reinterpret_cast<char const *>(pNode->name), reinterpret_cast<char*>(m_pName.get())) == 0)) |
129 | 0 | { |
130 | 0 | if (!m_pURI) { |
131 | 0 | m_nodevector.push_back(pNode); |
132 | 0 | } else { |
133 | 0 | if (pNode->ns != nullptr && (0 == |
134 | 0 | strcmp(reinterpret_cast<char const *>(pNode->ns->href), reinterpret_cast<char*>(m_pURI.get())))) |
135 | 0 | { |
136 | 0 | m_nodevector.push_back(pNode); |
137 | 0 | } |
138 | 0 | } |
139 | 0 | } |
140 | 0 | if (pNode->children != nullptr) buildlist(pNode->children, false); |
141 | |
|
142 | 0 | if (!start) pNode = pNode->next; |
143 | 0 | else break; // fold back |
144 | 0 | } |
145 | 0 | } |
146 | | |
147 | | /** |
148 | | The number of nodes in the list. |
149 | | */ |
150 | | sal_Int32 SAL_CALL CElementListImpl::getLength() |
151 | 0 | { |
152 | 0 | ::osl::MutexGuard const g(m_rMutex); |
153 | |
|
154 | 0 | if (!m_pElement.is()) { return 0; } |
155 | | |
156 | | // this has to be 'live' |
157 | 0 | buildlist(m_pElement->GetNodePtr()); |
158 | 0 | return m_nodevector.size(); |
159 | 0 | } |
160 | | /** |
161 | | Returns the indexth item in the collection. |
162 | | */ |
163 | | Reference< XNode > SAL_CALL CElementListImpl::item(sal_Int32 index) |
164 | 0 | { |
165 | 0 | if (index < 0) throw RuntimeException(); |
166 | | |
167 | 0 | ::osl::MutexGuard const g(m_rMutex); |
168 | |
|
169 | 0 | if (!m_pElement.is()) { return nullptr; } |
170 | | |
171 | 0 | buildlist(m_pElement->GetNodePtr()); |
172 | 0 | if (m_nodevector.size() <= o3tl::make_unsigned(index)) { |
173 | 0 | throw RuntimeException(); |
174 | 0 | } |
175 | 0 | return m_pElement->GetOwnerDocument().GetCNode(m_nodevector[index]); |
176 | 0 | } |
177 | | |
178 | | // tree mutations can change the list |
179 | | void SAL_CALL CElementListImpl::handleEvent(Reference< XEvent > const&) |
180 | 0 | { |
181 | 0 | ::osl::MutexGuard const g(m_rMutex); |
182 | |
|
183 | 0 | m_bRebuild = true; |
184 | 0 | } |
185 | | } |
186 | | |
187 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |