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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_xmloff.hxx" 30 #include <xmloff/XMLEventExport.hxx> 31 32 #ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP 33 #include <com/sun/star/beans/PropertyValue.hpp> 34 #endif 35 36 #ifndef _COM_SUN_STAR_DOCUMENT_XEVENTSSUPPLIER_HPP 37 #include <com/sun/star/document/XEventsSupplier.hpp> 38 #endif 39 40 #ifndef _COM_SUN_STAR_CONTAINER_XNAMEREPLACE_HPP 41 #include <com/sun/star/container/XNameReplace.hpp> 42 #endif 43 #include <tools/debug.hxx> 44 #include <xmloff/xmlexp.hxx> 45 #include <xmloff/xmltoken.hxx> 46 #include "xmloff/xmlnmspe.hxx" 47 #include <xmloff/nmspmap.hxx> 48 49 50 using namespace ::com::sun::star::uno; 51 52 using std::map; 53 using ::rtl::OUString; 54 using ::com::sun::star::beans::PropertyValue; 55 using ::com::sun::star::document::XEventsSupplier; 56 using ::com::sun::star::container::XNameReplace; 57 using ::com::sun::star::container::XNameAccess; 58 using ::xmloff::token::GetXMLToken; 59 using ::xmloff::token::XML_EVENT_LISTENERS; 60 61 62 XMLEventExport::XMLEventExport(SvXMLExport& rExp, 63 const XMLEventNameTranslation* pTranslationTable) : 64 sEventType(RTL_CONSTASCII_USTRINGPARAM("EventType")), 65 rExport(rExp), 66 bExtNamespace(false) 67 { 68 AddTranslationTable(pTranslationTable); 69 } 70 71 XMLEventExport::~XMLEventExport() 72 { 73 // delete all handlers 74 HandlerMap::iterator aEnd = aHandlerMap.end(); 75 for( HandlerMap::iterator aIter = 76 aHandlerMap.begin(); 77 aIter != aEnd; 78 aIter++ ) 79 { 80 delete aIter->second; 81 } 82 aHandlerMap.clear(); 83 } 84 85 void XMLEventExport::AddHandler( const OUString& rName, 86 XMLEventExportHandler* pHandler ) 87 { 88 DBG_ASSERT(pHandler != NULL, "Need EventExportHandler"); 89 if (pHandler != NULL) 90 { 91 aHandlerMap[rName] = pHandler; 92 } 93 } 94 95 void XMLEventExport::AddTranslationTable( 96 const XMLEventNameTranslation* pTransTable ) 97 { 98 if (NULL != pTransTable) 99 { 100 // put translation table into map 101 for(const XMLEventNameTranslation* pTrans = pTransTable; 102 pTrans->sAPIName != NULL; 103 pTrans++) 104 { 105 aNameTranslationMap[OUString::createFromAscii(pTrans->sAPIName)] = 106 XMLEventName(pTrans->nPrefix, pTrans->sXMLName); 107 } 108 } 109 // else? ignore! 110 } 111 112 void XMLEventExport::Export( Reference<XEventsSupplier> & rSupplier, 113 sal_Bool bWhitespace) 114 { 115 if (rSupplier.is()) 116 { 117 Reference<XNameAccess> xAccess(rSupplier->getEvents(), UNO_QUERY); 118 Export(xAccess, bWhitespace); 119 } 120 // else: no supplier, no export -> ignore! 121 } 122 123 void XMLEventExport::Export( Reference<XNameReplace> & rReplace, 124 sal_Bool bWhitespace) 125 { 126 Reference<XNameAccess> xAccess(rReplace, UNO_QUERY); 127 Export(xAccess, bWhitespace); 128 } 129 130 void XMLEventExport::Export( Reference<XNameAccess> & rAccess, 131 sal_Bool bWhitespace) 132 { 133 // early out if we don't actually get any events 134 if (!rAccess.is()) 135 { 136 return; 137 } 138 139 // have we already processed an element? 140 sal_Bool bStarted = sal_False; 141 142 // iterate over all event types 143 Sequence<OUString> aNames = rAccess->getElementNames(); 144 sal_Int32 nCount = aNames.getLength(); 145 for(sal_Int32 i = 0; i < nCount; i++) 146 { 147 // translate name 148 NameMap::iterator aIter = aNameTranslationMap.find(aNames[i]); 149 if (aIter != aNameTranslationMap.end()) 150 { 151 const XMLEventName& rXmlName = aIter->second; 152 153 // get PropertyValues for this event 154 Any aAny = rAccess->getByName( aNames[i] ); 155 Sequence<PropertyValue> aValues; 156 aAny >>= aValues; 157 158 // now export the current event 159 ExportEvent( aValues, rXmlName, bWhitespace, bStarted ); 160 } 161 #ifdef DBG_UTIL 162 else 163 { 164 // don't proceed further 165 ::rtl::OString aStr("Unknown event name:" ); 166 aStr += ::rtl::OUStringToOString( aNames[i], RTL_TEXTENCODING_UTF8 ); 167 DBG_ERROR( aStr.getStr() ); 168 } 169 #endif 170 } 171 172 // close <script:events> element (if it was opened before) 173 if (bStarted) 174 { 175 EndElement(bWhitespace); 176 } 177 } 178 179 void XMLEventExport::ExportExt( Reference<XNameAccess> & rAccess, 180 sal_Bool bWhitespace ) 181 { 182 // set bExtNamespace flag to use XML_NAMESPACE_OFFICE_EXT namespace 183 // for events element (not for child elements) 184 bExtNamespace = true; 185 Export(rAccess, bWhitespace); 186 bExtNamespace = false; // reset for future Export calls 187 } 188 189 /// export a singular event and wirte <office:events> container 190 void XMLEventExport::ExportSingleEvent( 191 Sequence<PropertyValue>& rEventValues, 192 const OUString& rApiEventName, 193 sal_Bool bUseWhitespace ) 194 { 195 // translate the name 196 NameMap::iterator aIter = aNameTranslationMap.find(rApiEventName); 197 if (aIter != aNameTranslationMap.end()) 198 { 199 const XMLEventName& rXmlName = aIter->second; 200 201 // export the event ... 202 sal_Bool bStarted = sal_False; 203 ExportEvent( rEventValues, rXmlName, bUseWhitespace, bStarted ); 204 205 // ... and close the container element (if necessary) 206 if (bStarted) 207 { 208 EndElement(bUseWhitespace); 209 } 210 } 211 #ifdef DBG_UTIL 212 else 213 { 214 // don't proceed further 215 ::rtl::OString aStr("Unknown event name:" ); 216 aStr += ::rtl::OUStringToOString( rApiEventName, RTL_TEXTENCODING_UTF8 ); 217 DBG_ERROR( aStr.getStr() ); 218 } 219 #endif 220 } 221 222 223 /// export a single event 224 void XMLEventExport::ExportEvent( 225 Sequence<PropertyValue>& rEventValues, 226 const XMLEventName& rXmlEventName, 227 sal_Bool bUseWhitespace, 228 sal_Bool& rExported ) 229 { 230 // search for EventType value and then delegate to EventHandler 231 sal_Int32 nValues = rEventValues.getLength(); 232 const PropertyValue* pValues = rEventValues.getConstArray(); 233 234 for(sal_Int32 nVal = 0; nVal < nValues; nVal++) 235 { 236 if (sEventType.equals(pValues[nVal].Name)) 237 { 238 // found! Now find handler and delegate 239 OUString sType; 240 pValues[nVal].Value >>= sType; 241 242 if (aHandlerMap.count(sType)) 243 { 244 if (! rExported) 245 { 246 // OK, we have't yet exported the enclosing 247 // element. So we do that now. 248 rExported = sal_True; 249 StartElement(bUseWhitespace); 250 } 251 252 OUString aEventQName( 253 rExport.GetNamespaceMap().GetQNameByKey( 254 rXmlEventName.m_nPrefix, rXmlEventName.m_aName ) ); 255 256 // delegate to proper ExportEventHandler 257 aHandlerMap[sType]->Export(rExport, aEventQName, 258 rEventValues, bUseWhitespace); 259 } 260 else 261 { 262 if (! sType.equalsAsciiL("None", sizeof("None")-1)) 263 { 264 DBG_ERROR("unknown event type returned by API"); 265 // unknown type -> error (ignore) 266 } 267 // else: we ignore None fields 268 } 269 270 // early out: we don't need to look for another type 271 break; 272 } 273 // else: we only care for EventType -> ignore 274 } 275 } 276 277 278 void XMLEventExport::StartElement(sal_Bool bWhitespace) 279 { 280 if (bWhitespace) 281 { 282 rExport.IgnorableWhitespace(); 283 } 284 sal_uInt16 nNamespace = bExtNamespace ? XML_NAMESPACE_OFFICE_EXT 285 : XML_NAMESPACE_OFFICE; 286 rExport.StartElement( nNamespace, XML_EVENT_LISTENERS, 287 bWhitespace); 288 } 289 290 void XMLEventExport::EndElement(sal_Bool bWhitespace) 291 { 292 sal_uInt16 nNamespace = bExtNamespace ? XML_NAMESPACE_OFFICE_EXT 293 : XML_NAMESPACE_OFFICE; 294 rExport.EndElement(nNamespace, XML_EVENT_LISTENERS, bWhitespace); 295 if (bWhitespace) 296 { 297 rExport.IgnorableWhitespace(); 298 } 299 } 300 301 302 // implement aStandardEventTable (defined in xmlevent.hxx) 303 const XMLEventNameTranslation aStandardEventTable[] = 304 { 305 { "OnSelect", XML_NAMESPACE_DOM, "select" }, // "on-select" 306 { "OnInsertStart", XML_NAMESPACE_OFFICE, "insert-start" }, // "on-insert-start" 307 { "OnInsertDone", XML_NAMESPACE_OFFICE, "insert-done" }, // "on-insert-done" 308 { "OnMailMerge", XML_NAMESPACE_OFFICE, "mail-merge" }, // "on-mail-merge" 309 { "OnAlphaCharInput", XML_NAMESPACE_OFFICE, "alpha-char-input" }, // "on-alpha-char-input" 310 { "OnNonAlphaCharInput", XML_NAMESPACE_OFFICE, "non-alpha-char-input" }, // "on-non-alpha-char-input" 311 { "OnResize", XML_NAMESPACE_DOM, "resize" }, // "on-resize" 312 { "OnMove", XML_NAMESPACE_OFFICE, "move" }, // "on-move" 313 { "OnPageCountChange", XML_NAMESPACE_OFFICE, "page-count-change" }, // "on-page-count-change" 314 { "OnMouseOver", XML_NAMESPACE_DOM, "mouseover" }, // "on-mouse-over" 315 { "OnClick", XML_NAMESPACE_DOM, "click" }, // "on-click" 316 { "OnMouseOut", XML_NAMESPACE_DOM, "mouseout" }, // "on-mouse-out" 317 { "OnLoadError", XML_NAMESPACE_OFFICE, "load-error" }, // "on-load-error" 318 { "OnLoadCancel", XML_NAMESPACE_OFFICE, "load-cancel" }, // "on-load-cancel" 319 { "OnLoadDone", XML_NAMESPACE_OFFICE, "load-done" }, // "on-load-done" 320 { "OnLoad", XML_NAMESPACE_DOM, "load" }, // "on-load" 321 { "OnUnload", XML_NAMESPACE_DOM, "unload" }, // "on-unload" 322 { "OnStartApp", XML_NAMESPACE_OFFICE, "start-app" }, // "on-start-app" 323 { "OnCloseApp", XML_NAMESPACE_OFFICE, "close-app" }, // "on-close-app" 324 { "OnNew", XML_NAMESPACE_OFFICE, "new" }, // "on-new" 325 { "OnSave", XML_NAMESPACE_OFFICE, "save" }, // "on-save" 326 { "OnSaveAs", XML_NAMESPACE_OFFICE, "save-as" }, // "on-save-as" 327 { "OnFocus", XML_NAMESPACE_DOM, "DOMFocusIn" }, // "on-focus" 328 { "OnUnfocus", XML_NAMESPACE_DOM, "DOMFocusOut" }, // "on-unfocus" 329 { "OnPrint", XML_NAMESPACE_OFFICE, "print" }, // "on-print" 330 { "OnError", XML_NAMESPACE_DOM, "error" }, // "on-error" 331 { "OnLoadFinished", XML_NAMESPACE_OFFICE, "load-finished" }, // "on-load-finished" 332 { "OnSaveFinished", XML_NAMESPACE_OFFICE, "save-finished" }, // "on-save-finished" 333 { "OnModifyChanged", XML_NAMESPACE_OFFICE, "modify-changed" }, // "on-modify-changed" 334 { "OnPrepareUnload", XML_NAMESPACE_OFFICE, "prepare-unload" }, // "on-prepare-unload" 335 { "OnNewMail", XML_NAMESPACE_OFFICE, "new-mail" }, // "on-new-mail" 336 { "OnToggleFullscreen", XML_NAMESPACE_OFFICE, "toggle-fullscreen" }, // "on-toggle-fullscreen" 337 { "OnSaveDone", XML_NAMESPACE_OFFICE, "save-done" }, // "on-save-done" 338 { "OnSaveAsDone", XML_NAMESPACE_OFFICE, "save-as-done" }, // "on-save-as-done" 339 { "OnCopyTo", XML_NAMESPACE_OFFICE, "copy-to" }, 340 { "OnCopyToDone", XML_NAMESPACE_OFFICE, "copy-to-done" }, 341 { "OnViewCreated", XML_NAMESPACE_OFFICE, "view-created" }, 342 { "OnPrepareViewClosing", XML_NAMESPACE_OFFICE, "prepare-view-closing" }, 343 { "OnViewClosed", XML_NAMESPACE_OFFICE, "view-close" }, 344 { "OnVisAreaChanged", XML_NAMESPACE_OFFICE, "visarea-changed" }, // "on-visarea-changed" 345 { "OnCreate", XML_NAMESPACE_OFFICE, "create" }, 346 { "OnSaveAsFailed", XML_NAMESPACE_OFFICE, "save-as-failed" }, 347 { "OnSaveFailed", XML_NAMESPACE_OFFICE, "save-failed" }, 348 { "OnCopyToFailed", XML_NAMESPACE_OFFICE, "copy-to-failed" }, 349 { "OnTitleChanged", XML_NAMESPACE_OFFICE, "title-changed" }, 350 { "OnModeChanged", XML_NAMESPACE_OFFICE, "mode-changed" }, 351 { "OnSaveTo", XML_NAMESPACE_OFFICE, "save-to" }, 352 { "OnSaveToDone", XML_NAMESPACE_OFFICE, "save-to-done" }, 353 { "OnSaveToFailed", XML_NAMESPACE_OFFICE, "save-to-failed" }, 354 { "OnSubComponentOpened", XML_NAMESPACE_OFFICE, "subcomponent-opened" }, 355 { "OnSubComponentClosed", XML_NAMESPACE_OFFICE, "subcomponent-closed" }, 356 { "OnStorageChanged", XML_NAMESPACE_OFFICE, "storage-changed" }, 357 { "OnMailMergeFinished", XML_NAMESPACE_OFFICE, "mail-merge-finished" }, 358 { "OnFieldMerge", XML_NAMESPACE_OFFICE, "field-merge" }, 359 { "OnFieldMergeFinished", XML_NAMESPACE_OFFICE, "field-merge-finished" }, 360 { "OnLayoutFinished", XML_NAMESPACE_OFFICE, "layout-finished" }, 361 { "OnDoubleClick", XML_NAMESPACE_OFFICE, "dblclick" }, 362 { "OnRightClick", XML_NAMESPACE_OFFICE, "contextmenu" }, 363 { "OnChange", XML_NAMESPACE_OFFICE, "content-changed" }, 364 { "OnCalculate", XML_NAMESPACE_OFFICE, "calculated" }, 365 366 { NULL, 0, 0 } 367 }; 368