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