build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / unoxml / source / events / eventdispatcher.cxx
blob0dab5b9d0624814fa8d51bf1a5e36788b06c0549
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <event.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;
49 } else {
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;
73 ++iter;
74 rMap.erase(tmp_iter);
76 else
77 ++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,
122 UNO_QUERY_THROW);
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());
132 pEvent = pMEvent;
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());
143 pEvent = pUIEvent;
144 } else if ( // MouseEvent
145 aType == "click" ||
146 aType == "mousedown" ||
147 aType == "mouseup" ||
148 aType == "mouseover" ||
149 aType == "mousemove" ||
150 aType == "mouseout" )
152 Reference< XMouseEvent > const aMouseEvent(i_xEvent,
153 UNO_QUERY_THROW);
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
167 pEvent = new CEvent;
168 pEvent->initEvent(
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> >
181 NodeVector_t;
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));
194 cur = cur->parent;
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
204 // order
205 // start at the 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())
210 // capturing phase:
211 pEvent->m_phase = PhaseType_CAPTURING_PHASE;
212 while (rinode !=
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;
218 ++rinode;
221 NodeVector_t::const_iterator inode = captureVector.begin();
223 // target phase
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;
228 // bubbeling phase
229 ++inode;
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;
238 ++inode;
242 return true;
246 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */