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