LibreOffice Module unoxml (master) 1
eventdispatcher.cxx
Go to the documentation of this file.
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 <eventdispatcher.hxx>
21
22#include <event.hxx>
23#include <mutationevent.hxx>
24#include <uievent.hxx>
25#include <mouseevent.hxx>
26
27#include "../dom/document.hxx"
28
29#include <osl/mutex.hxx>
30
31using namespace css::uno;
32using namespace css::xml::dom;
33using namespace css::xml::dom::events;
34
35namespace DOM::events {
36
37 void CEventDispatcher::addListener(xmlNodePtr pNode, const OUString& aType, const Reference<XEventListener>& aListener, bool bCapture)
38 {
39 TypeListenerMap *const pTMap = bCapture
41
42 // get the multimap for the specified type
43 ListenerMap *pMap = nullptr;
44 auto tIter = pTMap->find(aType);
45 if (tIter == pTMap->end()) {
46 // the map has to be created
47 auto const pair = pTMap->emplace(aType, ListenerMap());
48 pMap = & pair.first->second;
49 } else {
50 pMap = & tIter->second;
51 }
52 assert(pMap != nullptr);
53 pMap->emplace(pNode, aListener);
54 }
55
56 void CEventDispatcher::removeListener(xmlNodePtr pNode, const OUString& aType, const Reference<XEventListener>& aListener, bool bCapture)
57 {
58 TypeListenerMap *const pTMap = bCapture
60
61 // get the multimap for the specified type
62 auto tIter = pTMap->find(aType);
63 if (tIter == pTMap->end())
64 return;
65
66 ListenerMap & rMap = tIter->second;
67 // find listeners of specified type for specified node
68 ListenerMap::iterator iter = rMap.find(pNode);
69 while (iter != rMap.end() && iter->first == pNode)
70 {
71 // erase all references to specified listener
72 if (iter->second.is() && iter->second == aListener)
73 {
74 iter = rMap.erase(iter);
75 }
76 else
77 ++iter;
78 }
79 }
80
82 {
83 }
84
86 TypeListenerMap const& rTMap,
87 xmlNodePtr const pNode,
88 const OUString& aType, Reference< XEvent > const& xEvent)
89 {
90 // get the multimap for the specified type
91 TypeListenerMap::const_iterator tIter = rTMap.find(aType);
92 if (tIter != rTMap.end()) {
93 ListenerMap const& rMap = tIter->second;
94 auto iterRange = rMap.equal_range(pNode);
95 for( auto iter = iterRange.first; iter != iterRange.second; ++iter )
96 {
97 if(iter->second.is())
98 (iter->second)->handleEvent(xEvent);
99 }
100 }
101 }
102
104 DOM::CDocument & rDocument, ::osl::Mutex & rMutex,
105 xmlNodePtr const pNode, Reference<XNode> const& xNode,
106 Reference< XEvent > const& i_xEvent) const
107 {
108 TypeListenerMap captureListeners;
109 TypeListenerMap targetListeners;
110 {
111 ::osl::MutexGuard g(rMutex);
112
113 captureListeners = m_CaptureListeners;
114 targetListeners = m_TargetListeners;
115 }
116
117 if (captureListeners.empty() && targetListeners.empty())
118 return;
119
120 rtl::Reference<CEvent> pEvent; // pointer to internal event representation
121
122 OUString const aType = i_xEvent->getType();
123 if (aType == "DOMSubtreeModified" ||
124 aType == "DOMNodeInserted" ||
125 aType == "DOMNodeRemoved" ||
126 aType == "DOMNodeRemovedFromDocument" ||
127 aType == "DOMNodeInsertedIntoDocument" ||
128 aType == "DOMAttrModified" ||
129 aType == "DOMCharacterDataModified" )
130 {
131 Reference< XMutationEvent > const aMEvent(i_xEvent,
132 UNO_QUERY_THROW);
133 // dispatch a mutation event
134 // we need to clone the event in order to have complete control
135 // over the implementation
137 pMEvent->initMutationEvent(
138 aType, aMEvent->getBubbles(), aMEvent->getCancelable(),
139 aMEvent->getRelatedNode(), aMEvent->getPrevValue(),
140 aMEvent->getNewValue(), aMEvent->getAttrName(),
141 aMEvent->getAttrChange());
142 pEvent = pMEvent;
143 } else if ( // UIEvent
144 aType == "DOMFocusIn" ||
145 aType == "DOMFocusOut" ||
146 aType == "DOMActivate" )
147 {
148 Reference< XUIEvent > const aUIEvent(i_xEvent, UNO_QUERY_THROW);
149 rtl::Reference<CUIEvent> pUIEvent = new CUIEvent;
150 pUIEvent->initUIEvent(aType,
151 aUIEvent->getBubbles(), aUIEvent->getCancelable(),
152 aUIEvent->getView(), aUIEvent->getDetail());
153 pEvent = pUIEvent;
154 } else if ( // MouseEvent
155 aType == "click" ||
156 aType == "mousedown" ||
157 aType == "mouseup" ||
158 aType == "mouseover" ||
159 aType == "mousemove" ||
160 aType == "mouseout" )
161 {
162 Reference< XMouseEvent > const aMouseEvent(i_xEvent,
163 UNO_QUERY_THROW);
165 pMouseEvent->initMouseEvent(aType,
166 aMouseEvent->getBubbles(), aMouseEvent->getCancelable(),
167 aMouseEvent->getView(), aMouseEvent->getDetail(),
168 aMouseEvent->getScreenX(), aMouseEvent->getScreenY(),
169 aMouseEvent->getClientX(), aMouseEvent->getClientY(),
170 aMouseEvent->getCtrlKey(), aMouseEvent->getAltKey(),
171 aMouseEvent->getShiftKey(), aMouseEvent->getMetaKey(),
172 aMouseEvent->getButton(), aMouseEvent->getRelatedTarget());
173 pEvent = pMouseEvent;
174 }
175 else // generic event
176 {
177 pEvent = new CEvent;
178 pEvent->initEvent(
179 aType, i_xEvent->getBubbles(), i_xEvent->getCancelable());
180 }
181 pEvent->m_target.set(xNode, UNO_QUERY_THROW);
182 pEvent->m_currentTarget = i_xEvent->getCurrentTarget();
183 pEvent->m_time = i_xEvent->getTimeStamp();
184
185 // create the reference to the private event implementation
186 // that will be dispatched to the listeners
187 Reference< XEvent > const xEvent(pEvent);
188
189 // build the path from target node to the root
190 typedef std::vector< ::std::pair<Reference<XEventTarget>, xmlNodePtr> >
191 NodeVector_t;
192 NodeVector_t captureVector;
193 {
194 ::osl::MutexGuard g(rMutex);
195
196 xmlNodePtr cur = pNode;
197 while (cur != nullptr)
198 {
199 Reference< XEventTarget > const xRef(
200 rDocument.GetCNode(cur));
201 captureVector.emplace_back(xRef, cur);
202 cur = cur->parent;
203 }
204 }
205
206 // the capture vector now holds the node path from target to root
207 // first we must search for capture listeners in order root to
208 // to target. after that, any target listeners have to be called
209 // then bubbeling phase listeners are called in target to root
210 // order
211 // start at the root
212 NodeVector_t::const_reverse_iterator rinode =
213 const_cast<NodeVector_t const&>(captureVector).rbegin();
214 if (rinode == const_cast<NodeVector_t const&>(captureVector).rend())
215 return;
216
217 // capturing phase:
218 pEvent->m_phase = PhaseType_CAPTURING_PHASE;
219 while (rinode !=
220 const_cast<NodeVector_t const&>(captureVector).rend())
221 {
222 pEvent->m_currentTarget = rinode->first;
223 callListeners(captureListeners, rinode->second, aType, xEvent);
224 if (pEvent->m_canceled) return;
225 ++rinode;
226 }
227
228 NodeVector_t::const_iterator inode = captureVector.begin();
229
230 // target phase
231 pEvent->m_phase = PhaseType_AT_TARGET;
232 pEvent->m_currentTarget = inode->first;
233 callListeners(targetListeners, inode->second, aType, xEvent);
234 if (pEvent->m_canceled) return;
235 // bubbeling phase
236 ++inode;
237 if (i_xEvent->getBubbles()) {
238 pEvent->m_phase = PhaseType_BUBBLING_PHASE;
239 while (inode != captureVector.end())
240 {
241 pEvent->m_currentTarget = inode->first;
242 callListeners(targetListeners,
243 inode->second, aType, xEvent);
244 if (pEvent->m_canceled) return;
245 ++inode;
246 }
247 }
248 }
249}
250
251/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::rtl::Reference< CNode > GetCNode(xmlNodePtr const pNode, bool const bCreate=true)
get UNO wrapper instance for a libxml node
Definition: document.cxx:161
void removeListener(xmlNodePtr pNode, const OUString &aType, const css::uno::Reference< css::xml::dom::events::XEventListener > &aListener, bool bCapture)
void dispatchEvent(DOM::CDocument &rDocument, ::osl::Mutex &rMutex, xmlNodePtr const pNode, css::uno::Reference< css::xml::dom::XNode > const &xNode, css::uno::Reference< css::xml::dom::events::XEvent > const &xEvent) const
void addListener(xmlNodePtr pNode, const OUString &aType, const css::uno::Reference< css::xml::dom::events::XEventListener > &aListener, bool bCapture)
static void callListeners(TypeListenerMap const &rTMap, xmlNodePtr const pNode, const OUString &aType, const css::uno::Reference< css::xml::dom::events::XEvent > &xEvent)
std::multimap< xmlNodePtr, css::uno::Reference< css::xml::dom::events::XEventListener > > ListenerMap
std::map< OUString, ListenerMap > TypeListenerMap