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 "precompiled_sfx2.hxx" 25 26 #include "sal/config.h" 27 #include "cppuhelper/factory.hxx" 28 #include "cppuhelper/implementationentry.hxx" 29 #include "cppuhelper/compbase6.hxx" 30 #include "com/sun/star/lang/XServiceInfo.hpp" 31 #include "com/sun/star/document/XDocumentProperties.hpp" 32 #include "com/sun/star/lang/XInitialization.hpp" 33 #include "com/sun/star/util/XCloneable.hpp" 34 #include "com/sun/star/util/XModifiable.hpp" 35 #include "com/sun/star/xml/sax/XSAXSerializable.hpp" 36 37 #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" 38 #include "com/sun/star/lang/EventObject.hpp" 39 #include "com/sun/star/beans/XPropertySet.hpp" 40 #include "com/sun/star/beans/XPropertySetInfo.hpp" 41 #include "com/sun/star/beans/PropertyAttribute.hpp" 42 #include "com/sun/star/task/ErrorCodeIOException.hpp" 43 #include "com/sun/star/embed/XStorage.hpp" 44 #include "com/sun/star/embed/XTransactedObject.hpp" 45 #include "com/sun/star/embed/ElementModes.hpp" 46 #include "com/sun/star/io/XActiveDataControl.hpp" 47 #include "com/sun/star/io/XActiveDataSource.hpp" 48 #include "com/sun/star/io/XStream.hpp" 49 #include "com/sun/star/document/XImporter.hpp" 50 #include "com/sun/star/document/XExporter.hpp" 51 #include "com/sun/star/document/XFilter.hpp" 52 #include "com/sun/star/xml/sax/XParser.hpp" 53 #include "com/sun/star/xml/dom/XDocument.hpp" 54 #include "com/sun/star/xml/dom/XElement.hpp" 55 #include "com/sun/star/xml/dom/XDocumentBuilder.hpp" 56 #include "com/sun/star/xml/dom/XSAXDocumentBuilder.hpp" 57 #include "com/sun/star/xml/dom/NodeType.hpp" 58 #include "com/sun/star/xml/xpath/XXPathAPI.hpp" 59 #include "com/sun/star/util/Date.hpp" 60 #include "com/sun/star/util/Time.hpp" 61 #include "com/sun/star/util/Duration.hpp" 62 63 #include "SfxDocumentMetaData.hxx" 64 #include "rtl/ustrbuf.hxx" 65 #include "tools/debug.hxx" 66 #include "tools/string.hxx" // for DBG 67 #include "tools/datetime.hxx" 68 #include "tools/urlobj.hxx" 69 #include "osl/mutex.hxx" 70 #include "cppuhelper/basemutex.hxx" 71 #include "cppuhelper/interfacecontainer.hxx" 72 #include "comphelper/storagehelper.hxx" 73 #include "comphelper/mediadescriptor.hxx" 74 #include "comphelper/sequenceasvector.hxx" 75 #include "comphelper/stlunosequence.hxx" 76 #include "sot/storage.hxx" 77 #include "sfx2/docfile.hxx" 78 #include "sax/tools/converter.hxx" 79 80 #include <utility> 81 #include <vector> 82 #include <map> 83 #include <cstring> 84 #include <limits> 85 86 /** 87 * This file contains the implementation of the service 88 * com.sun.star.document.DocumentProperties. 89 * This service enables access to the meta-data stored in documents. 90 * Currently, this service only handles documents in ODF format. 91 * 92 * The implementation uses an XML DOM to store the properties. 93 * This approach was taken because it allows for preserving arbitrary XML data 94 * in loaded documents, which will be stored unmodified when saving the 95 * document again. 96 * 97 * Upon access, some properties are directly read from and updated in the DOM. 98 * Exception: it seems impossible to get notified upon addition of a property 99 * to a com.sun.star.beans.PropertyBag, which is used for storing user-defined 100 * properties; because of this, user-defined properties are updated in the 101 * XML DOM only when storing the document. 102 * Exception 2: when setting certain properties which correspond to attributes 103 * in the XML DOM, we want to remove the corresponding XML element. Detecting 104 * this condition can get messy, so we store all such properties as members, 105 * and update the DOM tree only when storing the document (in 106 * <method>updateUserDefinedAndAttributes</method>). 107 * 108 * @author mst 109 */ 110 111 /// anonymous implementation namespace 112 namespace { 113 114 namespace css = ::com::sun::star; 115 116 117 /// a list of attribute-lists, where attribute means name and content 118 typedef std::vector<std::vector<std::pair<const char*, ::rtl::OUString> > > 119 AttrVector; 120 121 typedef ::cppu::WeakComponentImplHelper6< 122 css::lang::XServiceInfo, 123 css::document::XDocumentProperties, 124 css::lang::XInitialization, 125 css::util::XCloneable, 126 css::util::XModifiable, 127 css::xml::sax::XSAXSerializable> 128 SfxDocumentMetaData_Base; 129 130 class SfxDocumentMetaData: 131 private ::cppu::BaseMutex, 132 public SfxDocumentMetaData_Base 133 { 134 public: 135 explicit SfxDocumentMetaData( 136 css::uno::Reference< css::uno::XComponentContext > const & context); 137 138 // ::com::sun::star::lang::XServiceInfo: 139 virtual ::rtl::OUString SAL_CALL getImplementationName(); 140 virtual ::sal_Bool SAL_CALL supportsService( 141 const ::rtl::OUString & ServiceName); 142 virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL 143 getSupportedServiceNames(); 144 145 // ::com::sun::star::lang::XComponent: 146 virtual void SAL_CALL dispose(); 147 148 // ::com::sun::star::document::XDocumentProperties: 149 virtual ::rtl::OUString SAL_CALL getAuthor(); 150 virtual void SAL_CALL setAuthor(const ::rtl::OUString & the_value); 151 virtual ::rtl::OUString SAL_CALL getGenerator(); 152 virtual void SAL_CALL setGenerator(const ::rtl::OUString & the_value); 153 virtual css::util::DateTime SAL_CALL getCreationDate(); 154 virtual void SAL_CALL setCreationDate(const css::util::DateTime & the_value); 155 virtual ::rtl::OUString SAL_CALL getTitle(); 156 virtual void SAL_CALL setTitle(const ::rtl::OUString & the_value); 157 virtual ::rtl::OUString SAL_CALL getSubject(); 158 virtual void SAL_CALL setSubject(const ::rtl::OUString & the_value); 159 virtual ::rtl::OUString SAL_CALL getDescription(); 160 virtual void SAL_CALL setDescription(const ::rtl::OUString & the_value); 161 virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL getKeywords(); 162 virtual void SAL_CALL setKeywords( 163 const css::uno::Sequence< ::rtl::OUString > & the_value); 164 virtual css::lang::Locale SAL_CALL getLanguage(); 165 virtual void SAL_CALL setLanguage(const css::lang::Locale & the_value); 166 virtual ::rtl::OUString SAL_CALL getModifiedBy(); 167 virtual void SAL_CALL setModifiedBy(const ::rtl::OUString & the_value); 168 virtual css::util::DateTime SAL_CALL getModificationDate(); 169 virtual void SAL_CALL setModificationDate( 170 const css::util::DateTime & the_value); 171 virtual ::rtl::OUString SAL_CALL getPrintedBy(); 172 virtual void SAL_CALL setPrintedBy(const ::rtl::OUString & the_value); 173 virtual css::util::DateTime SAL_CALL getPrintDate(); 174 virtual void SAL_CALL setPrintDate(const css::util::DateTime & the_value); 175 virtual ::rtl::OUString SAL_CALL getTemplateName(); 176 virtual void SAL_CALL setTemplateName(const ::rtl::OUString & the_value); 177 virtual ::rtl::OUString SAL_CALL getTemplateURL(); 178 virtual void SAL_CALL setTemplateURL(const ::rtl::OUString & the_value); 179 virtual css::util::DateTime SAL_CALL getTemplateDate(); 180 virtual void SAL_CALL setTemplateDate(const css::util::DateTime & the_value); 181 virtual ::rtl::OUString SAL_CALL getAutoloadURL(); 182 virtual void SAL_CALL setAutoloadURL(const ::rtl::OUString & the_value); 183 virtual ::sal_Int32 SAL_CALL getAutoloadSecs(); 184 virtual void SAL_CALL setAutoloadSecs(::sal_Int32 the_value); 185 virtual ::rtl::OUString SAL_CALL getDefaultTarget(); 186 virtual void SAL_CALL setDefaultTarget(const ::rtl::OUString & the_value); 187 virtual css::uno::Sequence< css::beans::NamedValue > SAL_CALL 188 getDocumentStatistics(); 189 virtual void SAL_CALL setDocumentStatistics( 190 const css::uno::Sequence< css::beans::NamedValue > & the_value); 191 virtual ::sal_Int16 SAL_CALL getEditingCycles(); 192 virtual void SAL_CALL setEditingCycles(::sal_Int16 the_value); 193 virtual ::sal_Int32 SAL_CALL getEditingDuration(); 194 virtual void SAL_CALL setEditingDuration(::sal_Int32 the_value); 195 virtual void SAL_CALL resetUserData(const ::rtl::OUString & the_value); 196 virtual css::uno::Reference< css::beans::XPropertyContainer > SAL_CALL 197 getUserDefinedProperties(); 198 virtual void SAL_CALL loadFromStorage( 199 const css::uno::Reference< css::embed::XStorage > & Storage, 200 const css::uno::Sequence< css::beans::PropertyValue > & Medium); 201 virtual void SAL_CALL loadFromMedium(const ::rtl::OUString & URL, 202 const css::uno::Sequence< css::beans::PropertyValue > & Medium); 203 virtual void SAL_CALL storeToStorage( 204 const css::uno::Reference< css::embed::XStorage > & Storage, 205 const css::uno::Sequence< css::beans::PropertyValue > & Medium); 206 virtual void SAL_CALL storeToMedium(const ::rtl::OUString & URL, 207 const css::uno::Sequence< css::beans::PropertyValue > & Medium); 208 209 // ::com::sun::star::lang::XInitialization: 210 virtual void SAL_CALL initialize( 211 const css::uno::Sequence< css::uno::Any > & aArguments); 212 213 // ::com::sun::star::util::XCloneable: 214 virtual css::uno::Reference<css::util::XCloneable> SAL_CALL createClone(); 215 216 // ::com::sun::star::util::XModifiable: 217 virtual ::sal_Bool SAL_CALL isModified( ); 218 virtual void SAL_CALL setModified( ::sal_Bool bModified ); 219 220 // ::com::sun::star::util::XModifyBroadcaster: 221 virtual void SAL_CALL addModifyListener( 222 const css::uno::Reference< css::util::XModifyListener > & xListener); 223 virtual void SAL_CALL removeModifyListener( 224 const css::uno::Reference< css::util::XModifyListener > & xListener); 225 226 // ::com::sun::star::xml::sax::XSAXSerializable 227 virtual void SAL_CALL serialize( 228 const css::uno::Reference<css::xml::sax::XDocumentHandler>& i_xHandler, 229 const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces); 230 231 private: 232 SfxDocumentMetaData(SfxDocumentMetaData &); // not defined 233 SfxDocumentMetaData& operator =(SfxDocumentMetaData &); // not defined 234 235 virtual ~SfxDocumentMetaData() {} 236 237 const css::uno::Reference< css::uno::XComponentContext > m_xContext; 238 239 /// for notification 240 ::cppu::OInterfaceContainerHelper m_NotifyListeners; 241 /// flag: false means not initialized yet, or disposed 242 bool m_isInitialized; 243 /// flag 244 bool m_isModified; 245 /// meta-data DOM tree 246 css::uno::Reference< css::xml::dom::XDocument > m_xDoc; 247 /// meta-data super node in the meta-data DOM tree 248 css::uno::Reference< css::xml::dom::XNode> m_xParent; 249 /// standard meta data (single occurrence) 250 std::map< ::rtl::OUString, css::uno::Reference<css::xml::dom::XNode> > 251 m_meta; 252 /// standard meta data (multiple occurrences) 253 std::map< ::rtl::OUString, 254 std::vector<css::uno::Reference<css::xml::dom::XNode> > > m_metaList; 255 /// user-defined meta data (meta:user-defined) @ATTENTION may be null! 256 css::uno::Reference<css::beans::XPropertyContainer> m_xUserDefined; 257 // now for some meta-data attributes; these are not updated directly in the 258 // DOM because updates (detecting "empty" elements) would be quite messy 259 ::rtl::OUString m_TemplateName; 260 ::rtl::OUString m_TemplateURL; 261 css::util::DateTime m_TemplateDate; 262 ::rtl::OUString m_AutoloadURL; 263 sal_Int32 m_AutoloadSecs; 264 ::rtl::OUString m_DefaultTarget; 265 266 /// check if we are initialized properly 267 void SAL_CALL checkInit() const; 268 // throw (css::uno::RuntimeException); 269 /// initialize state from given DOM tree 270 void SAL_CALL init(css::uno::Reference<css::xml::dom::XDocument> i_xDom); 271 // throw (css::uno::RuntimeException, css::io::WrongFormatException, 272 // css::uno::Exception); 273 /// update element in DOM tree 274 void SAL_CALL updateElement(const char *i_name, 275 std::vector<std::pair<const char *, ::rtl::OUString> >* i_pAttrs = 0); 276 /// update user-defined meta data and attributes in DOM tree 277 void SAL_CALL updateUserDefinedAndAttributes(); 278 /// create empty DOM tree (XDocument) 279 css::uno::Reference<css::xml::dom::XDocument> SAL_CALL createDOM() const; 280 /// extract base URL (necessary for converting relative links) 281 css::uno::Reference<css::beans::XPropertySet> SAL_CALL getURLProperties( 282 const css::uno::Sequence<css::beans::PropertyValue> & i_rMedium) const; 283 // throw (css::uno::RuntimeException); 284 /// get text of standard meta data element 285 ::rtl::OUString SAL_CALL getMetaText(const char* i_name) const; 286 // throw (css::uno::RuntimeException); 287 /// set text of standard meta data element iff not equal to existing text 288 bool SAL_CALL setMetaText(const char* i_name, 289 const ::rtl::OUString & i_rValue); 290 // throw (css::uno::RuntimeException); 291 /// set text of standard meta data element iff not equal to existing text 292 void SAL_CALL setMetaTextAndNotify(const char* i_name, 293 const ::rtl::OUString & i_rValue); 294 // throw (css::uno::RuntimeException); 295 /// get text of standard meta data element's attribute 296 ::rtl::OUString SAL_CALL getMetaAttr(const char* i_name, 297 const char* i_attr) const; 298 // throw (css::uno::RuntimeException); 299 /// get text of a list of standard meta data elements (multiple occ.) 300 css::uno::Sequence< ::rtl::OUString > SAL_CALL getMetaList( 301 const char* i_name) const; 302 // throw (css::uno::RuntimeException); 303 /// set text of a list of standard meta data elements (multiple occ.) 304 bool SAL_CALL setMetaList(const char* i_name, 305 const css::uno::Sequence< ::rtl::OUString > & i_rValue, 306 AttrVector const* = 0); 307 // throw (css::uno::RuntimeException); 308 void createUserDefined(); 309 }; 310 311 //////////////////////////////////////////////////////////////////////////// 312 313 bool operator== (const css::util::DateTime &i_rLeft, 314 const css::util::DateTime &i_rRight) 315 { 316 return i_rLeft.Year == i_rRight.Year 317 && i_rLeft.Month == i_rRight.Month 318 && i_rLeft.Day == i_rRight.Day 319 && i_rLeft.Hours == i_rRight.Hours 320 && i_rLeft.Minutes == i_rRight.Minutes 321 && i_rLeft.Seconds == i_rRight.Seconds 322 && i_rLeft.HundredthSeconds == i_rRight.HundredthSeconds; 323 } 324 325 // NB: keep these two arrays in sync! 326 const char* s_stdStatAttrs[] = { 327 "meta:page-count", 328 "meta:table-count", 329 "meta:draw-count", 330 "meta:image-count", 331 "meta:object-count", 332 "meta:ole-object-count", 333 "meta:paragraph-count", 334 "meta:word-count", 335 "meta:character-count", 336 "meta:row-count", 337 "meta:frame-count", 338 "meta:sentence-count", 339 "meta:syllable-count", 340 "meta:non-whitespace-character-count", 341 "meta:cell-count", 342 0 343 }; 344 345 // NB: keep these two arrays in sync! 346 const char* s_stdStats[] = { 347 "PageCount", 348 "TableCount", 349 "DrawCount", 350 "ImageCount", 351 "ObjectCount", 352 "OLEObjectCount", 353 "ParagraphCount", 354 "WordCount", 355 "CharacterCount", 356 "RowCount", 357 "FrameCount", 358 "SentenceCount", 359 "SyllableCount", 360 "NonWhitespaceCharacterCount", 361 "CellCount", 362 0 363 }; 364 365 const char* s_stdMeta[] = { 366 "meta:generator", // string 367 "dc:title", // string 368 "dc:description", // string 369 "dc:subject", // string 370 "meta:initial-creator", // string 371 "dc:creator", // string 372 "meta:printed-by", // string 373 "meta:creation-date", // dateTime 374 "dc:date", // dateTime 375 "meta:print-date", // dateTime 376 "meta:template", // XLink 377 "meta:auto-reload", // ... 378 "meta:hyperlink-behaviour", // ... 379 "dc:language", // language 380 "meta:editing-cycles", // nonNegativeInteger 381 "meta:editing-duration", // duration 382 "meta:document-statistic", // ... // note: statistic is singular, no s! 383 0 384 }; 385 386 const char* s_stdMetaList[] = { 387 "meta:keyword", // string* 388 "meta:user-defined", // ...* 389 0 390 }; 391 392 const char* s_nsXLink = "http://www.w3.org/1999/xlink"; 393 const char* s_nsDC = "http://purl.org/dc/elements/1.1/"; 394 const char* s_nsODF = "urn:oasis:names:tc:opendocument:xmlns:office:1.0"; 395 const char* s_nsODFMeta = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0"; 396 // const char* s_nsOOo = "http://openoffice.org/2004/office"; // not used (yet?) 397 398 const char* s_metaXml = "meta.xml"; 399 400 401 bool isValidDate(const css::util::Date & i_rDate) 402 { 403 return i_rDate.Month > 0; 404 } 405 406 bool isValidDateTime(const css::util::DateTime & i_rDateTime) 407 { 408 return i_rDateTime.Month > 0; 409 } 410 411 std::pair< ::rtl::OUString, ::rtl::OUString > SAL_CALL 412 getQualifier(const char* i_name) { 413 ::rtl::OUString nm = ::rtl::OUString::createFromAscii(i_name); 414 sal_Int32 ix = nm.indexOf(static_cast<sal_Unicode> (':')); 415 if (ix == -1) { 416 return std::make_pair(::rtl::OUString(), nm); 417 } else { 418 return std::make_pair(nm.copy(0,ix), nm.copy(ix+1)); 419 } 420 } 421 422 // get namespace for standard qualified names 423 // NB: only call this with statically known strings! 424 ::rtl::OUString SAL_CALL getNameSpace(const char* i_qname) throw () 425 { 426 DBG_ASSERT(i_qname, "SfxDocumentMetaData: getNameSpace: argument is null"); 427 const char * ns = ""; 428 ::rtl::OUString n = getQualifier(i_qname).first; 429 if (n.equalsAscii("xlink" )) ns = s_nsXLink; 430 if (n.equalsAscii("dc" )) ns = s_nsDC; 431 if (n.equalsAscii("office")) ns = s_nsODF; 432 if (n.equalsAscii("meta" )) ns = s_nsODFMeta; 433 DBG_ASSERT(*ns, "SfxDocumentMetaData: unknown namespace prefix"); 434 return ::rtl::OUString::createFromAscii(ns); 435 } 436 437 bool SAL_CALL 438 textToDateOrDateTime(css::util::Date & io_rd, css::util::DateTime & io_rdt, 439 bool & o_rIsDateTime, ::rtl::OUString i_text) throw () 440 { 441 if (::sax::Converter::convertDateOrDateTime( 442 io_rd, io_rdt, o_rIsDateTime, i_text)) { 443 return true; 444 } else { 445 DBG_WARNING1("SfxDocumentMetaData: invalid date: %s", 446 OUStringToOString(i_text, RTL_TEXTENCODING_UTF8).getStr()); 447 return false; 448 } 449 } 450 451 // convert string to date/time 452 bool SAL_CALL 453 textToDateTime(css::util::DateTime & io_rdt, ::rtl::OUString i_text) throw () 454 { 455 if (::sax::Converter::convertDateTime(io_rdt, i_text)) { 456 return true; 457 } else { 458 DBG_WARNING1("SfxDocumentMetaData: invalid date: %s", 459 OUStringToOString(i_text, RTL_TEXTENCODING_UTF8).getStr()); 460 return false; 461 } 462 } 463 464 // convert string to date/time with default return value 465 css::util::DateTime SAL_CALL 466 textToDateTimeDefault(::rtl::OUString i_text) throw () 467 { 468 css::util::DateTime dt; 469 static_cast<void> (textToDateTime(dt, i_text)); 470 // on conversion error: return default value (unchanged) 471 return dt; 472 } 473 474 // convert date to string 475 ::rtl::OUString SAL_CALL 476 dateToText(css::util::Date const& i_rd) throw () 477 { 478 if (isValidDate(i_rd)) { 479 ::rtl::OUStringBuffer buf; 480 ::sax::Converter::convertDate(buf, i_rd); 481 return buf.makeStringAndClear(); 482 } else { 483 return ::rtl::OUString(); 484 } 485 } 486 487 488 // convert date/time to string 489 ::rtl::OUString SAL_CALL 490 dateTimeToText(css::util::DateTime const& i_rdt) throw () 491 { 492 if (isValidDateTime(i_rdt)) { 493 ::rtl::OUStringBuffer buf; 494 ::sax::Converter::convertDateTime(buf, i_rdt, true); 495 return buf.makeStringAndClear(); 496 } else { 497 return ::rtl::OUString(); 498 } 499 } 500 501 // convert string to duration 502 bool 503 textToDuration(css::util::Duration& io_rDur, ::rtl::OUString const& i_rText) 504 throw () 505 { 506 if (::sax::Converter::convertDuration(io_rDur, i_rText)) { 507 return true; 508 } else { 509 DBG_WARNING1("SfxDocumentMetaData: invalid duration: %s", 510 OUStringToOString(i_rText, RTL_TEXTENCODING_UTF8).getStr()); 511 return false; 512 } 513 } 514 515 sal_Int32 textToDuration(::rtl::OUString const& i_rText) throw () 516 { 517 css::util::Duration d; 518 if (textToDuration(d, i_rText)) { 519 // #i107372#: approximate years/months 520 const sal_Int32 days( (d.Years * 365) + (d.Months * 30) + d.Days ); 521 return (days * (24*3600)) 522 + (d.Hours * 3600) + (d.Minutes * 60) + d.Seconds; 523 } else { 524 return 0; // default 525 } 526 } 527 528 // convert duration to string 529 ::rtl::OUString durationToText(css::util::Duration const& i_rDur) throw () 530 { 531 ::rtl::OUStringBuffer buf; 532 ::sax::Converter::convertDuration(buf, i_rDur); 533 return buf.makeStringAndClear(); 534 } 535 536 // convert duration to string 537 ::rtl::OUString SAL_CALL durationToText(sal_Int32 i_value) throw () 538 { 539 css::util::Duration ud; 540 ud.Days = static_cast<sal_Int16>(i_value / (24 * 3600)); 541 ud.Hours = static_cast<sal_Int16>((i_value % (24 * 3600)) / 3600); 542 ud.Minutes = static_cast<sal_Int16>((i_value % 3600) / 60); 543 ud.Seconds = static_cast<sal_Int16>(i_value % 60); 544 ud.MilliSeconds = 0; 545 return durationToText(ud); 546 } 547 548 // extract base URL (necessary for converting relative links) 549 css::uno::Reference< css::beans::XPropertySet > SAL_CALL 550 SfxDocumentMetaData::getURLProperties( 551 const css::uno::Sequence< css::beans::PropertyValue > & i_rMedium) const 552 { 553 css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( 554 m_xContext->getServiceManager()); 555 css::uno::Reference< css::beans::XPropertyContainer> xPropArg( 556 xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( 557 "com.sun.star.beans.PropertyBag"), m_xContext), 558 css::uno::UNO_QUERY_THROW); 559 try { 560 ::rtl::OUString dburl = 561 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DocumentBaseURL")); 562 ::rtl::OUString hdn = 563 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("HierarchicalDocumentName")); 564 for (sal_Int32 i = 0; i < i_rMedium.getLength(); ++i) { 565 if (i_rMedium[i].Name.equals(dburl)) { 566 xPropArg->addProperty( 567 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI")), 568 css::beans::PropertyAttribute::MAYBEVOID, 569 i_rMedium[i].Value); 570 } else if (i_rMedium[i].Name.equals(hdn)) { 571 xPropArg->addProperty( 572 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StreamRelPath")), 573 css::beans::PropertyAttribute::MAYBEVOID, 574 i_rMedium[i].Value); 575 } 576 } 577 xPropArg->addProperty(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StreamName")), 578 css::beans::PropertyAttribute::MAYBEVOID, 579 css::uno::makeAny(::rtl::OUString::createFromAscii(s_metaXml))); 580 } catch (css::uno::Exception &) { 581 // ignore 582 } 583 return css::uno::Reference< css::beans::XPropertySet>(xPropArg, 584 css::uno::UNO_QUERY_THROW); 585 } 586 587 // return the text of the (hopefully unique, i.e., normalize first!) text 588 // node _below_ the given node 589 ::rtl::OUString SAL_CALL 590 getNodeText(css::uno::Reference<css::xml::dom::XNode> i_xNode) 591 { 592 if (!i_xNode.is()) throw css::uno::RuntimeException( 593 ::rtl::OUString::createFromAscii( 594 "SfxDocumentMetaData::getNodeText: argument is null"), i_xNode); 595 for (css::uno::Reference<css::xml::dom::XNode> c = i_xNode->getFirstChild(); 596 c.is(); 597 c = c->getNextSibling()) { 598 if (c->getNodeType() == css::xml::dom::NodeType_TEXT_NODE) { 599 try { 600 return c->getNodeValue(); 601 } catch (css::xml::dom::DOMException &) { // too big? 602 return ::rtl::OUString(); 603 } 604 } 605 } 606 return ::rtl::OUString(); 607 } 608 609 ::rtl::OUString SAL_CALL 610 SfxDocumentMetaData::getMetaText(const char* i_name) const 611 // throw (css::uno::RuntimeException) 612 { 613 checkInit(); 614 615 const ::rtl::OUString name( ::rtl::OUString::createFromAscii(i_name) ); 616 DBG_ASSERT(m_meta.find(name) != m_meta.end(), 617 "SfxDocumentMetaData::getMetaText: not found"); 618 css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second; 619 return (xNode.is()) ? getNodeText(xNode) : ::rtl::OUString(); 620 } 621 622 bool SAL_CALL 623 SfxDocumentMetaData::setMetaText(const char* i_name, 624 const ::rtl::OUString & i_rValue) 625 // throw (css::uno::RuntimeException) 626 { 627 checkInit(); 628 629 const ::rtl::OUString name( ::rtl::OUString::createFromAscii(i_name) ); 630 DBG_ASSERT(m_meta.find(name) != m_meta.end(), 631 "SfxDocumentMetaData::setMetaText: not found"); 632 css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second; 633 634 try { 635 if (i_rValue.equalsAscii("")) { 636 if (xNode.is()) { // delete 637 m_xParent->removeChild(xNode); 638 xNode.clear(); 639 m_meta[name] = xNode; 640 return true; 641 } else { 642 return false; 643 } 644 } else { 645 if (xNode.is()) { // update 646 for (css::uno::Reference<css::xml::dom::XNode> c = 647 xNode->getFirstChild(); 648 c.is(); 649 c = c->getNextSibling()) { 650 if (c->getNodeType() == css::xml::dom::NodeType_TEXT_NODE) { 651 if (!c->getNodeValue().equals(i_rValue)) { 652 c->setNodeValue(i_rValue); 653 return true; 654 } else { 655 return false; 656 } 657 } 658 } 659 } else { // insert 660 xNode.set(m_xDoc->createElementNS(getNameSpace(i_name), name), 661 css::uno::UNO_QUERY_THROW); 662 m_xParent->appendChild(xNode); 663 m_meta[name] = xNode; 664 } 665 css::uno::Reference<css::xml::dom::XNode> xTextNode( 666 m_xDoc->createTextNode(i_rValue), css::uno::UNO_QUERY_THROW); 667 xNode->appendChild(xTextNode); 668 return true; 669 } 670 } catch (css::xml::dom::DOMException & e) { 671 css::uno::Any a(e); 672 throw css::lang::WrappedTargetRuntimeException( 673 ::rtl::OUString::createFromAscii( 674 "SfxDocumentMetaData::setMetaText: DOM exception"), 675 css::uno::Reference<css::uno::XInterface>(*this), a); 676 } 677 } 678 679 void SAL_CALL 680 SfxDocumentMetaData::setMetaTextAndNotify(const char* i_name, 681 const ::rtl::OUString & i_rValue) 682 // throw (css::uno::RuntimeException) 683 { 684 ::osl::ClearableMutexGuard g(m_aMutex); 685 if (setMetaText(i_name, i_rValue)) { 686 g.clear(); 687 setModified(true); 688 } 689 } 690 691 ::rtl::OUString SAL_CALL 692 SfxDocumentMetaData::getMetaAttr(const char* i_name, const char* i_attr) const 693 // throw (css::uno::RuntimeException) 694 { 695 // checkInit(); 696 ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name); 697 DBG_ASSERT(m_meta.find(name) != m_meta.end(), 698 "SfxDocumentMetaData::getMetaAttr: not found"); 699 css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second; 700 if (xNode.is()) { 701 css::uno::Reference<css::xml::dom::XElement> xElem(xNode, 702 css::uno::UNO_QUERY_THROW); 703 return xElem->getAttributeNS(getNameSpace(i_attr), 704 getQualifier(i_attr).second); 705 } else { 706 return ::rtl::OUString(); 707 } 708 } 709 710 css::uno::Sequence< ::rtl::OUString> SAL_CALL 711 SfxDocumentMetaData::getMetaList(const char* i_name) const 712 // throw (css::uno::RuntimeException) 713 { 714 checkInit(); 715 ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name); 716 DBG_ASSERT(m_metaList.find(name) != m_metaList.end(), 717 "SfxDocumentMetaData::getMetaList: not found"); 718 std::vector<css::uno::Reference<css::xml::dom::XNode> > const & vec = 719 m_metaList.find(name)->second; 720 css::uno::Sequence< ::rtl::OUString> ret(vec.size()); 721 for (size_t i = 0; i < vec.size(); ++i) { 722 ret[i] = getNodeText(vec.at(i)); 723 } 724 return ret; 725 } 726 727 bool SAL_CALL 728 SfxDocumentMetaData::setMetaList(const char* i_name, 729 const css::uno::Sequence< ::rtl::OUString> & i_rValue, 730 AttrVector const* i_pAttrs) 731 // throw (css::uno::RuntimeException) 732 { 733 checkInit(); 734 DBG_ASSERT((i_pAttrs == 0) || 735 (static_cast<size_t>(i_rValue.getLength()) == i_pAttrs->size()), 736 "SfxDocumentMetaData::setMetaList: invalid args"); 737 738 try { 739 ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name); 740 DBG_ASSERT(m_metaList.find(name) != m_metaList.end(), 741 "SfxDocumentMetaData::setMetaList: not found"); 742 std::vector<css::uno::Reference<css::xml::dom::XNode> > & vec = 743 m_metaList[name]; 744 745 // if nothing changed, do nothing 746 // alas, this does not check for permutations, or attributes... 747 if ((0 == i_pAttrs)) { 748 if (static_cast<size_t>(i_rValue.getLength()) == vec.size()) { 749 bool isEqual(true); 750 for (sal_Int32 i = 0; i < i_rValue.getLength(); ++i) { 751 css::uno::Reference<css::xml::dom::XNode> xNode(vec.at(i)); 752 if (xNode.is()) { 753 ::rtl::OUString val = getNodeText(xNode); 754 if (!val.equals(i_rValue[i])) { 755 isEqual = false; 756 break; 757 } 758 } 759 } 760 if (isEqual) return false; 761 } 762 } 763 764 // remove old meta data nodes 765 { 766 std::vector<css::uno::Reference<css::xml::dom::XNode> > 767 ::reverse_iterator it(vec.rbegin()); 768 try { 769 for ( ;it != vec.rend(); ++it) 770 { 771 m_xParent->removeChild(*it); 772 } 773 } 774 catch (...) 775 { 776 // Clean up already removed nodes 777 vec.erase(it.base(), vec.end()); 778 throw; 779 } 780 vec.clear(); 781 } 782 783 // insert new meta data nodes into DOM tree 784 for (sal_Int32 i = 0; i < i_rValue.getLength(); ++i) { 785 css::uno::Reference<css::xml::dom::XElement> xElem( 786 m_xDoc->createElementNS(getNameSpace(i_name), name), 787 css::uno::UNO_QUERY_THROW); 788 css::uno::Reference<css::xml::dom::XNode> xNode(xElem, 789 css::uno::UNO_QUERY_THROW); 790 css::uno::Reference<css::xml::dom::XNode> xTextNode( 791 m_xDoc->createTextNode(i_rValue[i]), css::uno::UNO_QUERY_THROW); 792 // set attributes 793 if (i_pAttrs != 0) { 794 for (std::vector<std::pair<const char*, ::rtl::OUString> > 795 ::const_iterator it = (*i_pAttrs)[i].begin(); 796 it != (*i_pAttrs)[i].end(); ++it) { 797 xElem->setAttributeNS(getNameSpace(it->first), 798 ::rtl::OUString::createFromAscii(it->first), 799 it->second); 800 } 801 } 802 xNode->appendChild(xTextNode); 803 m_xParent->appendChild(xNode); 804 vec.push_back(xNode); 805 } 806 807 return true; 808 } catch (css::xml::dom::DOMException & e) { 809 css::uno::Any a(e); 810 throw css::lang::WrappedTargetRuntimeException( 811 ::rtl::OUString::createFromAscii( 812 "SfxDocumentMetaData::setMetaList: DOM exception"), 813 css::uno::Reference<css::uno::XInterface>(*this), a); 814 } 815 } 816 817 // convert property list to string list and attribute list 818 std::pair<css::uno::Sequence< ::rtl::OUString>, AttrVector> SAL_CALL 819 propsToStrings(css::uno::Reference<css::beans::XPropertySet> const & i_xPropSet) 820 { 821 ::comphelper::SequenceAsVector< ::rtl::OUString > values; 822 AttrVector attrs; 823 824 css::uno::Reference<css::beans::XPropertySetInfo> xSetInfo 825 = i_xPropSet->getPropertySetInfo(); 826 css::uno::Sequence<css::beans::Property> props = xSetInfo->getProperties(); 827 828 for (sal_Int32 i = 0; i < props.getLength(); ++i) { 829 if (props[i].Attributes & css::beans::PropertyAttribute::TRANSIENT) { 830 continue; 831 } 832 const ::rtl::OUString name = props[i].Name; 833 css::uno::Any any; 834 try { 835 any = i_xPropSet->getPropertyValue(name); 836 } catch (css::uno::Exception &) { 837 // ignore 838 } 839 const css::uno::Type & type = any.getValueType(); 840 std::vector<std::pair<const char*, ::rtl::OUString> > as; 841 as.push_back(std::make_pair(static_cast<const char*>("meta:name"), 842 name)); 843 const char* vt = "meta:value-type"; 844 845 // convert according to type 846 if (type == ::cppu::UnoType<bool>::get()) { 847 bool b = false; 848 any >>= b; 849 ::rtl::OUStringBuffer buf; 850 ::sax::Converter::convertBool(buf, b); 851 values.push_back(buf.makeStringAndClear()); 852 as.push_back(std::make_pair(vt, 853 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("boolean")))); 854 } else if (type == ::cppu::UnoType< ::rtl::OUString>::get()) { 855 ::rtl::OUString s; 856 any >>= s; 857 values.push_back(s); 858 // #i90847# OOo 2.x does stupid things if value-type="string"; 859 // fortunately string is default anyway, so we can just omit it 860 // #i107502#: however, OOo 2.x only reads 4 user-defined without @value-type 861 // => best backward compatibility: first 4 without @value-type, rest with 862 if (4 <= i) 863 { 864 as.push_back(std::make_pair(vt, 865 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("string")))); 866 } 867 } else if (type == ::cppu::UnoType<css::util::DateTime>::get()) { 868 css::util::DateTime dt; 869 any >>= dt; 870 values.push_back(dateTimeToText(dt)); 871 as.push_back(std::make_pair(vt, 872 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("date")))); 873 } else if (type == ::cppu::UnoType<css::util::Date>::get()) { 874 css::util::Date d; 875 any >>= d; 876 values.push_back(dateToText(d)); 877 as.push_back(std::make_pair(vt, 878 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("date")))); 879 } else if (type == ::cppu::UnoType<css::util::Time>::get()) { 880 // #i97029#: replaced by Duration 881 // Time is supported for backward compatibility with OOo 3.x, x<=2 882 css::util::Time ut; 883 any >>= ut; 884 css::util::Duration ud; 885 ud.Hours = ut.Hours; 886 ud.Minutes = ut.Minutes; 887 ud.Seconds = ut.Seconds; 888 ud.MilliSeconds = 10 * ut.HundredthSeconds; 889 values.push_back(durationToText(ud)); 890 as.push_back(std::make_pair(vt, 891 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("time")))); 892 } else if (type == ::cppu::UnoType<css::util::Duration>::get()) { 893 css::util::Duration ud; 894 any >>= ud; 895 values.push_back(durationToText(ud)); 896 as.push_back(std::make_pair(vt, 897 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("time")))); 898 } else if (::cppu::UnoType<double>::get().isAssignableFrom(type)) { 899 // support not just double, but anything that can be converted 900 double d = 0; 901 any >>= d; 902 ::rtl::OUStringBuffer buf; 903 ::sax::Converter::convertDouble(buf, d); 904 values.push_back(buf.makeStringAndClear()); 905 as.push_back(std::make_pair(vt, 906 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("float")))); 907 } else { 908 DBG_WARNING1("SfxDocumentMetaData: unsupported property type: %s", 909 OUStringToOString(any.getValueTypeName(), 910 RTL_TEXTENCODING_UTF8).getStr()); 911 continue; 912 } 913 attrs.push_back(as); 914 } 915 916 return std::make_pair(values.getAsConstList(), attrs); 917 } 918 919 // remove the given element from the DOM, and iff i_pAttrs != 0 insert new one 920 void SAL_CALL 921 SfxDocumentMetaData::updateElement(const char *i_name, 922 std::vector<std::pair<const char *, ::rtl::OUString> >* i_pAttrs) 923 { 924 ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name); 925 try { 926 // remove old element 927 css::uno::Reference<css::xml::dom::XNode> xNode = 928 m_meta.find(name)->second; 929 if (xNode.is()) { 930 m_xParent->removeChild(xNode); 931 xNode.clear(); 932 } 933 // add new element 934 if (0 != i_pAttrs) { 935 css::uno::Reference<css::xml::dom::XElement> xElem( 936 m_xDoc->createElementNS(getNameSpace(i_name), name), 937 css::uno::UNO_QUERY_THROW); 938 xNode.set(xElem, css::uno::UNO_QUERY_THROW); 939 // set attributes 940 for (std::vector<std::pair<const char *, ::rtl::OUString> > 941 ::const_iterator it = i_pAttrs->begin(); 942 it != i_pAttrs->end(); ++it) { 943 xElem->setAttributeNS(getNameSpace(it->first), 944 ::rtl::OUString::createFromAscii(it->first), it->second); 945 } 946 m_xParent->appendChild(xNode); 947 } 948 m_meta[name] = xNode; 949 } catch (css::xml::dom::DOMException & e) { 950 css::uno::Any a(e); 951 throw css::lang::WrappedTargetRuntimeException( 952 ::rtl::OUString::createFromAscii( 953 "SfxDocumentMetaData::updateElement: DOM exception"), 954 css::uno::Reference<css::uno::XInterface>(*this), a); 955 } 956 } 957 958 // update user-defined meta data in DOM tree 959 void SAL_CALL SfxDocumentMetaData::updateUserDefinedAndAttributes() 960 { 961 createUserDefined(); 962 const css::uno::Reference<css::beans::XPropertySet> xPSet(m_xUserDefined, 963 css::uno::UNO_QUERY_THROW); 964 const std::pair<css::uno::Sequence< ::rtl::OUString>, AttrVector> 965 udStringsAttrs( propsToStrings(xPSet) ); 966 (void) setMetaList("meta:user-defined", udStringsAttrs.first, 967 &udStringsAttrs.second); 968 969 // update elements with attributes 970 std::vector<std::pair<const char *, ::rtl::OUString> > attributes; 971 if (!m_TemplateName.equalsAscii("") || !m_TemplateURL.equalsAscii("") 972 || isValidDateTime(m_TemplateDate)) { 973 attributes.push_back(std::make_pair( 974 static_cast<const char*>("xlink:type"), 975 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("simple")))); 976 attributes.push_back(std::make_pair( 977 static_cast<const char*>("xlink:actuate"), 978 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("onRequest")))); 979 attributes.push_back(std::make_pair( 980 static_cast<const char*>("xlink:title"), m_TemplateName)); 981 attributes.push_back(std::make_pair( 982 static_cast<const char*>("xlink:href" ), m_TemplateURL )); 983 if (isValidDateTime(m_TemplateDate)) { 984 attributes.push_back(std::make_pair( 985 static_cast<const char*>("meta:date" ), 986 dateTimeToText(m_TemplateDate))); 987 } 988 updateElement("meta:template", &attributes); 989 } else { 990 updateElement("meta:template"); 991 } 992 attributes.clear(); 993 994 if (!m_AutoloadURL.equalsAscii("") || (0 != m_AutoloadSecs)) { 995 attributes.push_back(std::make_pair( 996 static_cast<const char*>("xlink:href" ), m_AutoloadURL )); 997 attributes.push_back(std::make_pair( 998 static_cast<const char*>("meta:delay" ), 999 durationToText(m_AutoloadSecs))); 1000 updateElement("meta:auto-reload", &attributes); 1001 } else { 1002 updateElement("meta:auto-reload"); 1003 } 1004 attributes.clear(); 1005 1006 if (!m_DefaultTarget.equalsAscii("")) { 1007 attributes.push_back(std::make_pair( 1008 static_cast<const char*>("office:target-frame-name"), 1009 m_DefaultTarget)); 1010 // xlink:show: _blank -> new, any other value -> replace 1011 const sal_Char* show = m_DefaultTarget.equalsAscii("_blank") 1012 ? "new" : "replace"; 1013 attributes.push_back(std::make_pair( 1014 static_cast<const char*>("xlink:show"), 1015 ::rtl::OUString::createFromAscii(show))); 1016 updateElement("meta:hyperlink-behaviour", &attributes); 1017 } else { 1018 updateElement("meta:hyperlink-behaviour"); 1019 } 1020 attributes.clear(); 1021 } 1022 1023 // create empty DOM tree (XDocument) 1024 css::uno::Reference<css::xml::dom::XDocument> SAL_CALL 1025 SfxDocumentMetaData::createDOM() const // throw (css::uno::RuntimeException) 1026 { 1027 css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( 1028 m_xContext->getServiceManager()); 1029 css::uno::Reference<css::xml::dom::XDocumentBuilder> xBuilder( 1030 xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( 1031 "com.sun.star.xml.dom.DocumentBuilder"), m_xContext), 1032 css::uno::UNO_QUERY_THROW ); 1033 if (!xBuilder.is()) throw css::uno::RuntimeException( 1034 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::createDOM: " 1035 "cannot create DocumentBuilder service"), 1036 *const_cast<SfxDocumentMetaData*>(this)); 1037 css::uno::Reference<css::xml::dom::XDocument> xDoc = 1038 xBuilder->newDocument(); 1039 if (!xDoc.is()) throw css::uno::RuntimeException( 1040 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::createDOM: " 1041 "cannot create new document"), 1042 *const_cast<SfxDocumentMetaData*>(this)); 1043 return xDoc; 1044 } 1045 1046 void SAL_CALL 1047 SfxDocumentMetaData::checkInit() const // throw (css::uno::RuntimeException) 1048 { 1049 if (!m_isInitialized) { 1050 throw css::uno::RuntimeException(::rtl::OUString::createFromAscii( 1051 "SfxDocumentMetaData::checkInit: not initialized"), 1052 *const_cast<SfxDocumentMetaData*>(this)); 1053 } 1054 DBG_ASSERT((m_xDoc.is() && m_xParent.is() ), 1055 "SfxDocumentMetaData::checkInit: reference is null"); 1056 } 1057 1058 // initialize state from DOM tree 1059 void SAL_CALL SfxDocumentMetaData::init( 1060 css::uno::Reference<css::xml::dom::XDocument> i_xDoc) 1061 // throw (css::uno::RuntimeException, css::io::WrongFormatException, 1062 // css::uno::Exception) 1063 { 1064 if (!i_xDoc.is()) throw css::uno::RuntimeException( 1065 ::rtl::OUString::createFromAscii( 1066 "SfxDocumentMetaData::init: no DOM tree given"), *this); 1067 1068 css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( 1069 m_xContext->getServiceManager()); 1070 css::uno::Reference<css::xml::xpath::XXPathAPI> xPath( 1071 xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( 1072 "com.sun.star.xml.xpath.XPathAPI"), m_xContext), 1073 css::uno::UNO_QUERY_THROW ); 1074 if (!xPath.is()) throw css::uno::RuntimeException( 1075 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::init:" 1076 " cannot create XPathAPI service"), *this); 1077 1078 m_isInitialized = false; 1079 m_xDoc = i_xDoc; 1080 1081 // select nodes for standard meta data stuff 1082 xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xlink")), 1083 ::rtl::OUString::createFromAscii(s_nsXLink)); 1084 xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("dc")), 1085 ::rtl::OUString::createFromAscii(s_nsDC)); 1086 xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("office")), 1087 ::rtl::OUString::createFromAscii(s_nsODF)); 1088 xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("meta")), 1089 ::rtl::OUString::createFromAscii(s_nsODFMeta)); 1090 // NB: we do not handle the single-XML-file ODF variant, which would 1091 // have the root element office:document. 1092 // The root of such documents must be converted in the importer! 1093 ::rtl::OUString prefix = ::rtl::OUString::createFromAscii( 1094 "/child::office:document-meta/child::office:meta"); 1095 css::uno::Reference<css::xml::dom::XNode> xDocNode( 1096 m_xDoc, css::uno::UNO_QUERY_THROW); 1097 m_xParent.clear(); 1098 try { 1099 m_xParent = xPath->selectSingleNode(xDocNode, prefix); 1100 } catch (com::sun::star::uno::Exception &) { 1101 // DBG_WARNING("SfxDocumentMetaData::init: " 1102 // "caught RuntimeException from libxml!"); 1103 } 1104 1105 if (!m_xParent.is()) { 1106 // all this create/append stuff may throw DOMException 1107 try { 1108 css::uno::Reference<css::xml::dom::XElement> xRElem; 1109 css::uno::Reference<css::xml::dom::XNode> xNode( 1110 i_xDoc->getFirstChild()); 1111 while (xNode.is()) { 1112 if (css::xml::dom::NodeType_ELEMENT_NODE ==xNode->getNodeType()) 1113 { 1114 if (xNode->getNamespaceURI().equalsAscii(s_nsODF) && 1115 xNode->getLocalName().equalsAscii("document-meta")) 1116 { 1117 xRElem.set(xNode, css::uno::UNO_QUERY_THROW); 1118 break; 1119 } 1120 else 1121 { 1122 OSL_TRACE("SfxDocumentMetaData::init(): " 1123 "deleting unexpected root element: %s", 1124 ::rtl::OUStringToOString(xNode->getLocalName(), 1125 RTL_TEXTENCODING_UTF8).getStr()); 1126 i_xDoc->removeChild(xNode); 1127 xNode = i_xDoc->getFirstChild(); // start over 1128 } 1129 } else { 1130 xNode = xNode->getNextSibling(); 1131 } 1132 } 1133 if (!xRElem.is()) { 1134 xRElem = i_xDoc->createElementNS( 1135 ::rtl::OUString::createFromAscii(s_nsODF), 1136 ::rtl::OUString::createFromAscii("office:document-meta")); 1137 css::uno::Reference<css::xml::dom::XNode> xRNode(xRElem, 1138 css::uno::UNO_QUERY_THROW); 1139 i_xDoc->appendChild(xRNode); 1140 } 1141 xRElem->setAttributeNS(::rtl::OUString::createFromAscii(s_nsODF), 1142 ::rtl::OUString::createFromAscii("office:version"), 1143 ::rtl::OUString::createFromAscii("1.0")); 1144 // does not exist, otherwise m_xParent would not be null 1145 css::uno::Reference<css::xml::dom::XNode> xParent ( 1146 i_xDoc->createElementNS( 1147 ::rtl::OUString::createFromAscii(s_nsODF), 1148 ::rtl::OUString::createFromAscii("office:meta")), 1149 css::uno::UNO_QUERY_THROW); 1150 xRElem->appendChild(xParent); 1151 m_xParent = xParent; 1152 } catch (css::xml::dom::DOMException & e) { 1153 css::uno::Any a(e); 1154 throw css::lang::WrappedTargetRuntimeException( 1155 ::rtl::OUString::createFromAscii( 1156 "SfxDocumentMetaData::init: DOM exception"), 1157 css::uno::Reference<css::uno::XInterface>(*this), a); 1158 } 1159 } 1160 1161 1162 // select nodes for elements of which we only handle one occurrence 1163 for (const char **pName = s_stdMeta; *pName != 0; ++pName) { 1164 ::rtl::OUString name = ::rtl::OUString::createFromAscii(*pName); 1165 // NB: If a document contains more than one occurrence of a 1166 // meta-data element, we arbitrarily pick one of them here. 1167 // We do not remove the others, i.e., when we write the 1168 // document, it will contain the duplicates unchanged. 1169 // The ODF spec says that handling multiple occurrences is 1170 // application-specific. 1171 css::uno::Reference<css::xml::dom::XNode> xNode = 1172 xPath->selectSingleNode(m_xParent, 1173 ::rtl::OUString::createFromAscii("child::") + name); 1174 // Do not create an empty element if it is missing; 1175 // for certain elements, such as dateTime, this would be invalid 1176 m_meta[name] = xNode; 1177 } 1178 1179 // select nodes for elements of which we handle all occurrences 1180 for (const char **pName = s_stdMetaList; *pName != 0; ++pName) { 1181 ::rtl::OUString name = ::rtl::OUString::createFromAscii(*pName); 1182 css::uno::Reference<css::xml::dom::XNodeList> nodes = 1183 xPath->selectNodeList(m_xParent, 1184 ::rtl::OUString::createFromAscii("child::") + name); 1185 std::vector<css::uno::Reference<css::xml::dom::XNode> > v; 1186 for (sal_Int32 i = 0; i < nodes->getLength(); ++i) { 1187 v.push_back(nodes->item(i)); 1188 } 1189 m_metaList[name] = v; 1190 } 1191 1192 // initialize members corresponding to attributes from DOM nodes 1193 m_TemplateName = getMetaAttr("meta:template", "xlink:title"); 1194 m_TemplateURL = getMetaAttr("meta:template", "xlink:href"); 1195 m_TemplateDate = 1196 textToDateTimeDefault(getMetaAttr("meta:template", "meta:date")); 1197 m_AutoloadURL = getMetaAttr("meta:auto-reload", "xlink:href"); 1198 m_AutoloadSecs = 1199 textToDuration(getMetaAttr("meta:auto-reload", "meta:delay")); 1200 m_DefaultTarget = 1201 getMetaAttr("meta:hyperlink-behaviour", "office:target-frame-name"); 1202 1203 1204 std::vector<css::uno::Reference<css::xml::dom::XNode> > & vec = 1205 m_metaList[::rtl::OUString::createFromAscii("meta:user-defined")]; 1206 m_xUserDefined.clear(); // #i105826#: reset (may be re-initialization) 1207 if ( !vec.empty() ) 1208 { 1209 createUserDefined(); 1210 } 1211 1212 // user-defined meta data: initialize PropertySet from DOM nodes 1213 for (std::vector<css::uno::Reference<css::xml::dom::XNode> >::iterator 1214 it = vec.begin(); it != vec.end(); ++it) { 1215 css::uno::Reference<css::xml::dom::XElement> xElem(*it, 1216 css::uno::UNO_QUERY_THROW); 1217 css::uno::Any any; 1218 ::rtl::OUString name = xElem->getAttributeNS( 1219 ::rtl::OUString::createFromAscii(s_nsODFMeta), 1220 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("name"))); 1221 ::rtl::OUString type = xElem->getAttributeNS( 1222 ::rtl::OUString::createFromAscii(s_nsODFMeta), 1223 ::rtl::OUString::createFromAscii("value-type")); 1224 ::rtl::OUString text = getNodeText(*it); 1225 if (type.equalsAscii("float")) { 1226 double d; 1227 if (::sax::Converter::convertDouble(d, text)) { 1228 any <<= d; 1229 } else { 1230 DBG_WARNING1("SfxDocumentMetaData: invalid float: %s", 1231 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); 1232 continue; 1233 } 1234 } else if (type.equalsAscii("date")) { 1235 bool isDateTime; 1236 css::util::Date d; 1237 css::util::DateTime dt; 1238 if (textToDateOrDateTime(d, dt, isDateTime, text)) { 1239 if (isDateTime) { 1240 any <<= dt; 1241 } else { 1242 any <<= d; 1243 } 1244 } else { 1245 DBG_WARNING1("SfxDocumentMetaData: invalid date: %s", 1246 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); 1247 continue; 1248 } 1249 } else if (type.equalsAscii("time")) { 1250 css::util::Duration ud; 1251 if (textToDuration(ud, text)) { 1252 any <<= ud; 1253 } else { 1254 DBG_WARNING1("SfxDocumentMetaData: invalid time: %s", 1255 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); 1256 continue; 1257 } 1258 } else if (type.equalsAscii("boolean")) { 1259 bool b; 1260 if (::sax::Converter::convertBool(b, text)) { 1261 any <<= b; 1262 } else { 1263 DBG_WARNING1("SfxDocumentMetaData: invalid boolean: %s", 1264 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); 1265 continue; 1266 } 1267 } else if (type.equalsAscii("string") || true) { // default 1268 any <<= text; 1269 } 1270 try { 1271 m_xUserDefined->addProperty(name, 1272 css::beans::PropertyAttribute::REMOVEABLE, any); 1273 } catch (css::beans::PropertyExistException &) { 1274 DBG_WARNING1("SfxDocumentMetaData: duplicate: %s", 1275 OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr()); 1276 // ignore; duplicate 1277 } catch (css::beans::IllegalTypeException &) { 1278 DBG_ERROR1("SfxDocumentMetaData: illegal type: %s", 1279 OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr()); 1280 } catch (css::lang::IllegalArgumentException &) { 1281 DBG_ERROR1("SfxDocumentMetaData: illegal arg: %s", 1282 OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr()); 1283 } 1284 } 1285 1286 m_isModified = false; 1287 m_isInitialized = true; 1288 } 1289 1290 1291 //////////////////////////////////////////////////////////////////////////// 1292 1293 SfxDocumentMetaData::SfxDocumentMetaData( 1294 css::uno::Reference< css::uno::XComponentContext > const & context) 1295 : BaseMutex() 1296 , SfxDocumentMetaData_Base(m_aMutex) 1297 , m_xContext(context) 1298 , m_NotifyListeners(m_aMutex) 1299 , m_isInitialized(false) 1300 , m_isModified(false) 1301 , m_AutoloadSecs(0) 1302 { 1303 DBG_ASSERT(context.is(), "SfxDocumentMetaData: context is null"); 1304 DBG_ASSERT(context->getServiceManager().is(), 1305 "SfxDocumentMetaData: context has no service manager"); 1306 init(createDOM()); 1307 } 1308 1309 // com.sun.star.uno.XServiceInfo: 1310 ::rtl::OUString SAL_CALL 1311 SfxDocumentMetaData::getImplementationName() 1312 { 1313 return comp_SfxDocumentMetaData::_getImplementationName(); 1314 } 1315 1316 ::sal_Bool SAL_CALL 1317 SfxDocumentMetaData::supportsService(::rtl::OUString const & serviceName) 1318 { 1319 css::uno::Sequence< ::rtl::OUString > serviceNames = 1320 comp_SfxDocumentMetaData::_getSupportedServiceNames(); 1321 for (::sal_Int32 i = 0; i < serviceNames.getLength(); ++i) { 1322 if (serviceNames[i] == serviceName) 1323 return sal_True; 1324 } 1325 return sal_False; 1326 } 1327 1328 css::uno::Sequence< ::rtl::OUString > SAL_CALL 1329 SfxDocumentMetaData::getSupportedServiceNames() 1330 { 1331 return comp_SfxDocumentMetaData::_getSupportedServiceNames(); 1332 } 1333 1334 1335 // ::com::sun::star::lang::XComponent: 1336 void SAL_CALL SfxDocumentMetaData::dispose() 1337 { 1338 ::osl::MutexGuard g(m_aMutex); 1339 if (!m_isInitialized) { 1340 return; 1341 } 1342 WeakComponentImplHelperBase::dispose(); // superclass 1343 m_NotifyListeners.disposeAndClear(css::lang::EventObject( 1344 static_cast< ::cppu::OWeakObject* >(this))); 1345 m_isInitialized = false; 1346 m_meta.clear(); 1347 m_metaList.clear(); 1348 m_xParent.clear(); 1349 m_xDoc.clear(); 1350 m_xUserDefined.clear(); 1351 } 1352 1353 1354 // ::com::sun::star::document::XDocumentProperties: 1355 ::rtl::OUString SAL_CALL 1356 SfxDocumentMetaData::getAuthor() 1357 { 1358 ::osl::MutexGuard g(m_aMutex); 1359 return getMetaText("meta:initial-creator"); 1360 } 1361 1362 void SAL_CALL SfxDocumentMetaData::setAuthor(const ::rtl::OUString & the_value) 1363 { 1364 setMetaTextAndNotify("meta:initial-creator", the_value); 1365 } 1366 1367 1368 ::rtl::OUString SAL_CALL 1369 SfxDocumentMetaData::getGenerator() 1370 { 1371 ::osl::MutexGuard g(m_aMutex); 1372 return getMetaText("meta:generator"); 1373 } 1374 1375 void SAL_CALL 1376 SfxDocumentMetaData::setGenerator(const ::rtl::OUString & the_value) 1377 { 1378 setMetaTextAndNotify("meta:generator", the_value); 1379 } 1380 1381 css::util::DateTime SAL_CALL 1382 SfxDocumentMetaData::getCreationDate() 1383 { 1384 ::osl::MutexGuard g(m_aMutex); 1385 return textToDateTimeDefault(getMetaText("meta:creation-date")); 1386 } 1387 1388 void SAL_CALL 1389 SfxDocumentMetaData::setCreationDate(const css::util::DateTime & the_value) 1390 { 1391 setMetaTextAndNotify("meta:creation-date", dateTimeToText(the_value)); 1392 } 1393 1394 ::rtl::OUString SAL_CALL 1395 SfxDocumentMetaData::getTitle() 1396 { 1397 ::osl::MutexGuard g(m_aMutex); 1398 return getMetaText("dc:title"); 1399 } 1400 1401 void SAL_CALL SfxDocumentMetaData::setTitle(const ::rtl::OUString & the_value) 1402 { 1403 setMetaTextAndNotify("dc:title", the_value); 1404 } 1405 1406 ::rtl::OUString SAL_CALL 1407 SfxDocumentMetaData::getSubject() 1408 { 1409 ::osl::MutexGuard g(m_aMutex); 1410 return getMetaText("dc:subject"); 1411 } 1412 1413 void SAL_CALL 1414 SfxDocumentMetaData::setSubject(const ::rtl::OUString & the_value) 1415 { 1416 setMetaTextAndNotify("dc:subject", the_value); 1417 } 1418 1419 ::rtl::OUString SAL_CALL 1420 SfxDocumentMetaData::getDescription() 1421 { 1422 ::osl::MutexGuard g(m_aMutex); 1423 return getMetaText("dc:description"); 1424 } 1425 1426 void SAL_CALL 1427 SfxDocumentMetaData::setDescription(const ::rtl::OUString & the_value) 1428 { 1429 setMetaTextAndNotify("dc:description", the_value); 1430 } 1431 1432 css::uno::Sequence< ::rtl::OUString > 1433 SAL_CALL SfxDocumentMetaData::getKeywords() 1434 { 1435 ::osl::MutexGuard g(m_aMutex); 1436 return getMetaList("meta:keyword"); 1437 } 1438 1439 void SAL_CALL 1440 SfxDocumentMetaData::setKeywords( 1441 const css::uno::Sequence< ::rtl::OUString > & the_value) 1442 { 1443 ::osl::ClearableMutexGuard g(m_aMutex); 1444 if (setMetaList("meta:keyword", the_value)) { 1445 g.clear(); 1446 setModified(true); 1447 } 1448 } 1449 1450 css::lang::Locale SAL_CALL 1451 SfxDocumentMetaData::getLanguage() 1452 { 1453 ::osl::MutexGuard g(m_aMutex); 1454 css::lang::Locale loc; 1455 ::rtl::OUString text = getMetaText("dc:language"); 1456 sal_Int32 ix = text.indexOf(static_cast<sal_Unicode> ('-')); 1457 if (ix == -1) { 1458 loc.Language = text; 1459 } else { 1460 loc.Language = text.copy(0, ix); 1461 loc.Country = text.copy(ix+1); 1462 } 1463 return loc; 1464 } 1465 1466 void SAL_CALL 1467 SfxDocumentMetaData::setLanguage(const css::lang::Locale & the_value) 1468 { 1469 ::rtl::OUString text = the_value.Language; 1470 if (the_value.Country.getLength() > 0) { 1471 text += ::rtl::OUString::createFromAscii("-").concat(the_value.Country); 1472 } 1473 setMetaTextAndNotify("dc:language", text); 1474 } 1475 1476 ::rtl::OUString SAL_CALL 1477 SfxDocumentMetaData::getModifiedBy() 1478 { 1479 ::osl::MutexGuard g(m_aMutex); 1480 return getMetaText("dc:creator"); 1481 } 1482 1483 void SAL_CALL 1484 SfxDocumentMetaData::setModifiedBy(const ::rtl::OUString & the_value) 1485 { 1486 setMetaTextAndNotify("dc:creator", the_value); 1487 } 1488 1489 css::util::DateTime SAL_CALL 1490 SfxDocumentMetaData::getModificationDate() 1491 { 1492 ::osl::MutexGuard g(m_aMutex); 1493 return textToDateTimeDefault(getMetaText("dc:date")); 1494 } 1495 1496 void SAL_CALL 1497 SfxDocumentMetaData::setModificationDate(const css::util::DateTime & the_value) 1498 { 1499 setMetaTextAndNotify("dc:date", dateTimeToText(the_value)); 1500 } 1501 1502 ::rtl::OUString SAL_CALL 1503 SfxDocumentMetaData::getPrintedBy() 1504 { 1505 ::osl::MutexGuard g(m_aMutex); 1506 return getMetaText("meta:printed-by"); 1507 } 1508 1509 void SAL_CALL 1510 SfxDocumentMetaData::setPrintedBy(const ::rtl::OUString & the_value) 1511 { 1512 setMetaTextAndNotify("meta:printed-by", the_value); 1513 } 1514 1515 css::util::DateTime SAL_CALL 1516 SfxDocumentMetaData::getPrintDate() 1517 { 1518 ::osl::MutexGuard g(m_aMutex); 1519 return textToDateTimeDefault(getMetaText("meta:print-date")); 1520 } 1521 1522 void SAL_CALL 1523 SfxDocumentMetaData::setPrintDate(const css::util::DateTime & the_value) 1524 { 1525 setMetaTextAndNotify("meta:print-date", dateTimeToText(the_value)); 1526 } 1527 1528 ::rtl::OUString SAL_CALL 1529 SfxDocumentMetaData::getTemplateName() 1530 { 1531 ::osl::MutexGuard g(m_aMutex); 1532 checkInit(); 1533 return m_TemplateName; 1534 } 1535 1536 void SAL_CALL 1537 SfxDocumentMetaData::setTemplateName(const ::rtl::OUString & the_value) 1538 { 1539 ::osl::ClearableMutexGuard g(m_aMutex); 1540 checkInit(); 1541 if (m_TemplateName != the_value) { 1542 m_TemplateName = the_value; 1543 g.clear(); 1544 setModified(true); 1545 } 1546 } 1547 1548 ::rtl::OUString SAL_CALL 1549 SfxDocumentMetaData::getTemplateURL() 1550 { 1551 ::osl::MutexGuard g(m_aMutex); 1552 checkInit(); 1553 return m_TemplateURL; 1554 } 1555 1556 void SAL_CALL 1557 SfxDocumentMetaData::setTemplateURL(const ::rtl::OUString & the_value) 1558 { 1559 ::osl::ClearableMutexGuard g(m_aMutex); 1560 checkInit(); 1561 if (m_TemplateURL != the_value) { 1562 m_TemplateURL = the_value; 1563 g.clear(); 1564 setModified(true); 1565 } 1566 } 1567 1568 css::util::DateTime SAL_CALL 1569 SfxDocumentMetaData::getTemplateDate() 1570 { 1571 ::osl::MutexGuard g(m_aMutex); 1572 checkInit(); 1573 return m_TemplateDate; 1574 } 1575 1576 void SAL_CALL 1577 SfxDocumentMetaData::setTemplateDate(const css::util::DateTime & the_value) 1578 { 1579 ::osl::ClearableMutexGuard g(m_aMutex); 1580 checkInit(); 1581 if (!(m_TemplateDate == the_value)) { 1582 m_TemplateDate = the_value; 1583 g.clear(); 1584 setModified(true); 1585 } 1586 } 1587 1588 ::rtl::OUString SAL_CALL 1589 SfxDocumentMetaData::getAutoloadURL() 1590 { 1591 ::osl::MutexGuard g(m_aMutex); 1592 checkInit(); 1593 return m_AutoloadURL; 1594 } 1595 1596 void SAL_CALL 1597 SfxDocumentMetaData::setAutoloadURL(const ::rtl::OUString & the_value) 1598 { 1599 ::osl::ClearableMutexGuard g(m_aMutex); 1600 checkInit(); 1601 if (m_AutoloadURL != the_value) { 1602 m_AutoloadURL = the_value; 1603 g.clear(); 1604 setModified(true); 1605 } 1606 } 1607 1608 ::sal_Int32 SAL_CALL 1609 SfxDocumentMetaData::getAutoloadSecs() 1610 { 1611 ::osl::MutexGuard g(m_aMutex); 1612 checkInit(); 1613 return m_AutoloadSecs; 1614 } 1615 1616 void SAL_CALL 1617 SfxDocumentMetaData::setAutoloadSecs(::sal_Int32 the_value) 1618 { 1619 if (the_value < 0) throw css::lang::IllegalArgumentException( 1620 ::rtl::OUString::createFromAscii( 1621 "SfxDocumentMetaData::setAutoloadSecs: argument is negative"), 1622 *this, 0); 1623 ::osl::ClearableMutexGuard g(m_aMutex); 1624 checkInit(); 1625 if (m_AutoloadSecs != the_value) { 1626 m_AutoloadSecs = the_value; 1627 g.clear(); 1628 setModified(true); 1629 } 1630 } 1631 1632 ::rtl::OUString SAL_CALL 1633 SfxDocumentMetaData::getDefaultTarget() 1634 { 1635 ::osl::MutexGuard g(m_aMutex); 1636 checkInit(); 1637 return m_DefaultTarget; 1638 } 1639 1640 void SAL_CALL 1641 SfxDocumentMetaData::setDefaultTarget(const ::rtl::OUString & the_value) 1642 { 1643 ::osl::ClearableMutexGuard g(m_aMutex); 1644 checkInit(); 1645 if (m_DefaultTarget != the_value) { 1646 m_DefaultTarget = the_value; 1647 g.clear(); 1648 setModified(true); 1649 } 1650 } 1651 1652 css::uno::Sequence< css::beans::NamedValue > SAL_CALL 1653 SfxDocumentMetaData::getDocumentStatistics() 1654 { 1655 ::osl::MutexGuard g(m_aMutex); 1656 checkInit(); 1657 ::comphelper::SequenceAsVector<css::beans::NamedValue> stats; 1658 for (size_t i = 0; s_stdStats[i] != 0; ++i) { 1659 const char * aName = s_stdStatAttrs[i]; 1660 ::rtl::OUString text = getMetaAttr("meta:document-statistic", aName); 1661 if (text.equalsAscii("")) continue; 1662 css::beans::NamedValue stat; 1663 stat.Name = ::rtl::OUString::createFromAscii(s_stdStats[i]); 1664 sal_Int32 val; 1665 css::uno::Any any; 1666 if (!::sax::Converter::convertNumber(val, text, 0, 1667 std::numeric_limits<sal_Int32>::max()) || (val < 0)) { 1668 val = 0; 1669 DBG_WARNING1("SfxDocumentMetaData: invalid number: %s", 1670 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr()); 1671 } 1672 any <<= val; 1673 stat.Value = any; 1674 stats.push_back(stat); 1675 } 1676 1677 return stats.getAsConstList(); 1678 } 1679 1680 void SAL_CALL 1681 SfxDocumentMetaData::setDocumentStatistics( 1682 const css::uno::Sequence< css::beans::NamedValue > & the_value) 1683 { 1684 ::osl::ClearableMutexGuard g(m_aMutex); 1685 checkInit(); 1686 std::vector<std::pair<const char *, ::rtl::OUString> > attributes; 1687 for (sal_Int32 i = 0; i < the_value.getLength(); ++i) { 1688 const ::rtl::OUString name = the_value[i].Name; 1689 // inefficently search for matching attribute 1690 for (size_t j = 0; s_stdStats[j] != 0; ++j) { 1691 if (name.equalsAscii(s_stdStats[j])) { 1692 const css::uno::Any any = the_value[i].Value; 1693 sal_Int32 val = 0; 1694 if (any >>= val) { 1695 ::rtl::OUStringBuffer buf; 1696 ::sax::Converter::convertNumber(buf, val); 1697 attributes.push_back(std::make_pair(s_stdStatAttrs[j], 1698 buf.makeStringAndClear())); 1699 } else { 1700 DBG_WARNING1("SfxDocumentMetaData: invalid statistic: %s", 1701 OUStringToOString(name, RTL_TEXTENCODING_UTF8) 1702 .getStr()); 1703 } 1704 break; 1705 } 1706 } 1707 } 1708 updateElement("meta:document-statistic", &attributes); 1709 g.clear(); 1710 setModified(true); 1711 } 1712 1713 ::sal_Int16 SAL_CALL 1714 SfxDocumentMetaData::getEditingCycles() 1715 { 1716 ::osl::MutexGuard g(m_aMutex); 1717 ::rtl::OUString text = getMetaText("meta:editing-cycles"); 1718 sal_Int32 ret; 1719 if (::sax::Converter::convertNumber(ret, text, 1720 0, std::numeric_limits<sal_Int16>::max())) { 1721 return static_cast<sal_Int16>(ret); 1722 } else { 1723 return 0; 1724 } 1725 } 1726 1727 void SAL_CALL 1728 SfxDocumentMetaData::setEditingCycles(::sal_Int16 the_value) 1729 { 1730 if (the_value < 0) throw css::lang::IllegalArgumentException( 1731 ::rtl::OUString::createFromAscii( 1732 "SfxDocumentMetaData::setEditingCycles: argument is negative"), 1733 *this, 0); 1734 ::rtl::OUStringBuffer buf; 1735 ::sax::Converter::convertNumber(buf, the_value); 1736 setMetaTextAndNotify("meta:editing-cycles", buf.makeStringAndClear()); 1737 } 1738 1739 ::sal_Int32 SAL_CALL 1740 SfxDocumentMetaData::getEditingDuration() 1741 { 1742 ::osl::MutexGuard g(m_aMutex); 1743 return textToDuration(getMetaText("meta:editing-duration")); 1744 } 1745 1746 void SAL_CALL 1747 SfxDocumentMetaData::setEditingDuration(::sal_Int32 the_value) 1748 { 1749 if (the_value < 0) throw css::lang::IllegalArgumentException( 1750 ::rtl::OUString::createFromAscii( 1751 "SfxDocumentMetaData::setEditingDuration: argument is negative"), 1752 *this, 0); 1753 setMetaTextAndNotify("meta:editing-duration", durationToText(the_value)); 1754 } 1755 1756 void SAL_CALL 1757 SfxDocumentMetaData::resetUserData(const ::rtl::OUString & the_value) 1758 { 1759 ::osl::ClearableMutexGuard g(m_aMutex); 1760 1761 bool bModified( false ); 1762 bModified |= setMetaText("meta:initial-creator", the_value); 1763 ::DateTime now = DateTime(); 1764 css::util::DateTime uDT(now.Get100Sec(), now.GetSec(), now.GetMin(), 1765 now.GetHour(), now.GetDay(), now.GetMonth(), now.GetYear()); 1766 bModified |= setMetaText("meta:creation-date", dateTimeToText(uDT)); 1767 bModified |= setMetaText("dc:creator", ::rtl::OUString()); 1768 bModified |= setMetaText("meta:printed-by", ::rtl::OUString()); 1769 bModified |= setMetaText("dc:date", dateTimeToText(css::util::DateTime())); 1770 bModified |= setMetaText("meta:print-date", 1771 dateTimeToText(css::util::DateTime())); 1772 bModified |= setMetaText("meta:editing-duration", durationToText(0)); 1773 bModified |= setMetaText("meta:editing-cycles", 1774 ::rtl::OUString::createFromAscii("1")); 1775 1776 if (bModified) { 1777 g.clear(); 1778 setModified(true); 1779 } 1780 } 1781 1782 1783 css::uno::Reference< css::beans::XPropertyContainer > SAL_CALL 1784 SfxDocumentMetaData::getUserDefinedProperties() 1785 { 1786 ::osl::MutexGuard g(m_aMutex); 1787 checkInit(); 1788 createUserDefined(); 1789 return m_xUserDefined; 1790 } 1791 1792 1793 void SAL_CALL 1794 SfxDocumentMetaData::loadFromStorage( 1795 const css::uno::Reference< css::embed::XStorage > & xStorage, 1796 const css::uno::Sequence< css::beans::PropertyValue > & Medium) 1797 { 1798 if (!xStorage.is()) throw css::lang::IllegalArgumentException( 1799 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:" 1800 " argument is null"), *this, 0); 1801 ::osl::MutexGuard g(m_aMutex); 1802 1803 // open meta data file 1804 css::uno::Reference<css::io::XStream> xStream( 1805 xStorage->openStreamElement( 1806 ::rtl::OUString::createFromAscii(s_metaXml), 1807 css::embed::ElementModes::READ) ); 1808 if (!xStream.is()) throw css::uno::RuntimeException(); 1809 css::uno::Reference<css::io::XInputStream> xInStream = 1810 xStream->getInputStream(); 1811 if (!xInStream.is()) throw css::uno::RuntimeException(); 1812 1813 // create DOM parser service 1814 css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( 1815 m_xContext->getServiceManager()); 1816 css::uno::Reference<css::xml::sax::XParser> xParser ( 1817 xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( 1818 "com.sun.star.xml.sax.Parser"), m_xContext), 1819 css::uno::UNO_QUERY_THROW); 1820 if (!xParser.is()) throw css::uno::RuntimeException( 1821 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:" 1822 " cannot create Parser service"), *this); 1823 css::xml::sax::InputSource input; 1824 input.aInputStream = xInStream; 1825 1826 sal_uInt64 version = SotStorage::GetVersion( xStorage ); 1827 // Oasis is also the default (0) 1828 sal_Bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 ); 1829 const sal_Char *pServiceName = bOasis 1830 ? "com.sun.star.document.XMLOasisMetaImporter" 1831 : "com.sun.star.document.XMLMetaImporter"; 1832 1833 // set base URL 1834 css::uno::Reference<css::beans::XPropertySet> xPropArg = 1835 getURLProperties(Medium); 1836 try { 1837 xPropArg->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI"))) 1838 >>= input.sSystemId; 1839 input.sSystemId += ::rtl::OUString::createFromAscii("/").concat( 1840 ::rtl::OUString::createFromAscii(s_metaXml)); 1841 } catch (css::uno::Exception &) { 1842 input.sSystemId = ::rtl::OUString::createFromAscii(s_metaXml); 1843 } 1844 css::uno::Sequence< css::uno::Any > args(1); 1845 args[0] <<= xPropArg; 1846 1847 css::uno::Reference<css::xml::sax::XDocumentHandler> xDocHandler ( 1848 xMsf->createInstanceWithArgumentsAndContext( 1849 ::rtl::OUString::createFromAscii(pServiceName), args, m_xContext), 1850 css::uno::UNO_QUERY_THROW); 1851 if (!xDocHandler.is()) throw css::uno::RuntimeException( 1852 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:" 1853 " cannot create XMLOasisMetaImporter service"), *this); 1854 css::uno::Reference<css::document::XImporter> xImp (xDocHandler, 1855 css::uno::UNO_QUERY_THROW); 1856 xImp->setTargetDocument(css::uno::Reference<css::lang::XComponent>(this)); 1857 xParser->setDocumentHandler(xDocHandler); 1858 try { 1859 xParser->parseStream(input); 1860 } catch (css::xml::sax::SAXException &) { 1861 throw css::io::WrongFormatException(::rtl::OUString::createFromAscii( 1862 "SfxDocumentMetaData::loadFromStorage:" 1863 " XML parsing exception"), *this); 1864 } 1865 // NB: the implementation of XMLOasisMetaImporter calls initialize 1866 // init(xDocBuilder->getDocument()); 1867 checkInit(); 1868 } 1869 1870 void SAL_CALL 1871 SfxDocumentMetaData::storeToStorage( 1872 const css::uno::Reference< css::embed::XStorage > & xStorage, 1873 const css::uno::Sequence< css::beans::PropertyValue > & Medium) 1874 { 1875 if (!xStorage.is()) throw css::lang::IllegalArgumentException( 1876 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::storeToStorage:" 1877 " argument is null"), *this, 0); 1878 ::osl::MutexGuard g(m_aMutex); 1879 checkInit(); 1880 1881 // update user-defined meta data in DOM tree 1882 // updateUserDefinedAndAttributes(); // this will be done in serialize! 1883 1884 // write into storage 1885 css::uno::Reference<css::io::XStream> xStream = 1886 xStorage->openStreamElement(::rtl::OUString::createFromAscii(s_metaXml), 1887 css::embed::ElementModes::WRITE 1888 | css::embed::ElementModes::TRUNCATE); 1889 if (!xStream.is()) throw css::uno::RuntimeException(); 1890 css::uno::Reference< css::beans::XPropertySet > xStreamProps(xStream, 1891 css::uno::UNO_QUERY_THROW); 1892 xStreamProps->setPropertyValue( 1893 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MediaType")), 1894 css::uno::makeAny(::rtl::OUString::createFromAscii("text/xml"))); 1895 xStreamProps->setPropertyValue( 1896 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Compressed")), 1897 css::uno::makeAny(static_cast<sal_Bool> (sal_False))); 1898 xStreamProps->setPropertyValue( 1899 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("UseCommonStoragePasswordEncryption")), 1900 css::uno::makeAny(static_cast<sal_Bool> (sal_False))); 1901 css::uno::Reference<css::io::XOutputStream> xOutStream = 1902 xStream->getOutputStream(); 1903 if (!xOutStream.is()) throw css::uno::RuntimeException(); 1904 css::uno::Reference<css::lang::XMultiComponentFactory> xMsf ( 1905 m_xContext->getServiceManager()); 1906 css::uno::Reference<css::io::XActiveDataSource> xSaxWriter( 1907 xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii( 1908 "com.sun.star.xml.sax.Writer"), m_xContext), 1909 css::uno::UNO_QUERY_THROW); 1910 xSaxWriter->setOutputStream(xOutStream); 1911 css::uno::Reference<css::xml::sax::XDocumentHandler> xDocHandler ( 1912 xSaxWriter, css::uno::UNO_QUERY_THROW); 1913 1914 const sal_uInt64 version = SotStorage::GetVersion( xStorage ); 1915 // Oasis is also the default (0) 1916 const sal_Bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 ); 1917 const sal_Char *pServiceName = bOasis 1918 ? "com.sun.star.document.XMLOasisMetaExporter" 1919 : "com.sun.star.document.XMLMetaExporter"; 1920 1921 // set base URL 1922 css::uno::Reference<css::beans::XPropertySet> xPropArg = 1923 getURLProperties(Medium); 1924 css::uno::Sequence< css::uno::Any > args(2); 1925 args[0] <<= xDocHandler; 1926 args[1] <<= xPropArg; 1927 1928 css::uno::Reference<css::document::XExporter> xExp( 1929 xMsf->createInstanceWithArgumentsAndContext( 1930 ::rtl::OUString::createFromAscii(pServiceName), args, m_xContext), 1931 css::uno::UNO_QUERY_THROW); 1932 xExp->setSourceDocument(css::uno::Reference<css::lang::XComponent>(this)); 1933 css::uno::Reference<css::document::XFilter> xFilter(xExp, 1934 css::uno::UNO_QUERY_THROW); 1935 if (xFilter->filter(css::uno::Sequence< css::beans::PropertyValue >())) { 1936 css::uno::Reference<css::embed::XTransactedObject> xTransaction( 1937 xStorage, css::uno::UNO_QUERY); 1938 if (xTransaction.is()) { 1939 xTransaction->commit(); 1940 } 1941 } else { 1942 throw css::io::IOException(::rtl::OUString::createFromAscii( 1943 "SfxDocumentMetaData::storeToStorage: cannot filter"), *this); 1944 } 1945 } 1946 1947 void SAL_CALL 1948 SfxDocumentMetaData::loadFromMedium(const ::rtl::OUString & URL, 1949 const css::uno::Sequence< css::beans::PropertyValue > & Medium) 1950 { 1951 css::uno::Reference<css::io::XInputStream> xIn; 1952 ::comphelper::MediaDescriptor md(Medium); 1953 // if we have an URL parameter, it replaces the one in the media descriptor 1954 if (!URL.equalsAscii("")) { 1955 md[ ::comphelper::MediaDescriptor::PROP_URL() ] <<= URL; 1956 } 1957 if (sal_True == md.addInputStream()) { 1958 md[ ::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn; 1959 } 1960 css::uno::Reference<css::embed::XStorage> xStorage; 1961 css::uno::Reference<css::lang::XMultiServiceFactory> xMsf ( 1962 m_xContext->getServiceManager(), css::uno::UNO_QUERY_THROW); 1963 try { 1964 if (xIn.is()) { 1965 xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream( 1966 xIn, xMsf); 1967 } else { // fallback to url parameter 1968 xStorage = ::comphelper::OStorageHelper::GetStorageFromURL( 1969 URL, css::embed::ElementModes::READ, xMsf); 1970 } 1971 } catch (css::uno::RuntimeException &) { 1972 throw; 1973 } catch (css::io::IOException &) { 1974 throw; 1975 } catch (css::uno::Exception & e) { 1976 throw css::lang::WrappedTargetException( 1977 ::rtl::OUString::createFromAscii( 1978 "SfxDocumentMetaData::loadFromMedium: exception"), 1979 css::uno::Reference<css::uno::XInterface>(*this), 1980 css::uno::makeAny(e)); 1981 } 1982 if (!xStorage.is()) { 1983 throw css::uno::RuntimeException(::rtl::OUString::createFromAscii( 1984 "SfxDocumentMetaData::loadFromMedium: cannot get Storage"), 1985 *this); 1986 } 1987 loadFromStorage(xStorage, md.getAsConstPropertyValueList()); 1988 } 1989 1990 void SAL_CALL 1991 SfxDocumentMetaData::storeToMedium(const ::rtl::OUString & URL, 1992 const css::uno::Sequence< css::beans::PropertyValue > & Medium) 1993 { 1994 ::comphelper::MediaDescriptor md(Medium); 1995 if (!URL.equalsAscii("")) { 1996 md[ ::comphelper::MediaDescriptor::PROP_URL() ] <<= URL; 1997 } 1998 SfxMedium aMedium(md.getAsConstPropertyValueList()); 1999 css::uno::Reference<css::embed::XStorage> xStorage 2000 = aMedium.GetOutputStorage(); 2001 2002 2003 if (!xStorage.is()) { 2004 throw css::uno::RuntimeException(::rtl::OUString::createFromAscii( 2005 "SfxDocumentMetaData::storeToMedium: cannot get Storage"), 2006 *this); 2007 } 2008 // set MIME type of the storage 2009 ::comphelper::MediaDescriptor::const_iterator iter 2010 = md.find(::comphelper::MediaDescriptor::PROP_MEDIATYPE()); 2011 if (iter != md.end()) { 2012 css::uno::Reference< css::beans::XPropertySet > xProps(xStorage, 2013 css::uno::UNO_QUERY_THROW); 2014 xProps->setPropertyValue( 2015 ::comphelper::MediaDescriptor::PROP_MEDIATYPE(), 2016 iter->second); 2017 } 2018 storeToStorage(xStorage, md.getAsConstPropertyValueList()); 2019 2020 2021 const sal_Bool bOk = aMedium.Commit(); 2022 aMedium.Close(); 2023 if ( !bOk ) { 2024 sal_uInt32 nError = aMedium.GetError(); 2025 if ( nError == ERRCODE_NONE ) { 2026 nError = ERRCODE_IO_GENERAL; 2027 } 2028 2029 throw css::task::ErrorCodeIOException( ::rtl::OUString(), 2030 css::uno::Reference< css::uno::XInterface >(), nError); 2031 2032 } 2033 } 2034 2035 // ::com::sun::star::lang::XInitialization: 2036 void SAL_CALL 2037 SfxDocumentMetaData::initialize( 2038 const css::uno::Sequence< ::com::sun::star::uno::Any > & aArguments) 2039 { 2040 // possible arguments: 2041 // - no argument: default initialization (empty DOM) 2042 // - 1 argument, XDocument: initialize with given DOM and empty base URL 2043 // NB: links in document must be absolute 2044 2045 ::osl::MutexGuard g(m_aMutex); 2046 css::uno::Reference<css::xml::dom::XDocument> xDoc; 2047 2048 for (sal_Int32 i = 0; i < aArguments.getLength(); ++i) { 2049 const css::uno::Any any = aArguments[i]; 2050 if (any >>= xDoc) { 2051 if (!xDoc.is()) { 2052 throw css::lang::IllegalArgumentException( 2053 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::" 2054 "initialize: argument is null"), 2055 *this, static_cast<sal_Int16>(i)); 2056 } 2057 } else { 2058 throw css::lang::IllegalArgumentException( 2059 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::" 2060 "initialize: argument must be XDocument"), 2061 *this, static_cast<sal_Int16>(i)); 2062 } 2063 } 2064 2065 if (!xDoc.is()) { 2066 // For a new document, we create a new DOM tree here. 2067 xDoc = createDOM(); 2068 } 2069 2070 init(xDoc); 2071 } 2072 2073 // ::com::sun::star::util::XCloneable: 2074 css::uno::Reference<css::util::XCloneable> SAL_CALL 2075 SfxDocumentMetaData::createClone() 2076 { 2077 ::osl::MutexGuard g(m_aMutex); 2078 checkInit(); 2079 2080 SfxDocumentMetaData *pNew = new SfxDocumentMetaData(m_xContext); 2081 2082 // NB: do not copy the modification listeners, only DOM 2083 css::uno::Reference<css::xml::dom::XDocument> xDoc = createDOM(); 2084 try { 2085 updateUserDefinedAndAttributes(); 2086 // deep copy of root node 2087 css::uno::Reference<css::xml::dom::XNode> xRoot( 2088 m_xDoc->getDocumentElement(), css::uno::UNO_QUERY_THROW); 2089 css::uno::Reference<css::xml::dom::XNode> xRootNew( 2090 xDoc->importNode(xRoot, true)); 2091 xDoc->appendChild(xRootNew); 2092 pNew->init(xDoc); 2093 } catch (css::uno::RuntimeException &) { 2094 throw; 2095 } catch (css::uno::Exception & e) { 2096 css::uno::Any a(e); 2097 throw css::lang::WrappedTargetRuntimeException( 2098 ::rtl::OUString::createFromAscii( 2099 "SfxDocumentMetaData::createClone: exception"), 2100 css::uno::Reference<css::uno::XInterface>(*this), a); 2101 } 2102 // return static_cast< ::cppu::OWeakObject * > (pNew); 2103 return css::uno::Reference<css::util::XCloneable> (pNew); 2104 } 2105 2106 // ::com::sun::star::util::XModifiable: 2107 ::sal_Bool SAL_CALL SfxDocumentMetaData::isModified( ) 2108 { 2109 ::osl::MutexGuard g(m_aMutex); 2110 checkInit(); 2111 css::uno::Reference<css::util::XModifiable> xMB(m_xUserDefined, 2112 css::uno::UNO_QUERY); 2113 return m_isModified || (xMB.is() ? xMB->isModified() : sal_False); 2114 } 2115 2116 void SAL_CALL SfxDocumentMetaData::setModified( ::sal_Bool bModified ) 2117 { 2118 css::uno::Reference<css::util::XModifiable> xMB; 2119 { // do not lock mutex while notifying (#i93514#) to prevent deadlock 2120 ::osl::MutexGuard g(m_aMutex); 2121 checkInit(); 2122 m_isModified = bModified; 2123 if ( !bModified && m_xUserDefined.is() ) 2124 { 2125 xMB.set(m_xUserDefined, css::uno::UNO_QUERY); 2126 DBG_ASSERT(xMB.is(), 2127 "SfxDocumentMetaData::setModified: PropertyBag not Modifiable?"); 2128 } 2129 } 2130 if (bModified) { 2131 try { 2132 css::uno::Reference<css::uno::XInterface> xThis(*this); 2133 css::lang::EventObject event(xThis); 2134 m_NotifyListeners.notifyEach(&css::util::XModifyListener::modified, 2135 event); 2136 } catch (css::uno::RuntimeException &) { 2137 throw; 2138 } catch (css::uno::Exception & e) { 2139 // ignore 2140 DBG_WARNING1("SfxDocumentMetaData::setModified: exception:\n%s", 2141 OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); 2142 (void) e; 2143 } 2144 } else { 2145 if (xMB.is()) { 2146 xMB->setModified(false); 2147 } 2148 } 2149 } 2150 2151 // ::com::sun::star::util::XModifyBroadcaster: 2152 void SAL_CALL SfxDocumentMetaData::addModifyListener( 2153 const css::uno::Reference< css::util::XModifyListener > & xListener) 2154 { 2155 ::osl::MutexGuard g(m_aMutex); 2156 checkInit(); 2157 m_NotifyListeners.addInterface(xListener); 2158 css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined, 2159 css::uno::UNO_QUERY); 2160 if (xMB.is()) { 2161 xMB->addModifyListener(xListener); 2162 } 2163 } 2164 2165 void SAL_CALL SfxDocumentMetaData::removeModifyListener( 2166 const css::uno::Reference< css::util::XModifyListener > & xListener) 2167 { 2168 ::osl::MutexGuard g(m_aMutex); 2169 checkInit(); 2170 m_NotifyListeners.removeInterface(xListener); 2171 css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined, 2172 css::uno::UNO_QUERY); 2173 if (xMB.is()) { 2174 xMB->removeModifyListener(xListener); 2175 } 2176 } 2177 2178 // ::com::sun::star::xml::sax::XSAXSerializable 2179 void SAL_CALL SfxDocumentMetaData::serialize( 2180 const css::uno::Reference<css::xml::sax::XDocumentHandler>& i_xHandler, 2181 const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces) 2182 { 2183 ::osl::MutexGuard g(m_aMutex); 2184 checkInit(); 2185 updateUserDefinedAndAttributes(); 2186 css::uno::Reference<css::xml::sax::XSAXSerializable> xSAXable(m_xDoc, 2187 css::uno::UNO_QUERY_THROW); 2188 xSAXable->serialize(i_xHandler, i_rNamespaces); 2189 } 2190 2191 void SfxDocumentMetaData::createUserDefined() 2192 { 2193 // user-defined meta data: create PropertyBag which only accepts property 2194 // values of allowed types 2195 if ( !m_xUserDefined.is() ) 2196 { 2197 css::uno::Sequence<css::uno::Type> types(11); 2198 types[0] = ::cppu::UnoType<bool>::get(); 2199 types[1] = ::cppu::UnoType< ::rtl::OUString>::get(); 2200 types[2] = ::cppu::UnoType<css::util::DateTime>::get(); 2201 types[3] = ::cppu::UnoType<css::util::Date>::get(); 2202 types[4] = ::cppu::UnoType<css::util::Duration>::get(); 2203 types[5] = ::cppu::UnoType<float>::get(); 2204 types[6] = ::cppu::UnoType<double>::get(); 2205 types[7] = ::cppu::UnoType<sal_Int16>::get(); 2206 types[8] = ::cppu::UnoType<sal_Int32>::get(); 2207 types[9] = ::cppu::UnoType<sal_Int64>::get(); 2208 // Time is supported for backward compatibility with OOo 3.x, x<=2 2209 types[10] = ::cppu::UnoType<css::util::Time>::get(); 2210 css::uno::Sequence<css::uno::Any> args(2); 2211 args[0] <<= css::beans::NamedValue( 2212 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AllowedTypes")), 2213 css::uno::makeAny(types)); 2214 // #i94175#: ODF allows empty user-defined property names! 2215 args[1] <<= css::beans::NamedValue( ::rtl::OUString( 2216 RTL_CONSTASCII_USTRINGPARAM("AllowEmptyPropertyName")), 2217 css::uno::makeAny(sal_True)); 2218 2219 const css::uno::Reference<css::lang::XMultiComponentFactory> xMsf( 2220 m_xContext->getServiceManager()); 2221 m_xUserDefined.set( 2222 xMsf->createInstanceWithContext( 2223 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 2224 "com.sun.star.beans.PropertyBag")), m_xContext), 2225 css::uno::UNO_QUERY_THROW); 2226 const css::uno::Reference<css::lang::XInitialization> xInit( 2227 m_xUserDefined, css::uno::UNO_QUERY); 2228 if (xInit.is()) { 2229 xInit->initialize(args); 2230 } 2231 2232 const css::uno::Reference<css::util::XModifyBroadcaster> xMB( 2233 m_xUserDefined, css::uno::UNO_QUERY); 2234 if (xMB.is()) 2235 { 2236 const css::uno::Sequence<css::uno::Reference<css::uno::XInterface> > 2237 listeners(m_NotifyListeners.getElements()); 2238 for (css::uno::Reference< css::uno::XInterface > const * iter = 2239 ::comphelper::stl_begin(listeners); 2240 iter != ::comphelper::stl_end(listeners); ++iter) { 2241 xMB->addModifyListener( 2242 css::uno::Reference< css::util::XModifyListener >(*iter, 2243 css::uno::UNO_QUERY)); 2244 } 2245 } 2246 } 2247 } 2248 2249 } // closing anonymous implementation namespace 2250 2251 2252 // component helper namespace 2253 namespace comp_SfxDocumentMetaData { 2254 2255 ::rtl::OUString SAL_CALL _getImplementationName() { 2256 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 2257 "SfxDocumentMetaData")); 2258 } 2259 2260 css::uno::Sequence< ::rtl::OUString > SAL_CALL _getSupportedServiceNames() 2261 { 2262 css::uno::Sequence< ::rtl::OUString > s(1); 2263 s[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( 2264 "com.sun.star.document.DocumentProperties")); 2265 return s; 2266 } 2267 2268 css::uno::Reference< css::uno::XInterface > SAL_CALL _create( 2269 const css::uno::Reference< css::uno::XComponentContext > & context) 2270 { 2271 return static_cast< ::cppu::OWeakObject * > 2272 (new SfxDocumentMetaData(context)); 2273 } 2274 2275 } // closing component helper namespace 2276 2277 static ::cppu::ImplementationEntry const entries[] = { 2278 { &comp_SfxDocumentMetaData::_create, 2279 &comp_SfxDocumentMetaData::_getImplementationName, 2280 &comp_SfxDocumentMetaData::_getSupportedServiceNames, 2281 &::cppu::createSingleComponentFactory, 0, 0 }, 2282 { 0, 0, 0, 0, 0, 0 } 2283 }; 2284 2285 #if 0 2286 extern "C" void SAL_CALL component_getImplementationEnvironment( 2287 const char ** envTypeName, uno_Environment **) 2288 { 2289 *envTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 2290 } 2291 2292 extern "C" void * SAL_CALL component_getFactory( 2293 const char * implName, void * serviceManager, void * registryKey) 2294 { 2295 return ::cppu::component_getFactoryHelper( 2296 implName, serviceManager, registryKey, entries); 2297 } 2298 #endif 2299