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