1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <eventdispatcher.hxx>
32 #include <mutationevent.hxx>
33 #include <uievent.hxx>
34 #include <mouseevent.hxx>
36 #include "../dom/document.hxx"
39 namespace DOM
{ namespace events
{
41 void CEventDispatcher::addListener(xmlNodePtr pNode
, OUString aType
, const Reference
<XEventListener
>& aListener
, sal_Bool bCapture
)
43 TypeListenerMap
*const pTMap
= (bCapture
)
44 ? (& m_CaptureListeners
) : (& m_TargetListeners
);
46 // get the multimap for the specified type
47 ListenerMap
*pMap
= 0;
48 TypeListenerMap::const_iterator tIter
= pTMap
->find(aType
);
49 if (tIter
== pTMap
->end()) {
50 // the map has to be created
51 pMap
= new ListenerMap();
52 pTMap
->insert(TypeListenerMap::value_type(aType
, pMap
));
57 pMap
->insert(ListenerMap::value_type(pNode
, aListener
));
60 void CEventDispatcher::removeListener(xmlNodePtr pNode
, OUString aType
, const Reference
<XEventListener
>& aListener
, sal_Bool bCapture
)
62 TypeListenerMap
*const pTMap
= (bCapture
)
63 ? (& m_CaptureListeners
) : (& m_TargetListeners
);
65 // get the multimap for the specified type
66 TypeListenerMap::const_iterator tIter
= pTMap
->find(aType
);
67 if (tIter
!= pTMap
->end()) {
68 ListenerMap
*pMap
= tIter
->second
;
69 // find listeners of specied type for specified node
70 ListenerMap::iterator iter
= pMap
->find(pNode
);
71 while (iter
!= pMap
->end() && iter
->first
== pNode
)
73 // erase all references to specified listener
74 if ((iter
->second
).is() && iter
->second
== aListener
)
76 ListenerMap::iterator tmp_iter
= iter
;
78 pMap
->erase(tmp_iter
);
86 void CEventDispatcher::callListeners(
87 TypeListenerMap
const& rTMap
,
88 xmlNodePtr
const pNode
,
89 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
*pMap
= tIter
->second
;
95 ListenerMap::const_iterator iter
= pMap
->lower_bound(pNode
);
96 ListenerMap::const_iterator ibound
= pMap
->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
= 0; // pointer to internal event representation
112 OUString
const aType
= i_xEvent
->getType();
113 if (aType
.compareToAscii("DOMSubtreeModified") == 0||
114 aType
.compareToAscii("DOMNodeInserted") == 0||
115 aType
.compareToAscii("DOMNodeRemoved") == 0||
116 aType
.compareToAscii("DOMNodeRemovedFromDocument") == 0||
117 aType
.compareToAscii("DOMNodeInsertedIntoDocument") == 0||
118 aType
.compareToAscii("DOMAttrModified") == 0||
119 aType
.compareToAscii("DOMCharacterDataModified") == 0)
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
.compareToAscii("DOMFocusIn") == 0||
135 aType
.compareToAscii("DOMFocusOut") == 0||
136 aType
.compareToAscii("DOMActivate") == 0)
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
145 aType
.compareToAscii("click") == 0||
146 aType
.compareToAscii("mousedown") == 0||
147 aType
.compareToAscii("mouseup") == 0||
148 aType
.compareToAscii("mouseover") == 0||
149 aType
.compareToAscii("mousemove") == 0||
150 aType
.compareToAscii("mouseout") == 0)
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 provate 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
;
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 caputre vector now holds the node path from target to root
201 // first we must search for capture listernes 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 sal_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 sal_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 sal_True
;
246 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */