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
->insert(TypeListenerMap::value_type(aType
, ListenerMap()));
48 pMap
= & pair
.first
->second
;
50 pMap
= & tIter
->second
;
52 assert(pMap
!= nullptr);
53 pMap
->insert(ListenerMap::value_type(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 ListenerMap::iterator tmp_iter
= iter
;
82 CEventDispatcher::~CEventDispatcher()
86 void CEventDispatcher::callListeners(
87 TypeListenerMap
const& rTMap
,
88 xmlNodePtr
const pNode
,
89 const OUString
& aType
, Reference
< XEvent
> const& xEvent
)
91 // get the multimap for the specified type
92 TypeListenerMap::const_iterator tIter
= rTMap
.find(aType
);
93 if (tIter
!= rTMap
.end()) {
94 ListenerMap
const& rMap
= tIter
->second
;
95 auto iter
= rMap
.lower_bound(pNode
);
96 auto const ibound
= rMap
.upper_bound(pNode
);
97 for( ; iter
!= ibound
; ++iter
)
99 if((iter
->second
).is())
100 (iter
->second
)->handleEvent(xEvent
);
105 bool CEventDispatcher::dispatchEvent(
106 DOM::CDocument
& rDocument
, ::osl::Mutex
& rMutex
,
107 xmlNodePtr
const pNode
, Reference
<XNode
> const& xNode
,
108 Reference
< XEvent
> const& i_xEvent
) const
110 CEvent
*pEvent
= nullptr; // pointer to internal event representation
112 OUString
const aType
= i_xEvent
->getType();
113 if (aType
== "DOMSubtreeModified" ||
114 aType
== "DOMNodeInserted" ||
115 aType
== "DOMNodeRemoved" ||
116 aType
== "DOMNodeRemovedFromDocument" ||
117 aType
== "DOMNodeInsertedIntoDocument" ||
118 aType
== "DOMAttrModified" ||
119 aType
== "DOMCharacterDataModified" )
121 Reference
< XMutationEvent
> const aMEvent(i_xEvent
,
123 // dispatch a mutation event
124 // we need to clone the event in order to have complete control
125 // over the implementation
126 CMutationEvent
* pMEvent
= new CMutationEvent
;
127 pMEvent
->initMutationEvent(
128 aType
, aMEvent
->getBubbles(), aMEvent
->getCancelable(),
129 aMEvent
->getRelatedNode(), aMEvent
->getPrevValue(),
130 aMEvent
->getNewValue(), aMEvent
->getAttrName(),
131 aMEvent
->getAttrChange());
133 } else if ( // UIEvent
134 aType
== "DOMFocusIn" ||
135 aType
== "DOMFocusOut" ||
136 aType
== "DOMActivate" )
138 Reference
< XUIEvent
> const aUIEvent(i_xEvent
, UNO_QUERY_THROW
);
139 CUIEvent
* pUIEvent
= new CUIEvent
;
140 pUIEvent
->initUIEvent(aType
,
141 aUIEvent
->getBubbles(), aUIEvent
->getCancelable(),
142 aUIEvent
->getView(), aUIEvent
->getDetail());
144 } else if ( // MouseEvent
146 aType
== "mousedown" ||
147 aType
== "mouseup" ||
148 aType
== "mouseover" ||
149 aType
== "mousemove" ||
150 aType
== "mouseout" )
152 Reference
< XMouseEvent
> const aMouseEvent(i_xEvent
,
154 CMouseEvent
*pMouseEvent
= new CMouseEvent
;
155 pMouseEvent
->initMouseEvent(aType
,
156 aMouseEvent
->getBubbles(), aMouseEvent
->getCancelable(),
157 aMouseEvent
->getView(), aMouseEvent
->getDetail(),
158 aMouseEvent
->getScreenX(), aMouseEvent
->getScreenY(),
159 aMouseEvent
->getClientX(), aMouseEvent
->getClientY(),
160 aMouseEvent
->getCtrlKey(), aMouseEvent
->getAltKey(),
161 aMouseEvent
->getShiftKey(), aMouseEvent
->getMetaKey(),
162 aMouseEvent
->getButton(), aMouseEvent
->getRelatedTarget());
163 pEvent
= pMouseEvent
;
165 else // generic event
169 aType
, i_xEvent
->getBubbles(), i_xEvent
->getCancelable());
171 pEvent
->m_target
.set(xNode
, UNO_QUERY_THROW
);
172 pEvent
->m_currentTarget
= i_xEvent
->getCurrentTarget();
173 pEvent
->m_time
= i_xEvent
->getTimeStamp();
175 // create the reference to the private event implementation
176 // that will be dispatched to the listeners
177 Reference
< XEvent
> const xEvent(pEvent
);
179 // build the path from target node to the root
180 typedef std::vector
< ::std::pair
<Reference
<XEventTarget
>, xmlNodePtr
> >
182 NodeVector_t captureVector
;
183 TypeListenerMap captureListeners
;
184 TypeListenerMap targetListeners
;
186 ::osl::MutexGuard
g(rMutex
);
188 xmlNodePtr cur
= pNode
;
189 while (cur
!= nullptr)
191 Reference
< XEventTarget
> const xRef(
192 rDocument
.GetCNode(cur
).get());
193 captureVector
.push_back(::std::make_pair(xRef
, cur
));
196 captureListeners
= m_CaptureListeners
;
197 targetListeners
= m_TargetListeners
;
200 // the capture vector now holds the node path from target to root
201 // first we must search for capture listeners in order root to
202 // to target. after that, any target listeners have to be called
203 // then bubbeling phase listeners are called in target to root
206 NodeVector_t::const_reverse_iterator rinode
=
207 const_cast<NodeVector_t
const&>(captureVector
).rbegin();
208 if (rinode
!= const_cast<NodeVector_t
const&>(captureVector
).rend())
211 pEvent
->m_phase
= PhaseType_CAPTURING_PHASE
;
213 const_cast<NodeVector_t
const&>(captureVector
).rend())
215 pEvent
->m_currentTarget
= rinode
->first
;
216 callListeners(captureListeners
, rinode
->second
, aType
, xEvent
);
217 if (pEvent
->m_canceled
) return true;
221 NodeVector_t::const_iterator inode
= captureVector
.begin();
224 pEvent
->m_phase
= PhaseType_AT_TARGET
;
225 pEvent
->m_currentTarget
= inode
->first
;
226 callListeners(targetListeners
, inode
->second
, aType
, xEvent
);
227 if (pEvent
->m_canceled
) return true;
230 if (i_xEvent
->getBubbles()) {
231 pEvent
->m_phase
= PhaseType_BUBBLING_PHASE
;
232 while (inode
!= captureVector
.end())
234 pEvent
->m_currentTarget
= inode
->first
;
235 callListeners(targetListeners
,
236 inode
->second
, aType
, xEvent
);
237 if (pEvent
->m_canceled
) return true;
246 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */