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