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