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"
30 namespace DOM
{ namespace events
{
32 void CEventDispatcher::addListener(xmlNodePtr pNode
, OUString aType
, const Reference
<XEventListener
>& aListener
, sal_Bool bCapture
)
34 TypeListenerMap
*const pTMap
= (bCapture
)
35 ? (& m_CaptureListeners
) : (& m_TargetListeners
);
37 // get the multimap for the specified type
38 ListenerMap
*pMap
= 0;
39 TypeListenerMap::const_iterator tIter
= pTMap
->find(aType
);
40 if (tIter
== pTMap
->end()) {
41 // the map has to be created
42 pMap
= new ListenerMap();
43 pTMap
->insert(TypeListenerMap::value_type(aType
, pMap
));
48 pMap
->insert(ListenerMap::value_type(pNode
, aListener
));
51 void CEventDispatcher::removeListener(xmlNodePtr pNode
, OUString aType
, const Reference
<XEventListener
>& aListener
, sal_Bool bCapture
)
53 TypeListenerMap
*const pTMap
= (bCapture
)
54 ? (& m_CaptureListeners
) : (& m_TargetListeners
);
56 // get the multimap for the specified type
57 TypeListenerMap::const_iterator tIter
= pTMap
->find(aType
);
58 if (tIter
!= pTMap
->end()) {
59 ListenerMap
*pMap
= tIter
->second
;
60 // find listeners of specied type for specified node
61 ListenerMap::iterator iter
= pMap
->find(pNode
);
62 while (iter
!= pMap
->end() && iter
->first
== pNode
)
64 // erase all references to specified listener
65 if ((iter
->second
).is() && iter
->second
== aListener
)
67 ListenerMap::iterator tmp_iter
= iter
;
69 pMap
->erase(tmp_iter
);
77 CEventDispatcher::~CEventDispatcher()
79 // delete the multimaps for the various types
80 for (TypeListenerMap::iterator aI
= m_CaptureListeners
.begin(); aI
!= m_CaptureListeners
.end(); ++aI
)
83 for (TypeListenerMap::iterator aI
= m_TargetListeners
.begin(); aI
!= m_TargetListeners
.end(); ++aI
)
87 void CEventDispatcher::callListeners(
88 TypeListenerMap
const& rTMap
,
89 xmlNodePtr
const pNode
,
90 OUString aType
, Reference
< XEvent
> const& xEvent
)
92 // get the multimap for the specified type
93 TypeListenerMap::const_iterator tIter
= rTMap
.find(aType
);
94 if (tIter
!= rTMap
.end()) {
95 ListenerMap
*pMap
= tIter
->second
;
96 ListenerMap::const_iterator iter
= pMap
->lower_bound(pNode
);
97 ListenerMap::const_iterator ibound
= pMap
->upper_bound(pNode
);
98 for( ; iter
!= ibound
; ++iter
)
100 if((iter
->second
).is())
101 (iter
->second
)->handleEvent(xEvent
);
106 bool CEventDispatcher::dispatchEvent(
107 DOM::CDocument
& rDocument
, ::osl::Mutex
& rMutex
,
108 xmlNodePtr
const pNode
, Reference
<XNode
> const& xNode
,
109 Reference
< XEvent
> const& i_xEvent
) const
111 CEvent
*pEvent
= 0; // pointer to internal event representation
113 OUString
const aType
= i_xEvent
->getType();
114 if (aType
.compareToAscii("DOMSubtreeModified") == 0||
115 aType
.compareToAscii("DOMNodeInserted") == 0||
116 aType
.compareToAscii("DOMNodeRemoved") == 0||
117 aType
.compareToAscii("DOMNodeRemovedFromDocument") == 0||
118 aType
.compareToAscii("DOMNodeInsertedIntoDocument") == 0||
119 aType
.compareToAscii("DOMAttrModified") == 0||
120 aType
.compareToAscii("DOMCharacterDataModified") == 0)
122 Reference
< XMutationEvent
> const aMEvent(i_xEvent
,
124 // dispatch a mutation event
125 // we need to clone the event in order to have complete control
126 // over the implementation
127 CMutationEvent
* pMEvent
= new CMutationEvent
;
128 pMEvent
->initMutationEvent(
129 aType
, aMEvent
->getBubbles(), aMEvent
->getCancelable(),
130 aMEvent
->getRelatedNode(), aMEvent
->getPrevValue(),
131 aMEvent
->getNewValue(), aMEvent
->getAttrName(),
132 aMEvent
->getAttrChange());
134 } else if ( // UIEvent
135 aType
.compareToAscii("DOMFocusIn") == 0||
136 aType
.compareToAscii("DOMFocusOut") == 0||
137 aType
.compareToAscii("DOMActivate") == 0)
139 Reference
< XUIEvent
> const aUIEvent(i_xEvent
, UNO_QUERY_THROW
);
140 CUIEvent
* pUIEvent
= new CUIEvent
;
141 pUIEvent
->initUIEvent(aType
,
142 aUIEvent
->getBubbles(), aUIEvent
->getCancelable(),
143 aUIEvent
->getView(), aUIEvent
->getDetail());
145 } else if ( // MouseEvent
146 aType
.compareToAscii("click") == 0||
147 aType
.compareToAscii("mousedown") == 0||
148 aType
.compareToAscii("mouseup") == 0||
149 aType
.compareToAscii("mouseover") == 0||
150 aType
.compareToAscii("mousemove") == 0||
151 aType
.compareToAscii("mouseout") == 0)
153 Reference
< XMouseEvent
> const aMouseEvent(i_xEvent
,
155 CMouseEvent
*pMouseEvent
= new CMouseEvent
;
156 pMouseEvent
->initMouseEvent(aType
,
157 aMouseEvent
->getBubbles(), aMouseEvent
->getCancelable(),
158 aMouseEvent
->getView(), aMouseEvent
->getDetail(),
159 aMouseEvent
->getScreenX(), aMouseEvent
->getScreenY(),
160 aMouseEvent
->getClientX(), aMouseEvent
->getClientY(),
161 aMouseEvent
->getCtrlKey(), aMouseEvent
->getAltKey(),
162 aMouseEvent
->getShiftKey(), aMouseEvent
->getMetaKey(),
163 aMouseEvent
->getButton(), aMouseEvent
->getRelatedTarget());
164 pEvent
= pMouseEvent
;
166 else // generic event
170 aType
, i_xEvent
->getBubbles(), i_xEvent
->getCancelable());
172 pEvent
->m_target
.set(xNode
, UNO_QUERY_THROW
);
173 pEvent
->m_currentTarget
= i_xEvent
->getCurrentTarget();
174 pEvent
->m_time
= i_xEvent
->getTimeStamp();
176 // create the reference to the provate event implementation
177 // that will be dispatched to the listeners
178 Reference
< XEvent
> const xEvent(pEvent
);
180 // build the path from target node to the root
181 typedef std::vector
< ::std::pair
<Reference
<XEventTarget
>, xmlNodePtr
> >
183 NodeVector_t captureVector
;
184 TypeListenerMap captureListeners
;
185 TypeListenerMap targetListeners
;
187 ::osl::MutexGuard
g(rMutex
);
189 xmlNodePtr cur
= pNode
;
192 Reference
< XEventTarget
> const xRef(
193 rDocument
.GetCNode(cur
).get());
194 captureVector
.push_back(::std::make_pair(xRef
, cur
));
197 captureListeners
= m_CaptureListeners
;
198 targetListeners
= m_TargetListeners
;
201 // the caputre vector now holds the node path from target to root
202 // first we must search for capture listernes in order root to
203 // to target. after that, any target listeners have to be called
204 // then bubbeling phase listeners are called in target to root
207 NodeVector_t::const_reverse_iterator rinode
=
208 const_cast<NodeVector_t
const&>(captureVector
).rbegin();
209 if (rinode
!= const_cast<NodeVector_t
const&>(captureVector
).rend())
212 pEvent
->m_phase
= PhaseType_CAPTURING_PHASE
;
214 const_cast<NodeVector_t
const&>(captureVector
).rend())
216 pEvent
->m_currentTarget
= rinode
->first
;
217 callListeners(captureListeners
, rinode
->second
, aType
, xEvent
);
218 if (pEvent
->m_canceled
) return sal_True
;
222 NodeVector_t::const_iterator inode
= captureVector
.begin();
225 pEvent
->m_phase
= PhaseType_AT_TARGET
;
226 pEvent
->m_currentTarget
= inode
->first
;
227 callListeners(targetListeners
, inode
->second
, aType
, xEvent
);
228 if (pEvent
->m_canceled
) return sal_True
;
231 if (i_xEvent
->getBubbles()) {
232 pEvent
->m_phase
= PhaseType_BUBBLING_PHASE
;
233 while (inode
!= captureVector
.end())
235 pEvent
->m_currentTarget
= inode
->first
;
236 callListeners(targetListeners
,
237 inode
->second
, aType
, xEvent
);
238 if (pEvent
->m_canceled
) return sal_True
;
247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */