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