1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <eventdispatcher.hxx>
23 #include <mutationevent.hxx>
24 #include <uievent.hxx>
25 #include <mouseevent.hxx>
27 #include "../dom/document.hxx"
29 #include <osl/mutex.hxx>
31 using namespace css::uno
;
32 using namespace css::xml::dom
;
33 using namespace css::xml::dom::events
;
35 namespace DOM
{ namespace events
{
37 void CEventDispatcher::addListener(xmlNodePtr pNode
, const OUString
& aType
, const Reference
<XEventListener
>& aListener
, bool bCapture
)
39 TypeListenerMap
*const pTMap
= bCapture
40 ? (& m_CaptureListeners
) : (& m_TargetListeners
);
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
;
50 pMap
= & tIter
->second
;
52 assert(pMap
!= nullptr);
53 pMap
->emplace(pNode
, aListener
);
56 void CEventDispatcher::removeListener(xmlNodePtr pNode
, const OUString
& aType
, const Reference
<XEventListener
>& aListener
, bool bCapture
)
58 TypeListenerMap
*const pTMap
= bCapture
59 ? (& m_CaptureListeners
) : (& m_TargetListeners
);
61 // get the multimap for the specified type
62 auto tIter
= pTMap
->find(aType
);
63 if (tIter
!= pTMap
->end()) {
64 ListenerMap
& rMap
= tIter
->second
;
65 // find listeners of specified type for specified node
66 ListenerMap::iterator iter
= rMap
.find(pNode
);
67 while (iter
!= rMap
.end() && iter
->first
== pNode
)
69 // erase all references to specified listener
70 if (iter
->second
.is() && iter
->second
== aListener
)
72 iter
= rMap
.erase(iter
);
80 CEventDispatcher::~CEventDispatcher()
84 void CEventDispatcher::callListeners(
85 TypeListenerMap
const& rTMap
,
86 xmlNodePtr
const pNode
,
87 const OUString
& aType
, Reference
< XEvent
> const& xEvent
)
89 // get the multimap for the specified type
90 TypeListenerMap::const_iterator tIter
= rTMap
.find(aType
);
91 if (tIter
!= rTMap
.end()) {
92 ListenerMap
const& rMap
= tIter
->second
;
93 auto iterRange
= rMap
.equal_range(pNode
);
94 for( auto iter
= iterRange
.first
; iter
!= iterRange
.second
; ++iter
)
97 (iter
->second
)->handleEvent(xEvent
);
102 void CEventDispatcher::dispatchEvent(
103 DOM::CDocument
& rDocument
, ::osl::Mutex
& rMutex
,
104 xmlNodePtr
const pNode
, Reference
<XNode
> const& xNode
,
105 Reference
< XEvent
> const& i_xEvent
) const
107 TypeListenerMap captureListeners
;
108 TypeListenerMap targetListeners
;
110 ::osl::MutexGuard
g(rMutex
);
112 captureListeners
= m_CaptureListeners
;
113 targetListeners
= m_TargetListeners
;
116 if (captureListeners
.empty() && targetListeners
.empty())
119 CEvent
*pEvent
= nullptr; // pointer to internal event representation
121 OUString
const aType
= i_xEvent
->getType();
122 if (aType
== "DOMSubtreeModified" ||
123 aType
== "DOMNodeInserted" ||
124 aType
== "DOMNodeRemoved" ||
125 aType
== "DOMNodeRemovedFromDocument" ||
126 aType
== "DOMNodeInsertedIntoDocument" ||
127 aType
== "DOMAttrModified" ||
128 aType
== "DOMCharacterDataModified" )
130 Reference
< XMutationEvent
> const aMEvent(i_xEvent
,
132 // dispatch a mutation event
133 // we need to clone the event in order to have complete control
134 // over the implementation
135 CMutationEvent
* pMEvent
= new CMutationEvent
;
136 pMEvent
->initMutationEvent(
137 aType
, aMEvent
->getBubbles(), aMEvent
->getCancelable(),
138 aMEvent
->getRelatedNode(), aMEvent
->getPrevValue(),
139 aMEvent
->getNewValue(), aMEvent
->getAttrName(),
140 aMEvent
->getAttrChange());
142 } else if ( // UIEvent
143 aType
== "DOMFocusIn" ||
144 aType
== "DOMFocusOut" ||
145 aType
== "DOMActivate" )
147 Reference
< XUIEvent
> const aUIEvent(i_xEvent
, UNO_QUERY_THROW
);
148 CUIEvent
* pUIEvent
= new CUIEvent
;
149 pUIEvent
->initUIEvent(aType
,
150 aUIEvent
->getBubbles(), aUIEvent
->getCancelable(),
151 aUIEvent
->getView(), aUIEvent
->getDetail());
153 } else if ( // MouseEvent
155 aType
== "mousedown" ||
156 aType
== "mouseup" ||
157 aType
== "mouseover" ||
158 aType
== "mousemove" ||
159 aType
== "mouseout" )
161 Reference
< XMouseEvent
> const aMouseEvent(i_xEvent
,
163 CMouseEvent
*pMouseEvent
= new CMouseEvent
;
164 pMouseEvent
->initMouseEvent(aType
,
165 aMouseEvent
->getBubbles(), aMouseEvent
->getCancelable(),
166 aMouseEvent
->getView(), aMouseEvent
->getDetail(),
167 aMouseEvent
->getScreenX(), aMouseEvent
->getScreenY(),
168 aMouseEvent
->getClientX(), aMouseEvent
->getClientY(),
169 aMouseEvent
->getCtrlKey(), aMouseEvent
->getAltKey(),
170 aMouseEvent
->getShiftKey(), aMouseEvent
->getMetaKey(),
171 aMouseEvent
->getButton(), aMouseEvent
->getRelatedTarget());
172 pEvent
= pMouseEvent
;
174 else // generic event
178 aType
, i_xEvent
->getBubbles(), i_xEvent
->getCancelable());
180 pEvent
->m_target
.set(xNode
, UNO_QUERY_THROW
);
181 pEvent
->m_currentTarget
= i_xEvent
->getCurrentTarget();
182 pEvent
->m_time
= i_xEvent
->getTimeStamp();
184 // create the reference to the private event implementation
185 // that will be dispatched to the listeners
186 Reference
< XEvent
> const xEvent(pEvent
);
188 // build the path from target node to the root
189 typedef std::vector
< ::std::pair
<Reference
<XEventTarget
>, xmlNodePtr
> >
191 NodeVector_t captureVector
;
193 ::osl::MutexGuard
g(rMutex
);
195 xmlNodePtr cur
= pNode
;
196 while (cur
!= nullptr)
198 Reference
< XEventTarget
> const xRef(
199 rDocument
.GetCNode(cur
).get());
200 captureVector
.emplace_back(xRef
, cur
);
205 // the capture vector now holds the node path from target to root
206 // first we must search for capture listeners in order root to
207 // to target. after that, any target listeners have to be called
208 // then bubbeling phase listeners are called in target to root
211 NodeVector_t::const_reverse_iterator rinode
=
212 const_cast<NodeVector_t
const&>(captureVector
).rbegin();
213 if (rinode
!= const_cast<NodeVector_t
const&>(captureVector
).rend())
216 pEvent
->m_phase
= PhaseType_CAPTURING_PHASE
;
218 const_cast<NodeVector_t
const&>(captureVector
).rend())
220 pEvent
->m_currentTarget
= rinode
->first
;
221 callListeners(captureListeners
, rinode
->second
, aType
, xEvent
);
222 if (pEvent
->m_canceled
) return;
226 NodeVector_t::const_iterator inode
= captureVector
.begin();
229 pEvent
->m_phase
= PhaseType_AT_TARGET
;
230 pEvent
->m_currentTarget
= inode
->first
;
231 callListeners(targetListeners
, inode
->second
, aType
, xEvent
);
232 if (pEvent
->m_canceled
) return;
235 if (i_xEvent
->getBubbles()) {
236 pEvent
->m_phase
= PhaseType_BUBBLING_PHASE
;
237 while (inode
!= captureVector
.end())
239 pEvent
->m_currentTarget
= inode
->first
;
240 callListeners(targetListeners
,
241 inode
->second
, aType
, xEvent
);
242 if (pEvent
->m_canceled
) return;
250 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */