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