1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include <eventdispatcher.hxx>
25 
26 #include <event.hxx>
27 #include <mutationevent.hxx>
28 #include <uievent.hxx>
29 #include <mouseevent.hxx>
30 
31 #include "../dom/document.hxx"
32 
33 
34 namespace DOM { namespace events {
35 
addListener(xmlNodePtr pNode,OUString aType,const Reference<XEventListener> & aListener,sal_Bool bCapture)36     void CEventDispatcher::addListener(xmlNodePtr pNode, OUString aType, const Reference<XEventListener>& aListener, sal_Bool bCapture)
37     {
38         TypeListenerMap *const pTMap = (bCapture)
39             ? (& m_CaptureListeners) : (& m_TargetListeners);
40 
41         // get the multimap for the specified type
42         ListenerMap *pMap = 0;
43         TypeListenerMap::const_iterator tIter = pTMap->find(aType);
44         if (tIter == pTMap->end()) {
45             // the map has to be created
46             pMap = new ListenerMap();
47             pTMap->insert(TypeListenerMap::value_type(aType, pMap));
48         } else {
49             pMap = tIter->second;
50         }
51         if (pMap !=0)
52             pMap->insert(ListenerMap::value_type(pNode, aListener));
53     }
54 
removeListener(xmlNodePtr pNode,OUString aType,const Reference<XEventListener> & aListener,sal_Bool bCapture)55     void CEventDispatcher::removeListener(xmlNodePtr pNode, OUString aType, const Reference<XEventListener>& aListener, sal_Bool bCapture)
56     {
57         TypeListenerMap *const pTMap = (bCapture)
58             ? (& m_CaptureListeners) : (& m_TargetListeners);
59 
60         // get the multimap for the specified type
61         TypeListenerMap::const_iterator tIter = pTMap->find(aType);
62         if (tIter != pTMap->end()) {
63             ListenerMap *pMap = tIter->second;
64             // find listeners of specied type for specified node
65             ListenerMap::iterator iter = pMap->find(pNode);
66             while (iter != pMap->end() && iter->first == pNode)
67             {
68                 // erase all references to specified listener
69                 if ((iter->second).is() && iter->second == aListener)
70                 {
71                     ListenerMap::iterator tmp_iter = iter;
72                     iter++;
73                     pMap->erase(tmp_iter);
74                 }
75                 else
76                     iter++;
77             }
78         }
79     }
80 
callListeners(TypeListenerMap const & rTMap,xmlNodePtr const pNode,OUString aType,Reference<XEvent> const & xEvent)81     void CEventDispatcher::callListeners(
82             TypeListenerMap const& rTMap,
83             xmlNodePtr const pNode,
84             OUString aType, Reference< XEvent > const& xEvent)
85     {
86         // get the multimap for the specified type
87         TypeListenerMap::const_iterator tIter = rTMap.find(aType);
88         if (tIter != rTMap.end()) {
89             ListenerMap *pMap = tIter->second;
90             ListenerMap::const_iterator iter = pMap->lower_bound(pNode);
91             ListenerMap::const_iterator ibound = pMap->upper_bound(pNode);
92             for( ; iter != ibound; iter++ )
93             {
94                 if((iter->second).is())
95                     (iter->second)->handleEvent(xEvent);
96             }
97         }
98     }
99 
dispatchEvent(DOM::CDocument & rDocument,::osl::Mutex & rMutex,xmlNodePtr const pNode,Reference<XNode> const & xNode,Reference<XEvent> const & i_xEvent) const100     bool CEventDispatcher::dispatchEvent(
101             DOM::CDocument & rDocument, ::osl::Mutex & rMutex,
102             xmlNodePtr const pNode, Reference<XNode> const& xNode,
103             Reference< XEvent > const& i_xEvent) const
104     {
105         CEvent *pEvent = 0; // pointer to internal event representation
106 
107         OUString const aType = i_xEvent->getType();
108         if (aType.compareToAscii("DOMSubtreeModified")          == 0||
109             aType.compareToAscii("DOMNodeInserted")             == 0||
110             aType.compareToAscii("DOMNodeRemoved")              == 0||
111             aType.compareToAscii("DOMNodeRemovedFromDocument")  == 0||
112             aType.compareToAscii("DOMNodeInsertedIntoDocument") == 0||
113             aType.compareToAscii("DOMAttrModified")             == 0||
114             aType.compareToAscii("DOMCharacterDataModified")    == 0)
115         {
116                 Reference< XMutationEvent > const aMEvent(i_xEvent,
117                         UNO_QUERY_THROW);
118                 // dispatch a mutation event
119                 // we need to clone the event in order to have complete control
120                 // over the implementation
121                 CMutationEvent* pMEvent = new CMutationEvent;
122                 pMEvent->initMutationEvent(
123                     aType, aMEvent->getBubbles(), aMEvent->getCancelable(),
124                     aMEvent->getRelatedNode(), aMEvent->getPrevValue(),
125                     aMEvent->getNewValue(), aMEvent->getAttrName(),
126                     aMEvent->getAttrChange());
127                 pEvent = pMEvent;
128         } else if ( // UIEvent
129             aType.compareToAscii("DOMFocusIn")  == 0||
130             aType.compareToAscii("DOMFocusOut") == 0||
131             aType.compareToAscii("DOMActivate") == 0)
132         {
133             Reference< XUIEvent > const aUIEvent(i_xEvent, UNO_QUERY_THROW);
134             CUIEvent* pUIEvent = new CUIEvent;
135             pUIEvent->initUIEvent(aType,
136                 aUIEvent->getBubbles(), aUIEvent->getCancelable(),
137                 aUIEvent->getView(), aUIEvent->getDetail());
138             pEvent = pUIEvent;
139         } else if ( // MouseEvent
140             aType.compareToAscii("click")     == 0||
141             aType.compareToAscii("mousedown") == 0||
142             aType.compareToAscii("mouseup")   == 0||
143             aType.compareToAscii("mouseover") == 0||
144             aType.compareToAscii("mousemove") == 0||
145             aType.compareToAscii("mouseout")  == 0)
146         {
147             Reference< XMouseEvent > const aMouseEvent(i_xEvent,
148                     UNO_QUERY_THROW);
149             CMouseEvent *pMouseEvent = new CMouseEvent;
150             pMouseEvent->initMouseEvent(aType,
151                 aMouseEvent->getBubbles(), aMouseEvent->getCancelable(),
152                 aMouseEvent->getView(), aMouseEvent->getDetail(),
153                 aMouseEvent->getScreenX(), aMouseEvent->getScreenY(),
154                 aMouseEvent->getClientX(), aMouseEvent->getClientY(),
155                 aMouseEvent->getCtrlKey(), aMouseEvent->getAltKey(),
156                 aMouseEvent->getShiftKey(), aMouseEvent->getMetaKey(),
157                 aMouseEvent->getButton(), aMouseEvent->getRelatedTarget());
158             pEvent = pMouseEvent;
159         }
160         else // generic event
161         {
162             pEvent = new CEvent;
163             pEvent->initEvent(
164                 aType, i_xEvent->getBubbles(), i_xEvent->getCancelable());
165         }
166         pEvent->m_target.set(xNode, UNO_QUERY_THROW);
167         pEvent->m_currentTarget = i_xEvent->getCurrentTarget();
168         pEvent->m_time = i_xEvent->getTimeStamp();
169 
170         // create the reference to the provate event implementation
171         // that will be dispatched to the listeners
172         Reference< XEvent > const xEvent(pEvent);
173 
174         // build the path from target node to the root
175         typedef std::vector< ::std::pair<Reference<XEventTarget>, xmlNodePtr> >
176             NodeVector_t;
177         NodeVector_t captureVector;
178         TypeListenerMap captureListeners;
179         TypeListenerMap targetListeners;
180         {
181             ::osl::MutexGuard g(rMutex);
182 
183             xmlNodePtr cur = pNode;
184             while (cur != NULL)
185             {
186                 Reference< XEventTarget > const xRef(
187                         rDocument.GetCNode(cur).get());
188                 captureVector.push_back(::std::make_pair(xRef, cur));
189                 cur = cur->parent;
190             }
191             captureListeners = m_CaptureListeners;
192             targetListeners = m_TargetListeners;
193         }
194 
195         // the caputre vector now holds the node path from target to root
196         // first we must search for capture listernes in order root to
197         // to target. after that, any target listeners have to be called
198         // then bubbeling phase listeners are called in target to root
199         // order
200         // start at the root
201         NodeVector_t::const_reverse_iterator rinode =
202             const_cast<NodeVector_t const&>(captureVector).rbegin();
203         if (rinode != const_cast<NodeVector_t const&>(captureVector).rend())
204         {
205             // capturing phase:
206             pEvent->m_phase = PhaseType_CAPTURING_PHASE;
207             while (rinode !=
208                     const_cast<NodeVector_t const&>(captureVector).rend())
209             {
210                 pEvent->m_currentTarget = rinode->first;
211                 callListeners(captureListeners, rinode->second, aType, xEvent);
212                 if  (pEvent->m_canceled) return sal_True;
213                 rinode++;
214             }
215 
216             NodeVector_t::const_iterator inode = captureVector.begin();
217 
218             // target phase
219             pEvent->m_phase = PhaseType_AT_TARGET;
220             pEvent->m_currentTarget = inode->first;
221             callListeners(targetListeners, inode->second, aType, xEvent);
222             if  (pEvent->m_canceled) return sal_True;
223             // bubbeling phase
224             inode++;
225             if (i_xEvent->getBubbles()) {
226                 pEvent->m_phase = PhaseType_BUBBLING_PHASE;
227                 while (inode != captureVector.end())
228                 {
229                     pEvent->m_currentTarget = inode->first;
230                     callListeners(targetListeners,
231                             inode->second, aType, xEvent);
232                     if  (pEvent->m_canceled) return sal_True;
233                     inode++;
234                 }
235             }
236         }
237         return sal_True;
238     }
239 }}
240