1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <cppuhelper/compbase.hxx>
24 #include <cppuhelper/exc_hlp.hxx>
25 #include <com/sun/star/lang/XServiceInfo.hpp>
26 #include <com/sun/star/document/XDocumentProperties.hpp>
27 #include <com/sun/star/lang/XInitialization.hpp>
28 #include <com/sun/star/util/XCloneable.hpp>
29 #include <com/sun/star/util/XModifiable.hpp>
30 #include <com/sun/star/xml/sax/SAXException.hpp>
31 #include <com/sun/star/xml/sax/XSAXSerializable.hpp>
33 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
34 #include <com/sun/star/lang/EventObject.hpp>
35 #include <com/sun/star/beans/IllegalTypeException.hpp>
36 #include <com/sun/star/beans/PropertyExistException.hpp>
37 #include <com/sun/star/beans/XPropertySet.hpp>
38 #include <com/sun/star/beans/XPropertySetInfo.hpp>
39 #include <com/sun/star/beans/PropertyAttribute.hpp>
40 #include <com/sun/star/task/ErrorCodeIOException.hpp>
41 #include <com/sun/star/embed/XStorage.hpp>
42 #include <com/sun/star/embed/XTransactedObject.hpp>
43 #include <com/sun/star/embed/ElementModes.hpp>
44 #include <com/sun/star/io/WrongFormatException.hpp>
45 #include <com/sun/star/io/XStream.hpp>
46 #include <com/sun/star/document/XImporter.hpp>
47 #include <com/sun/star/document/XExporter.hpp>
48 #include <com/sun/star/document/XFilter.hpp>
49 #include <com/sun/star/xml/sax/Parser.hpp>
50 #include <com/sun/star/xml/sax/Writer.hpp>
51 #include <com/sun/star/xml/sax/Parser.hpp>
52 #include <com/sun/star/xml/sax/XFastParser.hpp>
53 #include <com/sun/star/xml/dom/DOMException.hpp>
54 #include <com/sun/star/xml/dom/XDocument.hpp>
55 #include <com/sun/star/xml/dom/XElement.hpp>
56 #include <com/sun/star/xml/dom/DocumentBuilder.hpp>
57 #include <com/sun/star/xml/dom/NodeType.hpp>
58 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
59 #include <com/sun/star/util/Date.hpp>
60 #include <com/sun/star/util/Time.hpp>
61 #include <com/sun/star/util/DateWithTimezone.hpp>
62 #include <com/sun/star/util/DateTimeWithTimezone.hpp>
63 #include <com/sun/star/util/Duration.hpp>
65 #include <rtl/ustrbuf.hxx>
66 #include <tools/datetime.hxx>
67 #include <tools/diagnose_ex.h>
68 #include <osl/mutex.hxx>
69 #include <comphelper/fileformat.h>
70 #include <cppuhelper/basemutex.hxx>
71 #include <comphelper/interfacecontainer2.hxx>
72 #include <comphelper/storagehelper.hxx>
73 #include <unotools/mediadescriptor.hxx>
74 #include <comphelper/sequence.hxx>
75 #include <sot/storage.hxx>
76 #include <sfx2/docfile.hxx>
77 #include <sax/tools/converter.hxx>
78 #include <i18nlangtag/languagetag.hxx>
88 #include <cppuhelper/implbase.hxx>
89 #include <cppuhelper/supportsservice.hxx>
90 #include <com/sun/star/document/XCompatWriterDocProperties.hpp>
91 #include <com/sun/star/beans/PropertyBag.hpp>
94 * This file contains the implementation of the service
95 * com.sun.star.document.DocumentProperties.
96 * This service enables access to the meta-data stored in documents.
97 * Currently, this service only handles documents in ODF format.
99 * The implementation uses an XML DOM to store the properties.
100 * This approach was taken because it allows for preserving arbitrary XML data
101 * in loaded documents, which will be stored unmodified when saving the
104 * Upon access, some properties are directly read from and updated in the DOM.
105 * Exception: it seems impossible to get notified upon addition of a property
106 * to a com.sun.star.beans.PropertyBag, which is used for storing user-defined
107 * properties; because of this, user-defined properties are updated in the
108 * XML DOM only when storing the document.
109 * Exception 2: when setting certain properties which correspond to attributes
110 * in the XML DOM, we want to remove the corresponding XML element. Detecting
111 * this condition can get messy, so we store all such properties as members,
112 * and update the DOM tree only when storing the document (in
113 * <method>updateUserDefinedAndAttributes</method>).
117 /// anonymous implementation namespace
120 /// a list of attribute-lists, where attribute means name and content
121 typedef std::vector
<std::vector
<std::pair
<const char*, OUString
> > >
124 typedef ::cppu::WeakComponentImplHelper
<
125 css::lang::XServiceInfo
,
126 css::document::XDocumentProperties
,
127 css::lang::XInitialization
,
128 css::util::XCloneable
,
129 css::util::XModifiable
,
130 css::xml::sax::XSAXSerializable
>
131 SfxDocumentMetaData_Base
;
133 class SfxDocumentMetaData
:
134 private ::cppu::BaseMutex
,
135 public SfxDocumentMetaData_Base
138 explicit SfxDocumentMetaData(
139 css::uno::Reference
< css::uno::XComponentContext
> const & context
);
140 SfxDocumentMetaData(const SfxDocumentMetaData
&) = delete;
141 SfxDocumentMetaData
& operator=(const SfxDocumentMetaData
&) = delete;
143 // css::lang::XServiceInfo:
144 virtual OUString SAL_CALL
getImplementationName() override
;
145 virtual sal_Bool SAL_CALL
supportsService(
146 const OUString
& ServiceName
) override
;
147 virtual css::uno::Sequence
< OUString
> SAL_CALL
148 getSupportedServiceNames() override
;
150 // css::lang::XComponent:
151 virtual void SAL_CALL
dispose() override
;
153 // css::document::XDocumentProperties:
154 virtual OUString SAL_CALL
getAuthor() override
;
155 virtual void SAL_CALL
setAuthor(const OUString
& the_value
) override
;
156 virtual OUString SAL_CALL
getGenerator() override
;
157 virtual void SAL_CALL
setGenerator(const OUString
& the_value
) override
;
158 virtual css::util::DateTime SAL_CALL
getCreationDate() override
;
159 virtual void SAL_CALL
setCreationDate(const css::util::DateTime
& the_value
) override
;
160 virtual OUString SAL_CALL
getTitle() override
;
161 virtual void SAL_CALL
setTitle(const OUString
& the_value
) override
;
162 virtual OUString SAL_CALL
getSubject() override
;
163 virtual void SAL_CALL
setSubject(const OUString
& the_value
) override
;
164 virtual OUString SAL_CALL
getDescription() override
;
165 virtual void SAL_CALL
setDescription(const OUString
& the_value
) override
;
166 virtual css::uno::Sequence
< OUString
> SAL_CALL
getKeywords() override
;
167 virtual void SAL_CALL
setKeywords(
168 const css::uno::Sequence
< OUString
> & the_value
) override
;
169 virtual css::lang::Locale SAL_CALL
getLanguage() override
;
170 virtual void SAL_CALL
setLanguage(const css::lang::Locale
& the_value
) override
;
171 virtual OUString SAL_CALL
getModifiedBy() override
;
172 virtual void SAL_CALL
setModifiedBy(const OUString
& the_value
) override
;
173 virtual css::util::DateTime SAL_CALL
getModificationDate() override
;
174 virtual void SAL_CALL
setModificationDate(
175 const css::util::DateTime
& the_value
) override
;
176 virtual OUString SAL_CALL
getPrintedBy() override
;
177 virtual void SAL_CALL
setPrintedBy(const OUString
& the_value
) override
;
178 virtual css::util::DateTime SAL_CALL
getPrintDate() override
;
179 virtual void SAL_CALL
setPrintDate(const css::util::DateTime
& the_value
) override
;
180 virtual OUString SAL_CALL
getTemplateName() override
;
181 virtual void SAL_CALL
setTemplateName(const OUString
& the_value
) override
;
182 virtual OUString SAL_CALL
getTemplateURL() override
;
183 virtual void SAL_CALL
setTemplateURL(const OUString
& the_value
) override
;
184 virtual css::util::DateTime SAL_CALL
getTemplateDate() override
;
185 virtual void SAL_CALL
setTemplateDate(const css::util::DateTime
& the_value
) override
;
186 virtual OUString SAL_CALL
getAutoloadURL() override
;
187 virtual void SAL_CALL
setAutoloadURL(const OUString
& the_value
) override
;
188 virtual ::sal_Int32 SAL_CALL
getAutoloadSecs() override
;
189 virtual void SAL_CALL
setAutoloadSecs(::sal_Int32 the_value
) override
;
190 virtual OUString SAL_CALL
getDefaultTarget() override
;
191 virtual void SAL_CALL
setDefaultTarget(const OUString
& the_value
) override
;
192 virtual css::uno::Sequence
< css::beans::NamedValue
> SAL_CALL
193 getDocumentStatistics() override
;
194 virtual void SAL_CALL
setDocumentStatistics(
195 const css::uno::Sequence
< css::beans::NamedValue
> & the_value
) override
;
196 virtual ::sal_Int16 SAL_CALL
getEditingCycles() override
;
197 virtual void SAL_CALL
setEditingCycles(::sal_Int16 the_value
) override
;
198 virtual ::sal_Int32 SAL_CALL
getEditingDuration() override
;
199 virtual void SAL_CALL
setEditingDuration(::sal_Int32 the_value
) override
;
200 virtual void SAL_CALL
resetUserData(const OUString
& the_value
) override
;
201 virtual css::uno::Reference
< css::beans::XPropertyContainer
> SAL_CALL
202 getUserDefinedProperties() override
;
203 virtual void SAL_CALL
loadFromStorage(
204 const css::uno::Reference
< css::embed::XStorage
> & Storage
,
205 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
) override
;
206 virtual void SAL_CALL
loadFromMedium(const OUString
& URL
,
207 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
) override
;
208 virtual void SAL_CALL
storeToStorage(
209 const css::uno::Reference
< css::embed::XStorage
> & Storage
,
210 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
) override
;
211 virtual void SAL_CALL
storeToMedium(const OUString
& URL
,
212 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
) override
;
214 // css::lang::XInitialization:
215 virtual void SAL_CALL
initialize(
216 const css::uno::Sequence
< css::uno::Any
> & aArguments
) override
;
218 // css::util::XCloneable:
219 virtual css::uno::Reference
<css::util::XCloneable
> SAL_CALL
createClone() override
;
221 // css::util::XModifiable:
222 virtual sal_Bool SAL_CALL
isModified( ) override
;
223 virtual void SAL_CALL
setModified( sal_Bool bModified
) override
;
225 // css::util::XModifyBroadcaster:
226 virtual void SAL_CALL
addModifyListener(
227 const css::uno::Reference
< css::util::XModifyListener
> & xListener
) override
;
228 virtual void SAL_CALL
removeModifyListener(
229 const css::uno::Reference
< css::util::XModifyListener
> & xListener
) override
;
231 // css::xml::sax::XSAXSerializable
232 virtual void SAL_CALL
serialize(
233 const css::uno::Reference
<css::xml::sax::XDocumentHandler
>& i_xHandler
,
234 const css::uno::Sequence
< css::beans::StringPair
>& i_rNamespaces
) override
;
237 virtual ~SfxDocumentMetaData() override
{}
238 virtual SfxDocumentMetaData
* createMe( css::uno::Reference
< css::uno::XComponentContext
> const & context
) { return new SfxDocumentMetaData( context
); };
239 const css::uno::Reference
< css::uno::XComponentContext
> m_xContext
;
242 ::comphelper::OInterfaceContainerHelper2 m_NotifyListeners
;
243 /// flag: false means not initialized yet, or disposed
244 bool m_isInitialized
;
247 /// meta-data DOM tree
248 css::uno::Reference
< css::xml::dom::XDocument
> m_xDoc
;
249 /// meta-data super node in the meta-data DOM tree
250 css::uno::Reference
< css::xml::dom::XNode
> m_xParent
;
251 /// standard meta data (single occurrence)
252 std::map
< OUString
, css::uno::Reference
<css::xml::dom::XNode
> >
254 /// standard meta data (multiple occurrences)
256 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> > > m_metaList
;
257 /// user-defined meta data (meta:user-defined) @ATTENTION may be null!
258 css::uno::Reference
<css::beans::XPropertyContainer
> m_xUserDefined
;
259 // now for some meta-data attributes; these are not updated directly in the
260 // DOM because updates (detecting "empty" elements) would be quite messy
261 OUString m_TemplateName
;
262 OUString m_TemplateURL
;
263 css::util::DateTime m_TemplateDate
;
264 OUString m_AutoloadURL
;
265 sal_Int32 m_AutoloadSecs
;
266 OUString m_DefaultTarget
;
268 /// check if we are initialized properly
269 void checkInit() const;
270 /// initialize state from given DOM tree
271 void init(const css::uno::Reference
<css::xml::dom::XDocument
>& i_xDom
);
272 /// update element in DOM tree
273 void updateElement(const char *i_name
,
274 std::vector
<std::pair
<const char *, OUString
> >* i_pAttrs
= nullptr);
275 /// update user-defined meta data and attributes in DOM tree
276 void updateUserDefinedAndAttributes();
277 /// create empty DOM tree (XDocument)
278 css::uno::Reference
<css::xml::dom::XDocument
> createDOM() const;
279 /// extract base URL (necessary for converting relative links)
280 css::uno::Reference
<css::beans::XPropertySet
> getURLProperties(
281 const css::uno::Sequence
<css::beans::PropertyValue
> & i_rMedium
) const;
282 /// get text of standard meta data element
283 OUString
getMetaText(const char* i_name
) const;
284 /// set text of standard meta data element iff not equal to existing text
285 bool setMetaText(const char* i_name
,
286 const OUString
& i_rValue
);
287 /// set text of standard meta data element iff not equal to existing text
288 void setMetaTextAndNotify(const char* i_name
,
289 const OUString
& i_rValue
);
290 /// get text of standard meta data element's attribute
291 OUString
getMetaAttr(const char* i_name
,
292 const char* i_attr
) const;
293 /// get text of a list of standard meta data elements (multiple occ.)
294 css::uno::Sequence
< OUString
> getMetaList(
295 const char* i_name
) const;
296 /// set text of a list of standard meta data elements (multiple occ.)
297 bool setMetaList(const char* i_name
,
298 const css::uno::Sequence
< OUString
> & i_rValue
,
300 void createUserDefined();
303 typedef ::cppu::ImplInheritanceHelper
< SfxDocumentMetaData
, css::document::XCompatWriterDocProperties
> CompatWriterDocPropsImpl_BASE
;
305 class CompatWriterDocPropsImpl
: public CompatWriterDocPropsImpl_BASE
311 virtual SfxDocumentMetaData
* createMe( css::uno::Reference
< css::uno::XComponentContext
> const & context
) override
{ return new CompatWriterDocPropsImpl( context
); };
313 explicit CompatWriterDocPropsImpl( css::uno::Reference
< css::uno::XComponentContext
> const & context
) : CompatWriterDocPropsImpl_BASE( context
) {}
315 // XCompatWriterDocPropsImpl
316 virtual OUString SAL_CALL
getManager() override
{ return msManager
; }
317 virtual void SAL_CALL
setManager( const OUString
& _manager
) override
{ msManager
= _manager
; }
318 virtual OUString SAL_CALL
getCategory() override
{ return msCategory
; }
319 virtual void SAL_CALL
setCategory( const OUString
& _category
) override
{ msCategory
= _category
; }
320 virtual OUString SAL_CALL
getCompany() override
{ return msCompany
; }
321 virtual void SAL_CALL
setCompany( const OUString
& _company
) override
{ msCompany
= _company
; }
324 virtual OUString SAL_CALL
getImplementationName( ) override
326 return "CompatWriterDocPropsImpl";
329 virtual sal_Bool SAL_CALL
supportsService( const OUString
& ServiceName
) override
331 return cppu::supportsService(this, ServiceName
);
334 virtual css::uno::Sequence
< OUString
> SAL_CALL
getSupportedServiceNames( ) override
336 css::uno::Sequence
<OUString
> aServiceNames
{ "com.sun.star.writer.DocumentProperties" };
337 return aServiceNames
;
341 // NB: keep these two arrays in sync!
342 const char* s_stdStatAttrs
[] = {
348 "meta:ole-object-count",
349 "meta:paragraph-count",
351 "meta:character-count",
354 "meta:sentence-count",
355 "meta:syllable-count",
356 "meta:non-whitespace-character-count",
361 // NB: keep these two arrays in sync!
362 const char* s_stdStats
[] = {
376 "NonWhitespaceCharacterCount",
381 const char* s_stdMeta
[] = {
382 "meta:generator", // string
383 "dc:title", // string
384 "dc:description", // string
385 "dc:subject", // string
386 "meta:initial-creator", // string
387 "dc:creator", // string
388 "meta:printed-by", // string
389 "meta:creation-date", // dateTime
390 "dc:date", // dateTime
391 "meta:print-date", // dateTime
392 "meta:template", // XLink
394 "meta:hyperlink-behaviour",
395 "dc:language", // language
396 "meta:editing-cycles", // nonNegativeInteger
397 "meta:editing-duration", // duration
398 "meta:document-statistic", // ... // note: statistic is singular, no s!
402 const char* s_stdMetaList
[] = {
403 "meta:keyword", // string*
404 "meta:user-defined", // ...*
408 const char s_nsXLink
[] = "http://www.w3.org/1999/xlink";
409 const char s_nsDC
[] = "http://purl.org/dc/elements/1.1/";
410 const char s_nsODF
[] = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
411 const char s_nsODFMeta
[] = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0";
412 // const char* s_nsOOo = "http://openoffice.org/2004/office"; // not used (yet?)
414 const char s_meta
[] = "meta.xml";
416 bool isValidDate(const css::util::Date
& i_rDate
)
418 return i_rDate
.Month
> 0;
421 bool isValidDateTime(const css::util::DateTime
& i_rDateTime
)
423 return i_rDateTime
.Month
> 0;
426 std::pair
< OUString
, OUString
>
427 getQualifier(const char* i_name
) {
428 OUString nm
= OUString::createFromAscii(i_name
);
429 sal_Int32 ix
= nm
.indexOf(u
':');
431 return std::make_pair(OUString(), nm
);
433 return std::make_pair(nm
.copy(0,ix
), nm
.copy(ix
+1));
437 // get namespace for standard qualified names
438 // NB: only call this with statically known strings!
439 OUString
getNameSpace(const char* i_qname
) throw ()
442 const char * ns
= "";
443 OUString n
= getQualifier(i_qname
).first
;
444 if ( n
== "xlink" ) ns
= s_nsXLink
;
445 if ( n
== "dc" ) ns
= s_nsDC
;
446 if ( n
== "office" ) ns
= s_nsODF
;
447 if ( n
== "meta" ) ns
= s_nsODFMeta
;
449 return OUString::createFromAscii(ns
);
453 textToDateOrDateTime(css::util::Date
& io_rd
, css::util::DateTime
& io_rdt
,
454 bool & o_rIsDateTime
, std::optional
<sal_Int16
> & o_rTimeZone
,
455 const OUString
& i_text
) throw ()
457 if (::sax::Converter::parseDateOrDateTime(
458 &io_rd
, io_rdt
, o_rIsDateTime
, &o_rTimeZone
, i_text
)) {
461 SAL_WARN_IF(!i_text
.isEmpty(), "sfx.doc", "Invalid date: " << i_text
);
466 // convert string to date/time
468 textToDateTime(css::util::DateTime
& io_rdt
, const OUString
& i_text
) throw ()
470 if (::sax::Converter::parseDateTime(io_rdt
, i_text
)) {
473 SAL_WARN_IF(!i_text
.isEmpty(), "sfx.doc", "Invalid date: " << i_text
);
478 // convert string to date/time with default return value
480 textToDateTimeDefault(const OUString
& i_text
) throw ()
482 css::util::DateTime dt
;
483 static_cast<void> (textToDateTime(dt
, i_text
));
484 // on conversion error: return default value (unchanged)
488 // convert date to string
490 dateToText(css::util::Date
const& i_rd
,
491 sal_Int16
const*const pTimeZone
) throw ()
493 if (isValidDate(i_rd
)) {
495 ::sax::Converter::convertDate(buf
, i_rd
, pTimeZone
);
496 return buf
.makeStringAndClear();
503 // convert date/time to string
505 dateTimeToText(css::util::DateTime
const& i_rdt
,
506 sal_Int16
const*const pTimeZone
= nullptr) throw ()
508 if (isValidDateTime(i_rdt
)) {
509 OUStringBuffer
buf(32);
510 ::sax::Converter::convertDateTime(buf
, i_rdt
, pTimeZone
, true);
511 return buf
.makeStringAndClear();
517 // convert string to duration
519 textToDuration(css::util::Duration
& io_rDur
, OUString
const& i_rText
)
522 if (::sax::Converter::convertDuration(io_rDur
, i_rText
)) {
525 SAL_WARN_IF(!i_rText
.isEmpty(), "sfx.doc", "Invalid duration: " << i_rText
);
530 sal_Int32
textToDuration(OUString
const& i_rText
) throw ()
532 css::util::Duration d
;
533 if (textToDuration(d
, i_rText
)) {
534 // #i107372#: approximate years/months
535 const sal_Int32
days( (d
.Years
* 365) + (d
.Months
* 30) + d
.Days
);
536 return (days
* (24*3600))
537 + (d
.Hours
* 3600) + (d
.Minutes
* 60) + d
.Seconds
;
543 // convert duration to string
544 OUString
durationToText(css::util::Duration
const& i_rDur
) throw ()
547 ::sax::Converter::convertDuration(buf
, i_rDur
);
548 return buf
.makeStringAndClear();
551 // convert duration to string
552 OUString
durationToText(sal_Int32 i_value
) throw ()
554 css::util::Duration ud
;
555 ud
.Days
= static_cast<sal_Int16
>(i_value
/ (24 * 3600));
556 ud
.Hours
= static_cast<sal_Int16
>((i_value
% (24 * 3600)) / 3600);
557 ud
.Minutes
= static_cast<sal_Int16
>((i_value
% 3600) / 60);
558 ud
.Seconds
= static_cast<sal_Int16
>(i_value
% 60);
560 return durationToText(ud
);
563 // extract base URL (necessary for converting relative links)
564 css::uno::Reference
< css::beans::XPropertySet
>
565 SfxDocumentMetaData::getURLProperties(
566 const css::uno::Sequence
< css::beans::PropertyValue
> & i_rMedium
) const
568 css::uno::Reference
< css::beans::XPropertyBag
> xPropArg
= css::beans::PropertyBag::createDefault( m_xContext
);
570 css::uno::Any baseUri
;
571 for (const auto& rProp
: i_rMedium
) {
572 if (rProp
.Name
== "DocumentBaseURL") {
573 baseUri
= rProp
.Value
;
574 } else if (rProp
.Name
== "URL") {
575 if (!baseUri
.hasValue()) {
576 baseUri
= rProp
.Value
;
578 } else if (rProp
.Name
== "HierarchicalDocumentName") {
579 xPropArg
->addProperty(
581 css::beans::PropertyAttribute::MAYBEVOID
,
585 if (baseUri
.hasValue()) {
586 xPropArg
->addProperty(
587 "BaseURI", css::beans::PropertyAttribute::MAYBEVOID
,
590 xPropArg
->addProperty("StreamName",
591 css::beans::PropertyAttribute::MAYBEVOID
,
592 css::uno::makeAny(OUString(s_meta
)));
593 } catch (const css::uno::Exception
&) {
596 return css::uno::Reference
< css::beans::XPropertySet
>(xPropArg
,
597 css::uno::UNO_QUERY_THROW
);
600 // return the text of the (hopefully unique, i.e., normalize first!) text
601 // node _below_ the given node
602 /// @throws css::uno::RuntimeException
604 getNodeText(const css::uno::Reference
<css::xml::dom::XNode
>& i_xNode
)
607 throw css::uno::RuntimeException("SfxDocumentMetaData::getNodeText: argument is null", i_xNode
);
608 for (css::uno::Reference
<css::xml::dom::XNode
> c
= i_xNode
->getFirstChild();
610 c
= c
->getNextSibling()) {
611 if (c
->getNodeType() == css::xml::dom::NodeType_TEXT_NODE
) {
613 return c
->getNodeValue();
614 } catch (const css::xml::dom::DOMException
&) { // too big?
623 SfxDocumentMetaData::getMetaText(const char* i_name
) const
624 // throw (css::uno::RuntimeException)
628 const OUString
name( OUString::createFromAscii(i_name
) );
629 assert(m_meta
.find(name
) != m_meta
.end());
630 css::uno::Reference
<css::xml::dom::XNode
> xNode
= m_meta
.find(name
)->second
;
631 return (xNode
.is()) ? getNodeText(xNode
) : OUString();
635 SfxDocumentMetaData::setMetaText(const char* i_name
,
636 const OUString
& i_rValue
)
637 // throw (css::uno::RuntimeException)
641 const OUString
name( OUString::createFromAscii(i_name
) );
642 assert(m_meta
.find(name
) != m_meta
.end());
643 css::uno::Reference
<css::xml::dom::XNode
> xNode
= m_meta
.find(name
)->second
;
646 if (i_rValue
.isEmpty()) {
647 if (xNode
.is()) { // delete
648 m_xParent
->removeChild(xNode
);
650 m_meta
[name
] = xNode
;
656 if (xNode
.is()) { // update
657 for (css::uno::Reference
<css::xml::dom::XNode
> c
=
658 xNode
->getFirstChild();
660 c
= c
->getNextSibling()) {
661 if (c
->getNodeType() == css::xml::dom::NodeType_TEXT_NODE
) {
662 if (c
->getNodeValue() != i_rValue
) {
663 c
->setNodeValue(i_rValue
);
671 xNode
.set(m_xDoc
->createElementNS(getNameSpace(i_name
), name
),
672 css::uno::UNO_QUERY_THROW
);
673 m_xParent
->appendChild(xNode
);
674 m_meta
[name
] = xNode
;
676 css::uno::Reference
<css::xml::dom::XNode
> xTextNode(
677 m_xDoc
->createTextNode(i_rValue
), css::uno::UNO_QUERY_THROW
);
678 xNode
->appendChild(xTextNode
);
681 } catch (const css::xml::dom::DOMException
&) {
682 css::uno::Any anyEx
= cppu::getCaughtException();
683 throw css::lang::WrappedTargetRuntimeException(
684 "SfxDocumentMetaData::setMetaText: DOM exception",
685 css::uno::Reference
<css::uno::XInterface
>(*this), anyEx
);
690 SfxDocumentMetaData::setMetaTextAndNotify(const char* i_name
,
691 const OUString
& i_rValue
)
692 // throw (css::uno::RuntimeException)
694 ::osl::ClearableMutexGuard
g(m_aMutex
);
695 if (setMetaText(i_name
, i_rValue
)) {
702 SfxDocumentMetaData::getMetaAttr(const char* i_name
, const char* i_attr
) const
703 // throw (css::uno::RuntimeException)
705 OUString name
= OUString::createFromAscii(i_name
);
706 assert(m_meta
.find(name
) != m_meta
.end());
707 css::uno::Reference
<css::xml::dom::XNode
> xNode
= m_meta
.find(name
)->second
;
709 css::uno::Reference
<css::xml::dom::XElement
> xElem(xNode
,
710 css::uno::UNO_QUERY_THROW
);
711 return xElem
->getAttributeNS(getNameSpace(i_attr
),
712 getQualifier(i_attr
).second
);
718 css::uno::Sequence
< OUString
>
719 SfxDocumentMetaData::getMetaList(const char* i_name
) const
720 // throw (css::uno::RuntimeException)
723 OUString name
= OUString::createFromAscii(i_name
);
724 assert(m_metaList
.find(name
) != m_metaList
.end());
725 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> > const & vec
=
726 m_metaList
.find(name
)->second
;
727 css::uno::Sequence
< OUString
> ret(vec
.size());
728 for (size_t i
= 0; i
< vec
.size(); ++i
) {
729 ret
[i
] = getNodeText(vec
.at(i
));
735 SfxDocumentMetaData::setMetaList(const char* i_name
,
736 const css::uno::Sequence
<OUString
> & i_rValue
,
737 AttrVector
const* i_pAttrs
)
738 // throw (css::uno::RuntimeException)
741 assert((i_pAttrs
== nullptr) ||
742 (static_cast<size_t>(i_rValue
.getLength()) == i_pAttrs
->size()));
745 OUString name
= OUString::createFromAscii(i_name
);
746 assert(m_metaList
.find(name
) != m_metaList
.end());
747 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> > & vec
=
750 // if nothing changed, do nothing
751 // alas, this does not check for permutations, or attributes...
752 if (nullptr == i_pAttrs
) {
753 if (static_cast<size_t>(i_rValue
.getLength()) == vec
.size()) {
755 for (sal_Int32 i
= 0; i
< i_rValue
.getLength(); ++i
) {
756 css::uno::Reference
<css::xml::dom::XNode
> xNode(vec
.at(i
));
758 OUString val
= getNodeText(xNode
);
759 if (val
!= i_rValue
[i
]) {
765 if (isEqual
) return false;
769 // remove old meta data nodes
771 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> >
772 ::reverse_iterator
it(vec
.rbegin());
774 for ( ;it
!= vec
.rend(); ++it
)
776 m_xParent
->removeChild(*it
);
781 // Clean up already removed nodes
782 vec
.erase(it
.base(), vec
.end());
788 // insert new meta data nodes into DOM tree
789 for (sal_Int32 i
= 0; i
< i_rValue
.getLength(); ++i
) {
790 css::uno::Reference
<css::xml::dom::XElement
> xElem(
791 m_xDoc
->createElementNS(getNameSpace(i_name
), name
),
792 css::uno::UNO_SET_THROW
);
793 css::uno::Reference
<css::xml::dom::XNode
> xNode(xElem
,
794 css::uno::UNO_QUERY_THROW
);
795 css::uno::Reference
<css::xml::dom::XNode
> xTextNode(
796 m_xDoc
->createTextNode(i_rValue
[i
]), css::uno::UNO_QUERY_THROW
);
798 if (i_pAttrs
!= nullptr) {
799 for (auto const& elem
: (*i_pAttrs
)[i
])
801 xElem
->setAttributeNS(getNameSpace(elem
.first
),
802 OUString::createFromAscii(elem
.first
),
806 xNode
->appendChild(xTextNode
);
807 m_xParent
->appendChild(xNode
);
808 vec
.push_back(xNode
);
812 } catch (const css::xml::dom::DOMException
&) {
813 css::uno::Any anyEx
= cppu::getCaughtException();
814 throw css::lang::WrappedTargetRuntimeException(
815 "SfxDocumentMetaData::setMetaList: DOM exception",
816 css::uno::Reference
<css::uno::XInterface
>(*this), anyEx
);
820 // convert property list to string list and attribute list
821 std::pair
<css::uno::Sequence
< OUString
>, AttrVector
>
822 propsToStrings(css::uno::Reference
<css::beans::XPropertySet
> const & i_xPropSet
)
824 ::std::vector
< OUString
> values
;
827 css::uno::Reference
<css::beans::XPropertySetInfo
> xSetInfo
828 = i_xPropSet
->getPropertySetInfo();
829 css::uno::Sequence
<css::beans::Property
> props
= xSetInfo
->getProperties();
831 for (sal_Int32 i
= 0; i
< props
.getLength(); ++i
) {
832 if (props
[i
].Attributes
& css::beans::PropertyAttribute::TRANSIENT
) {
835 const OUString name
= props
[i
].Name
;
838 any
= i_xPropSet
->getPropertyValue(name
);
839 } catch (const css::uno::Exception
&) {
842 const css::uno::Type
& type
= any
.getValueType();
843 std::vector
<std::pair
<const char*, OUString
> > as
;
844 as
.emplace_back("meta:name", name
);
845 const char* vt
= "meta:value-type";
847 // convert according to type
848 if (type
== ::cppu::UnoType
<bool>::get()) {
852 ::sax::Converter::convertBool(buf
, b
);
853 values
.push_back(buf
.makeStringAndClear());
854 as
.emplace_back(vt
, OUString("boolean"));
855 } else if (type
== ::cppu::UnoType
< OUString
>::get()) {
859 // #i90847# OOo 2.x does stupid things if value-type="string";
860 // fortunately string is default anyway, so we can just omit it
861 // #i107502#: however, OOo 2.x only reads 4 user-defined without @value-type
862 // => best backward compatibility: first 4 without @value-type, rest with
865 as
.emplace_back(vt
, OUString("string"));
867 } else if (type
== ::cppu::UnoType
<css::util::DateTime
>::get()) {
868 css::util::DateTime dt
;
870 values
.push_back(dateTimeToText(dt
));
871 as
.emplace_back(vt
, OUString("date"));
872 } else if (type
== ::cppu::UnoType
<css::util::Date
>::get()) {
875 values
.push_back(dateToText(d
, nullptr));
876 as
.emplace_back(vt
,OUString("date"));
877 } else if (type
== ::cppu::UnoType
<css::util::DateTimeWithTimezone
>::get()) {
878 css::util::DateTimeWithTimezone dttz
;
880 values
.push_back(dateTimeToText(dttz
.DateTimeInTZ
, &dttz
.Timezone
));
881 as
.emplace_back(vt
, OUString("date"));
882 } else if (type
== ::cppu::UnoType
<css::util::DateWithTimezone
>::get()) {
883 css::util::DateWithTimezone dtz
;
885 values
.push_back(dateToText(dtz
.DateInTZ
, &dtz
.Timezone
));
886 as
.emplace_back(vt
, OUString("date"));
887 } else if (type
== ::cppu::UnoType
<css::util::Time
>::get()) {
888 // #i97029#: replaced by Duration
889 // Time is supported for backward compatibility with OOo 3.x, x<=2
892 css::util::Duration ud
;
894 ud
.Minutes
= ut
.Minutes
;
895 ud
.Seconds
= ut
.Seconds
;
896 ud
.NanoSeconds
= ut
.NanoSeconds
;
897 values
.push_back(durationToText(ud
));
898 as
.emplace_back(vt
, OUString("time"));
899 } else if (type
== ::cppu::UnoType
<css::util::Duration
>::get()) {
900 css::util::Duration ud
;
902 values
.push_back(durationToText(ud
));
903 as
.emplace_back(vt
, OUString("time"));
904 } else if (::cppu::UnoType
<double>::get().isAssignableFrom(type
)) {
905 // support not just double, but anything that can be converted
909 ::sax::Converter::convertDouble(buf
, d
);
910 values
.push_back(buf
.makeStringAndClear());
911 as
.emplace_back(vt
, OUString("float"));
913 SAL_WARN("sfx.doc", "Unsupported property type: " << any
.getValueTypeName() );
919 return std::make_pair(comphelper::containerToSequence(values
), attrs
);
922 // remove the given element from the DOM, and iff i_pAttrs != 0 insert new one
924 SfxDocumentMetaData::updateElement(const char *i_name
,
925 std::vector
<std::pair
<const char *, OUString
> >* i_pAttrs
)
927 OUString name
= OUString::createFromAscii(i_name
);
929 // remove old element
930 css::uno::Reference
<css::xml::dom::XNode
> xNode
=
931 m_meta
.find(name
)->second
;
933 m_xParent
->removeChild(xNode
);
937 if (nullptr != i_pAttrs
) {
938 css::uno::Reference
<css::xml::dom::XElement
> xElem(
939 m_xDoc
->createElementNS(getNameSpace(i_name
), name
),
940 css::uno::UNO_SET_THROW
);
941 xNode
.set(xElem
, css::uno::UNO_QUERY_THROW
);
943 for (auto const& elem
: *i_pAttrs
)
945 xElem
->setAttributeNS(getNameSpace(elem
.first
),
946 OUString::createFromAscii(elem
.first
), elem
.second
);
948 m_xParent
->appendChild(xNode
);
950 m_meta
[name
] = xNode
;
951 } catch (const css::xml::dom::DOMException
&) {
952 css::uno::Any anyEx
= cppu::getCaughtException();
953 throw css::lang::WrappedTargetRuntimeException(
954 "SfxDocumentMetaData::updateElement: DOM exception",
955 css::uno::Reference
<css::uno::XInterface
>(*this), anyEx
);
959 // update user-defined meta data in DOM tree
960 void SfxDocumentMetaData::updateUserDefinedAndAttributes()
963 const css::uno::Reference
<css::beans::XPropertySet
> xPSet(m_xUserDefined
,
964 css::uno::UNO_QUERY_THROW
);
965 const std::pair
<css::uno::Sequence
< OUString
>, AttrVector
>
966 udStringsAttrs( propsToStrings(xPSet
) );
967 (void) setMetaList("meta:user-defined", udStringsAttrs
.first
,
968 &udStringsAttrs
.second
);
970 // update elements with attributes
971 std::vector
<std::pair
<const char *, OUString
> > attributes
;
972 if (!m_TemplateName
.isEmpty() || !m_TemplateURL
.isEmpty()
973 || isValidDateTime(m_TemplateDate
)) {
974 attributes
.emplace_back("xlink:type", OUString("simple"));
975 attributes
.emplace_back("xlink:actuate", OUString("onRequest"));
976 attributes
.emplace_back("xlink:title", m_TemplateName
);
977 attributes
.emplace_back("xlink:href", m_TemplateURL
);
978 if (isValidDateTime(m_TemplateDate
)) {
979 attributes
.emplace_back(
980 "meta:date", dateTimeToText(m_TemplateDate
));
982 updateElement("meta:template", &attributes
);
984 updateElement("meta:template");
988 if (!m_AutoloadURL
.isEmpty() || (0 != m_AutoloadSecs
)) {
989 attributes
.emplace_back("xlink:href", m_AutoloadURL
);
990 attributes
.emplace_back("meta:delay",
991 durationToText(m_AutoloadSecs
));
992 updateElement("meta:auto-reload", &attributes
);
994 updateElement("meta:auto-reload");
998 if (!m_DefaultTarget
.isEmpty()) {
999 attributes
.emplace_back(
1000 "office:target-frame-name",
1002 // xlink:show: _blank -> new, any other value -> replace
1003 const char* show
= m_DefaultTarget
== "_blank" ? "new" : "replace";
1004 attributes
.emplace_back(
1006 OUString::createFromAscii(show
));
1007 updateElement("meta:hyperlink-behaviour", &attributes
);
1009 updateElement("meta:hyperlink-behaviour");
1014 // create empty DOM tree (XDocument)
1015 css::uno::Reference
<css::xml::dom::XDocument
>
1016 SfxDocumentMetaData::createDOM() const // throw (css::uno::RuntimeException)
1018 css::uno::Reference
<css::xml::dom::XDocumentBuilder
> xBuilder( css::xml::dom::DocumentBuilder::create(m_xContext
) );
1019 css::uno::Reference
<css::xml::dom::XDocument
> xDoc
= xBuilder
->newDocument();
1021 throw css::uno::RuntimeException(
1022 "SfxDocumentMetaData::createDOM: cannot create new document",
1023 *const_cast<SfxDocumentMetaData
*>(this));
1028 SfxDocumentMetaData::checkInit() const // throw (css::uno::RuntimeException)
1030 if (!m_isInitialized
) {
1031 throw css::uno::RuntimeException(
1032 "SfxDocumentMetaData::checkInit: not initialized",
1033 *const_cast<SfxDocumentMetaData
*>(this));
1035 assert(m_xDoc
.is() && m_xParent
.is());
1038 // initialize state from DOM tree
1039 void SfxDocumentMetaData::init(
1040 const css::uno::Reference
<css::xml::dom::XDocument
>& i_xDoc
)
1043 throw css::uno::RuntimeException("SfxDocumentMetaData::init: no DOM tree given", *this);
1045 css::uno::Reference
<css::xml::xpath::XXPathAPI
> xPath
= css::xml::xpath::XPathAPI::create(m_xContext
);
1047 m_isInitialized
= false;
1050 // select nodes for standard meta data stuff
1051 xPath
->registerNS("xlink", s_nsXLink
);
1052 xPath
->registerNS("dc", s_nsDC
);
1053 xPath
->registerNS("office", s_nsODF
);
1054 xPath
->registerNS("meta", s_nsODFMeta
);
1055 // NB: we do not handle the single-XML-file ODF variant, which would
1056 // have the root element office:document.
1057 // The root of such documents must be converted in the importer!
1058 css::uno::Reference
<css::xml::dom::XNode
> xDocNode(
1059 m_xDoc
, css::uno::UNO_QUERY_THROW
);
1062 m_xParent
= xPath
->selectSingleNode(xDocNode
, "/child::office:document-meta/child::office:meta");
1063 } catch (const css::uno::Exception
&) {
1066 if (!m_xParent
.is()) {
1067 // all this create/append stuff may throw DOMException
1069 css::uno::Reference
<css::xml::dom::XElement
> xRElem
;
1070 css::uno::Reference
<css::xml::dom::XNode
> xNode(
1071 i_xDoc
->getFirstChild());
1072 while (xNode
.is()) {
1073 if (css::xml::dom::NodeType_ELEMENT_NODE
==xNode
->getNodeType())
1075 if ( xNode
->getNamespaceURI() == s_nsODF
&& xNode
->getLocalName() == "document-meta" )
1077 xRElem
.set(xNode
, css::uno::UNO_QUERY_THROW
);
1082 SAL_INFO("sfx.doc", "SfxDocumentMetaData::init(): "
1083 "deleting unexpected root element: "
1084 << xNode
->getLocalName());
1085 i_xDoc
->removeChild(xNode
);
1086 xNode
= i_xDoc
->getFirstChild(); // start over
1089 xNode
= xNode
->getNextSibling();
1093 xRElem
= i_xDoc
->createElementNS(
1094 s_nsODF
, "office:document-meta");
1095 css::uno::Reference
<css::xml::dom::XNode
> xRNode(xRElem
,
1096 css::uno::UNO_QUERY_THROW
);
1097 i_xDoc
->appendChild(xRNode
);
1099 xRElem
->setAttributeNS(s_nsODF
, "office:version", "1.0");
1100 // does not exist, otherwise m_xParent would not be null
1101 css::uno::Reference
<css::xml::dom::XNode
> xParent (
1102 i_xDoc
->createElementNS(s_nsODF
, "office:meta"),
1103 css::uno::UNO_QUERY_THROW
);
1104 xRElem
->appendChild(xParent
);
1105 m_xParent
= xParent
;
1106 } catch (const css::xml::dom::DOMException
&) {
1107 css::uno::Any anyEx
= cppu::getCaughtException();
1108 throw css::lang::WrappedTargetRuntimeException(
1109 "SfxDocumentMetaData::init: DOM exception",
1110 css::uno::Reference
<css::uno::XInterface
>(*this), anyEx
);
1115 // select nodes for elements of which we only handle one occurrence
1116 for (const char **pName
= s_stdMeta
; *pName
!= nullptr; ++pName
) {
1117 OUString name
= OUString::createFromAscii(*pName
);
1118 // NB: If a document contains more than one occurrence of a
1119 // meta-data element, we arbitrarily pick one of them here.
1120 // We do not remove the others, i.e., when we write the
1121 // document, it will contain the duplicates unchanged.
1122 // The ODF spec says that handling multiple occurrences is
1123 // application-specific.
1124 css::uno::Reference
<css::xml::dom::XNode
> xNode
=
1125 xPath
->selectSingleNode(m_xParent
, "child::" + name
);
1126 // Do not create an empty element if it is missing;
1127 // for certain elements, such as dateTime, this would be invalid
1128 m_meta
[name
] = xNode
;
1131 // select nodes for elements of which we handle all occurrences
1132 for (const char **pName
= s_stdMetaList
; *pName
!= nullptr; ++pName
) {
1133 OUString name
= OUString::createFromAscii(*pName
);
1134 css::uno::Reference
<css::xml::dom::XNodeList
> nodes
=
1135 xPath
->selectNodeList(m_xParent
, "child::" + name
);
1136 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> > v
;
1137 v
.reserve(nodes
->getLength());
1138 for (sal_Int32 i
= 0; i
< nodes
->getLength(); ++i
)
1140 v
.push_back(nodes
->item(i
));
1142 m_metaList
[name
] = v
;
1145 // initialize members corresponding to attributes from DOM nodes
1146 m_TemplateName
= getMetaAttr("meta:template", "xlink:title");
1147 m_TemplateURL
= getMetaAttr("meta:template", "xlink:href");
1149 textToDateTimeDefault(getMetaAttr("meta:template", "meta:date"));
1150 m_AutoloadURL
= getMetaAttr("meta:auto-reload", "xlink:href");
1152 textToDuration(getMetaAttr("meta:auto-reload", "meta:delay"));
1154 getMetaAttr("meta:hyperlink-behaviour", "office:target-frame-name");
1157 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> > & vec
=
1158 m_metaList
[OUString("meta:user-defined")];
1159 m_xUserDefined
.clear(); // #i105826#: reset (may be re-initialization)
1162 createUserDefined();
1165 // user-defined meta data: initialize PropertySet from DOM nodes
1166 for (auto const& elem
: vec
)
1168 css::uno::Reference
<css::xml::dom::XElement
> xElem(elem
,
1169 css::uno::UNO_QUERY_THROW
);
1171 OUString name
= xElem
->getAttributeNS(s_nsODFMeta
, "name");
1172 OUString type
= xElem
->getAttributeNS(s_nsODFMeta
, "value-type");
1173 OUString text
= getNodeText(elem
);
1174 if ( type
== "float" ) {
1176 if (::sax::Converter::convertDouble(d
, text
)) {
1179 SAL_WARN("sfx.doc", "Invalid float: " << text
);
1182 } else if ( type
== "date" ) {
1185 css::util::DateTime dt
;
1186 std::optional
<sal_Int16
> nTimeZone
;
1187 if (textToDateOrDateTime(d
, dt
, isDateTime
, nTimeZone
, text
)) {
1190 any
<<= css::util::DateTimeWithTimezone(dt
,
1197 any
<<= css::util::DateWithTimezone(d
, *nTimeZone
);
1203 SAL_WARN("sfx.doc", "Invalid date: " << text
);
1206 } else if ( type
== "time" ) {
1207 css::util::Duration ud
;
1208 if (textToDuration(ud
, text
)) {
1211 SAL_WARN("sfx.doc", "Invalid time: " << text
);
1214 } else if ( type
== "boolean" ) {
1216 if (::sax::Converter::convertBool(b
, text
)) {
1219 SAL_WARN("sfx.doc", "Invalid boolean: " << text
);
1226 m_xUserDefined
->addProperty(name
,
1227 css::beans::PropertyAttribute::REMOVABLE
, any
);
1228 } catch (const css::beans::PropertyExistException
&) {
1229 SAL_WARN("sfx.doc", "Duplicate: " << name
);
1230 // ignore; duplicate
1231 } catch (const css::beans::IllegalTypeException
&) {
1232 SAL_INFO("sfx.doc", "SfxDocumentMetaData: illegal type: " << name
);
1233 } catch (const css::lang::IllegalArgumentException
&) {
1234 SAL_INFO("sfx.doc", "SfxDocumentMetaData: illegal arg: " << name
);
1238 m_isModified
= false;
1239 m_isInitialized
= true;
1243 SfxDocumentMetaData::SfxDocumentMetaData(
1244 css::uno::Reference
< css::uno::XComponentContext
> const & context
)
1246 , SfxDocumentMetaData_Base(m_aMutex
)
1247 , m_xContext(context
)
1248 , m_NotifyListeners(m_aMutex
)
1249 , m_isInitialized(false)
1250 , m_isModified(false)
1253 assert(context
.is());
1254 assert(context
->getServiceManager().is());
1258 // com.sun.star.uno.XServiceInfo:
1260 SfxDocumentMetaData::getImplementationName()
1262 return "SfxDocumentMetaData";
1266 SfxDocumentMetaData::supportsService(OUString
const & serviceName
)
1268 return cppu::supportsService(this, serviceName
);
1271 css::uno::Sequence
< OUString
> SAL_CALL
1272 SfxDocumentMetaData::getSupportedServiceNames()
1274 css::uno::Sequence
< OUString
> s
{ "com.sun.star.document.DocumentProperties" };
1279 // css::lang::XComponent:
1280 void SAL_CALL
SfxDocumentMetaData::dispose()
1282 ::osl::MutexGuard
g(m_aMutex
);
1283 if (!m_isInitialized
) {
1286 WeakComponentImplHelperBase::dispose(); // superclass
1287 m_NotifyListeners
.disposeAndClear(css::lang::EventObject(
1288 static_cast< ::cppu::OWeakObject
* >(this)));
1289 m_isInitialized
= false;
1294 m_xUserDefined
.clear();
1298 // css::document::XDocumentProperties:
1300 SfxDocumentMetaData::getAuthor()
1302 ::osl::MutexGuard
g(m_aMutex
);
1303 return getMetaText("meta:initial-creator");
1306 void SAL_CALL
SfxDocumentMetaData::setAuthor(const OUString
& the_value
)
1308 setMetaTextAndNotify("meta:initial-creator", the_value
);
1313 SfxDocumentMetaData::getGenerator()
1315 ::osl::MutexGuard
g(m_aMutex
);
1316 return getMetaText("meta:generator");
1320 SfxDocumentMetaData::setGenerator(const OUString
& the_value
)
1322 setMetaTextAndNotify("meta:generator", the_value
);
1325 css::util::DateTime SAL_CALL
1326 SfxDocumentMetaData::getCreationDate()
1328 ::osl::MutexGuard
g(m_aMutex
);
1329 return textToDateTimeDefault(getMetaText("meta:creation-date"));
1333 SfxDocumentMetaData::setCreationDate(const css::util::DateTime
& the_value
)
1335 setMetaTextAndNotify("meta:creation-date", dateTimeToText(the_value
));
1339 SfxDocumentMetaData::getTitle()
1341 ::osl::MutexGuard
g(m_aMutex
);
1342 return getMetaText("dc:title");
1345 void SAL_CALL
SfxDocumentMetaData::setTitle(const OUString
& the_value
)
1347 setMetaTextAndNotify("dc:title", the_value
);
1351 SfxDocumentMetaData::getSubject()
1353 ::osl::MutexGuard
g(m_aMutex
);
1354 return getMetaText("dc:subject");
1358 SfxDocumentMetaData::setSubject(const OUString
& the_value
)
1360 setMetaTextAndNotify("dc:subject", the_value
);
1364 SfxDocumentMetaData::getDescription()
1366 ::osl::MutexGuard
g(m_aMutex
);
1367 return getMetaText("dc:description");
1371 SfxDocumentMetaData::setDescription(const OUString
& the_value
)
1373 setMetaTextAndNotify("dc:description", the_value
);
1376 css::uno::Sequence
< OUString
>
1377 SAL_CALL
SfxDocumentMetaData::getKeywords()
1379 ::osl::MutexGuard
g(m_aMutex
);
1380 return getMetaList("meta:keyword");
1384 SfxDocumentMetaData::setKeywords(
1385 const css::uno::Sequence
< OUString
> & the_value
)
1387 ::osl::ClearableMutexGuard
g(m_aMutex
);
1388 if (setMetaList("meta:keyword", the_value
, nullptr)) {
1394 css::lang::Locale SAL_CALL
1395 SfxDocumentMetaData::getLanguage()
1397 ::osl::MutexGuard
g(m_aMutex
);
1398 css::lang::Locale
loc( LanguageTag::convertToLocale( getMetaText("dc:language"), false));
1403 SfxDocumentMetaData::setLanguage(const css::lang::Locale
& the_value
)
1405 OUString
text( LanguageTag::convertToBcp47( the_value
, false));
1406 setMetaTextAndNotify("dc:language", text
);
1410 SfxDocumentMetaData::getModifiedBy()
1412 ::osl::MutexGuard
g(m_aMutex
);
1413 return getMetaText("dc:creator");
1417 SfxDocumentMetaData::setModifiedBy(const OUString
& the_value
)
1419 setMetaTextAndNotify("dc:creator", the_value
);
1422 css::util::DateTime SAL_CALL
1423 SfxDocumentMetaData::getModificationDate()
1425 ::osl::MutexGuard
g(m_aMutex
);
1426 return textToDateTimeDefault(getMetaText("dc:date"));
1430 SfxDocumentMetaData::setModificationDate(const css::util::DateTime
& the_value
)
1432 setMetaTextAndNotify("dc:date", dateTimeToText(the_value
));
1436 SfxDocumentMetaData::getPrintedBy()
1438 ::osl::MutexGuard
g(m_aMutex
);
1439 return getMetaText("meta:printed-by");
1443 SfxDocumentMetaData::setPrintedBy(const OUString
& the_value
)
1445 setMetaTextAndNotify("meta:printed-by", the_value
);
1448 css::util::DateTime SAL_CALL
1449 SfxDocumentMetaData::getPrintDate()
1451 ::osl::MutexGuard
g(m_aMutex
);
1452 return textToDateTimeDefault(getMetaText("meta:print-date"));
1456 SfxDocumentMetaData::setPrintDate(const css::util::DateTime
& the_value
)
1458 setMetaTextAndNotify("meta:print-date", dateTimeToText(the_value
));
1462 SfxDocumentMetaData::getTemplateName()
1464 ::osl::MutexGuard
g(m_aMutex
);
1466 return m_TemplateName
;
1470 SfxDocumentMetaData::setTemplateName(const OUString
& the_value
)
1472 ::osl::ClearableMutexGuard
g(m_aMutex
);
1474 if (m_TemplateName
!= the_value
) {
1475 m_TemplateName
= the_value
;
1482 SfxDocumentMetaData::getTemplateURL()
1484 ::osl::MutexGuard
g(m_aMutex
);
1486 return m_TemplateURL
;
1490 SfxDocumentMetaData::setTemplateURL(const OUString
& the_value
)
1492 ::osl::ClearableMutexGuard
g(m_aMutex
);
1494 if (m_TemplateURL
!= the_value
) {
1495 m_TemplateURL
= the_value
;
1501 css::util::DateTime SAL_CALL
1502 SfxDocumentMetaData::getTemplateDate()
1504 ::osl::MutexGuard
g(m_aMutex
);
1506 return m_TemplateDate
;
1510 SfxDocumentMetaData::setTemplateDate(const css::util::DateTime
& the_value
)
1512 ::osl::ClearableMutexGuard
g(m_aMutex
);
1514 if (m_TemplateDate
!= the_value
) {
1515 m_TemplateDate
= the_value
;
1522 SfxDocumentMetaData::getAutoloadURL()
1524 ::osl::MutexGuard
g(m_aMutex
);
1526 return m_AutoloadURL
;
1530 SfxDocumentMetaData::setAutoloadURL(const OUString
& the_value
)
1532 ::osl::ClearableMutexGuard
g(m_aMutex
);
1534 if (m_AutoloadURL
!= the_value
) {
1535 m_AutoloadURL
= the_value
;
1541 ::sal_Int32 SAL_CALL
1542 SfxDocumentMetaData::getAutoloadSecs()
1544 ::osl::MutexGuard
g(m_aMutex
);
1546 return m_AutoloadSecs
;
1550 SfxDocumentMetaData::setAutoloadSecs(::sal_Int32 the_value
)
1553 throw css::lang::IllegalArgumentException(
1554 "SfxDocumentMetaData::setAutoloadSecs: argument is negative",
1556 ::osl::ClearableMutexGuard
g(m_aMutex
);
1558 if (m_AutoloadSecs
!= the_value
) {
1559 m_AutoloadSecs
= the_value
;
1566 SfxDocumentMetaData::getDefaultTarget()
1568 ::osl::MutexGuard
g(m_aMutex
);
1570 return m_DefaultTarget
;
1574 SfxDocumentMetaData::setDefaultTarget(const OUString
& the_value
)
1576 ::osl::ClearableMutexGuard
g(m_aMutex
);
1578 if (m_DefaultTarget
!= the_value
) {
1579 m_DefaultTarget
= the_value
;
1585 css::uno::Sequence
< css::beans::NamedValue
> SAL_CALL
1586 SfxDocumentMetaData::getDocumentStatistics()
1588 ::osl::MutexGuard
g(m_aMutex
);
1590 ::std::vector
<css::beans::NamedValue
> stats
;
1591 for (size_t i
= 0; s_stdStats
[i
] != nullptr; ++i
) {
1592 const char * aName
= s_stdStatAttrs
[i
];
1593 OUString text
= getMetaAttr("meta:document-statistic", aName
);
1594 if (text
.isEmpty()) continue;
1595 css::beans::NamedValue stat
;
1596 stat
.Name
= OUString::createFromAscii(s_stdStats
[i
]);
1599 if (!::sax::Converter::convertNumber(val
, text
, 0) || (val
< 0)) {
1601 SAL_WARN("sfx.doc", "Invalid number: " << text
);
1605 stats
.push_back(stat
);
1608 return ::comphelper::containerToSequence(stats
);
1612 SfxDocumentMetaData::setDocumentStatistics(
1613 const css::uno::Sequence
< css::beans::NamedValue
> & the_value
)
1616 osl::MutexGuard
g(m_aMutex
);
1618 std::vector
<std::pair
<const char *, OUString
> > attributes
;
1619 for (const auto& rValue
: the_value
) {
1620 const OUString name
= rValue
.Name
;
1621 // inefficiently search for matching attribute
1622 for (size_t j
= 0; s_stdStats
[j
] != nullptr; ++j
) {
1623 if (name
.equalsAscii(s_stdStats
[j
])) {
1624 const css::uno::Any any
= rValue
.Value
;
1627 attributes
.emplace_back(s_stdStatAttrs
[j
],
1628 OUString::number(val
));
1631 SAL_WARN("sfx.doc", "Invalid statistic: " << name
);
1637 updateElement("meta:document-statistic", &attributes
);
1642 ::sal_Int16 SAL_CALL
1643 SfxDocumentMetaData::getEditingCycles()
1645 ::osl::MutexGuard
g(m_aMutex
);
1646 OUString text
= getMetaText("meta:editing-cycles");
1648 if (::sax::Converter::convertNumber(ret
, text
,
1649 0, std::numeric_limits
<sal_Int16
>::max())) {
1650 return static_cast<sal_Int16
>(ret
);
1657 SfxDocumentMetaData::setEditingCycles(::sal_Int16 the_value
)
1660 throw css::lang::IllegalArgumentException(
1661 "SfxDocumentMetaData::setEditingCycles: argument is negative",
1663 setMetaTextAndNotify("meta:editing-cycles", OUString::number(the_value
));
1666 ::sal_Int32 SAL_CALL
1667 SfxDocumentMetaData::getEditingDuration()
1669 ::osl::MutexGuard
g(m_aMutex
);
1670 return textToDuration(getMetaText("meta:editing-duration"));
1674 SfxDocumentMetaData::setEditingDuration(::sal_Int32 the_value
)
1677 throw css::lang::IllegalArgumentException(
1678 "SfxDocumentMetaData::setEditingDuration: argument is negative",
1680 setMetaTextAndNotify("meta:editing-duration", durationToText(the_value
));
1684 SfxDocumentMetaData::resetUserData(const OUString
& the_value
)
1686 ::osl::ClearableMutexGuard
g(m_aMutex
);
1688 bool bModified( false );
1689 bModified
|= setMetaText("meta:initial-creator", the_value
);
1690 ::DateTime
now( ::DateTime::SYSTEM
);
1691 css::util::DateTime
uDT(now
.GetUNODateTime());
1692 bModified
|= setMetaText("meta:creation-date", dateTimeToText(uDT
));
1693 bModified
|= setMetaText("dc:creator", OUString());
1694 bModified
|= setMetaText("meta:printed-by", OUString());
1695 bModified
|= setMetaText("dc:date", dateTimeToText(css::util::DateTime()));
1696 bModified
|= setMetaText("meta:print-date",
1697 dateTimeToText(css::util::DateTime()));
1698 bModified
|= setMetaText("meta:editing-duration", durationToText(0));
1699 bModified
|= setMetaText("meta:editing-cycles",
1709 css::uno::Reference
< css::beans::XPropertyContainer
> SAL_CALL
1710 SfxDocumentMetaData::getUserDefinedProperties()
1712 ::osl::MutexGuard
g(m_aMutex
);
1714 createUserDefined();
1715 return m_xUserDefined
;
1720 SfxDocumentMetaData::loadFromStorage(
1721 const css::uno::Reference
< css::embed::XStorage
> & xStorage
,
1722 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
)
1725 throw css::lang::IllegalArgumentException("SfxDocumentMetaData::loadFromStorage: argument is null", *this, 0);
1726 ::osl::MutexGuard
g(m_aMutex
);
1728 // open meta data file
1729 css::uno::Reference
<css::io::XStream
> xStream(
1730 xStorage
->openStreamElement(
1732 css::embed::ElementModes::READ
) );
1733 if (!xStream
.is()) throw css::uno::RuntimeException();
1734 css::uno::Reference
<css::io::XInputStream
> xInStream
=
1735 xStream
->getInputStream();
1736 if (!xInStream
.is()) throw css::uno::RuntimeException();
1738 // create DOM parser service
1739 css::uno::Reference
<css::lang::XMultiComponentFactory
> xMsf (
1740 m_xContext
->getServiceManager());
1741 css::xml::sax::InputSource input
;
1742 input
.aInputStream
= xInStream
;
1744 sal_uInt64 version
= SotStorage::GetVersion( xStorage
);
1745 // Oasis is also the default (0)
1746 bool bOasis
= ( version
> SOFFICE_FILEFORMAT_60
|| version
== 0 );
1747 const char *pServiceName
= bOasis
1748 ? "com.sun.star.document.XMLOasisMetaImporter"
1749 : "com.sun.star.document.XMLMetaImporter";
1752 css::uno::Reference
<css::beans::XPropertySet
> xPropArg
=
1753 getURLProperties(Medium
);
1755 xPropArg
->getPropertyValue("BaseURI")
1756 >>= input
.sSystemId
;
1757 input
.sSystemId
+= OUStringLiteral(u
"/") + s_meta
;
1758 } catch (const css::uno::Exception
&) {
1759 input
.sSystemId
= s_meta
;
1761 css::uno::Sequence
< css::uno::Any
> args(1);
1762 args
[0] <<= xPropArg
;
1764 // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler
1765 css::uno::Reference
<XInterface
> xFilter
=
1766 xMsf
->createInstanceWithArgumentsAndContext(
1767 OUString::createFromAscii(pServiceName
), args
, m_xContext
);
1769 css::uno::Reference
<css::xml::sax::XFastParser
> xFastParser(xFilter
, css::uno::UNO_QUERY
);
1770 css::uno::Reference
<css::document::XImporter
> xImp(xFilter
, css::uno::UNO_QUERY_THROW
);
1771 xImp
->setTargetDocument(css::uno::Reference
<css::lang::XComponent
>(this));
1774 xFastParser
->parseStream(input
);
1777 css::uno::Reference
<css::xml::sax::XDocumentHandler
> xDocHandler(xFilter
, css::uno::UNO_QUERY_THROW
);
1778 css::uno::Reference
<css::xml::sax::XParser
> xParser
= css::xml::sax::Parser::create(m_xContext
);
1779 xParser
->setDocumentHandler(xDocHandler
);
1780 xParser
->parseStream(input
);
1782 } catch (const css::xml::sax::SAXException
&) {
1783 throw css::io::WrongFormatException(
1784 "SfxDocumentMetaData::loadFromStorage:"
1785 " XML parsing exception", *this);
1787 // NB: the implementation of XMLOasisMetaImporter calls initialize
1792 SfxDocumentMetaData::storeToStorage(
1793 const css::uno::Reference
< css::embed::XStorage
> & xStorage
,
1794 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
)
1797 throw css::lang::IllegalArgumentException(
1798 "SfxDocumentMetaData::storeToStorage: argument is null", *this, 0);
1799 ::osl::MutexGuard
g(m_aMutex
);
1802 // update user-defined meta data in DOM tree
1803 // updateUserDefinedAndAttributes(); // this will be done in serialize!
1805 // write into storage
1806 css::uno::Reference
<css::io::XStream
> xStream
=
1807 xStorage
->openStreamElement(s_meta
,
1808 css::embed::ElementModes::WRITE
1809 | css::embed::ElementModes::TRUNCATE
);
1810 if (!xStream
.is()) throw css::uno::RuntimeException();
1811 css::uno::Reference
< css::beans::XPropertySet
> xStreamProps(xStream
,
1812 css::uno::UNO_QUERY_THROW
);
1813 xStreamProps
->setPropertyValue(
1815 css::uno::makeAny(OUString("text/xml")));
1816 xStreamProps
->setPropertyValue(
1818 css::uno::makeAny(false));
1819 xStreamProps
->setPropertyValue(
1820 "UseCommonStoragePasswordEncryption",
1821 css::uno::makeAny(false));
1822 css::uno::Reference
<css::io::XOutputStream
> xOutStream
=
1823 xStream
->getOutputStream();
1824 if (!xOutStream
.is()) throw css::uno::RuntimeException();
1825 css::uno::Reference
<css::lang::XMultiComponentFactory
> xMsf (
1826 m_xContext
->getServiceManager());
1827 css::uno::Reference
<css::xml::sax::XWriter
> xSaxWriter(
1828 css::xml::sax::Writer::create(m_xContext
));
1829 xSaxWriter
->setOutputStream(xOutStream
);
1831 const sal_uInt64 version
= SotStorage::GetVersion( xStorage
);
1832 // Oasis is also the default (0)
1833 const bool bOasis
= ( version
> SOFFICE_FILEFORMAT_60
|| version
== 0 );
1834 const char *pServiceName
= bOasis
1835 ? "com.sun.star.document.XMLOasisMetaExporter"
1836 : "com.sun.star.document.XMLMetaExporter";
1839 css::uno::Reference
<css::beans::XPropertySet
> xPropArg
=
1840 getURLProperties(Medium
);
1841 css::uno::Sequence
< css::uno::Any
> args(2);
1842 args
[0] <<= xSaxWriter
;
1843 args
[1] <<= xPropArg
;
1845 css::uno::Reference
<css::document::XExporter
> xExp(
1846 xMsf
->createInstanceWithArgumentsAndContext(
1847 OUString::createFromAscii(pServiceName
), args
, m_xContext
),
1848 css::uno::UNO_QUERY_THROW
);
1849 xExp
->setSourceDocument(css::uno::Reference
<css::lang::XComponent
>(this));
1850 css::uno::Reference
<css::document::XFilter
> xFilter(xExp
,
1851 css::uno::UNO_QUERY_THROW
);
1852 if (!xFilter
->filter(css::uno::Sequence
< css::beans::PropertyValue
>())) {
1853 throw css::io::IOException(
1854 "SfxDocumentMetaData::storeToStorage: cannot filter", *this);
1856 css::uno::Reference
<css::embed::XTransactedObject
> xTransaction(
1857 xStorage
, css::uno::UNO_QUERY
);
1858 if (xTransaction
.is()) {
1859 xTransaction
->commit();
1864 SfxDocumentMetaData::loadFromMedium(const OUString
& URL
,
1865 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
)
1867 css::uno::Reference
<css::io::XInputStream
> xIn
;
1868 utl::MediaDescriptor
md(Medium
);
1869 // if we have a URL parameter, it replaces the one in the media descriptor
1870 if (!URL
.isEmpty()) {
1871 md
[ utl::MediaDescriptor::PROP_URL() ] <<= URL
;
1872 md
[ utl::MediaDescriptor::PROP_READONLY() ] <<= true;
1874 if (md
.addInputStream()) {
1875 md
[ utl::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn
;
1877 css::uno::Reference
<css::embed::XStorage
> xStorage
;
1880 xStorage
= ::comphelper::OStorageHelper::GetStorageFromInputStream(
1882 } else { // fallback to url parameter
1883 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL(
1884 URL
, css::embed::ElementModes::READ
, m_xContext
);
1886 } catch (const css::uno::RuntimeException
&) {
1888 } catch (const css::io::IOException
&) {
1890 } catch (const css::uno::Exception
&) {
1891 css::uno::Any anyEx
= cppu::getCaughtException();
1892 throw css::lang::WrappedTargetException(
1893 "SfxDocumentMetaData::loadFromMedium: exception",
1894 css::uno::Reference
<css::uno::XInterface
>(*this),
1897 if (!xStorage
.is()) {
1898 throw css::uno::RuntimeException(
1899 "SfxDocumentMetaData::loadFromMedium: cannot get Storage",
1902 loadFromStorage(xStorage
, md
.getAsConstPropertyValueList());
1906 SfxDocumentMetaData::storeToMedium(const OUString
& URL
,
1907 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
)
1909 utl::MediaDescriptor
md(Medium
);
1910 if (!URL
.isEmpty()) {
1911 md
[ utl::MediaDescriptor::PROP_URL() ] <<= URL
;
1913 SfxMedium
aMedium(md
.getAsConstPropertyValueList());
1914 css::uno::Reference
<css::embed::XStorage
> xStorage
1915 = aMedium
.GetOutputStorage();
1918 if (!xStorage
.is()) {
1919 throw css::uno::RuntimeException(
1920 "SfxDocumentMetaData::storeToMedium: cannot get Storage",
1923 // set MIME type of the storage
1924 utl::MediaDescriptor::const_iterator iter
1925 = md
.find(utl::MediaDescriptor::PROP_MEDIATYPE());
1926 if (iter
!= md
.end()) {
1927 css::uno::Reference
< css::beans::XPropertySet
> xProps(xStorage
,
1928 css::uno::UNO_QUERY_THROW
);
1929 xProps
->setPropertyValue(
1930 utl::MediaDescriptor::PROP_MEDIATYPE(),
1933 storeToStorage(xStorage
, md
.getAsConstPropertyValueList());
1936 const bool bOk
= aMedium
.Commit();
1939 ErrCode nError
= aMedium
.GetError();
1940 if ( nError
== ERRCODE_NONE
) {
1941 nError
= ERRCODE_IO_GENERAL
;
1944 throw css::task::ErrorCodeIOException(
1945 "SfxDocumentMetaData::storeToMedium <" + URL
+ "> Commit failed: " + nError
.toHexString(),
1946 css::uno::Reference
< css::uno::XInterface
>(), sal_uInt32(nError
));
1951 // css::lang::XInitialization:
1952 void SAL_CALL
SfxDocumentMetaData::initialize( const css::uno::Sequence
< css::uno::Any
> & aArguments
)
1954 // possible arguments:
1955 // - no argument: default initialization (empty DOM)
1956 // - 1 argument, XDocument: initialize with given DOM and empty base URL
1957 // NB: links in document must be absolute
1959 ::osl::MutexGuard
g(m_aMutex
);
1960 css::uno::Reference
<css::xml::dom::XDocument
> xDoc
;
1962 for (sal_Int32 i
= 0; i
< aArguments
.getLength(); ++i
) {
1963 const css::uno::Any any
= aArguments
[i
];
1964 if (!(any
>>= xDoc
)) {
1965 throw css::lang::IllegalArgumentException(
1966 "SfxDocumentMetaData::initialize: argument must be XDocument",
1967 *this, static_cast<sal_Int16
>(i
));
1970 throw css::lang::IllegalArgumentException(
1971 "SfxDocumentMetaData::initialize: argument is null",
1972 *this, static_cast<sal_Int16
>(i
));
1977 // For a new document, we create a new DOM tree here.
1984 // css::util::XCloneable:
1985 css::uno::Reference
<css::util::XCloneable
> SAL_CALL
1986 SfxDocumentMetaData::createClone()
1988 ::osl::MutexGuard
g(m_aMutex
);
1991 SfxDocumentMetaData
*pNew
= createMe(m_xContext
);
1993 // NB: do not copy the modification listeners, only DOM
1994 css::uno::Reference
<css::xml::dom::XDocument
> xDoc
= createDOM();
1996 updateUserDefinedAndAttributes();
1997 // deep copy of root node
1998 css::uno::Reference
<css::xml::dom::XNode
> xRoot(
1999 m_xDoc
->getDocumentElement(), css::uno::UNO_QUERY_THROW
);
2000 css::uno::Reference
<css::xml::dom::XNode
> xRootNew(
2001 xDoc
->importNode(xRoot
, true));
2002 xDoc
->appendChild(xRootNew
);
2004 } catch (const css::uno::RuntimeException
&) {
2006 } catch (const css::uno::Exception
&) {
2007 css::uno::Any anyEx
= cppu::getCaughtException();
2008 throw css::lang::WrappedTargetRuntimeException(
2009 "SfxDocumentMetaData::createClone: exception",
2010 css::uno::Reference
<css::uno::XInterface
>(*this), anyEx
);
2012 return css::uno::Reference
<css::util::XCloneable
> (pNew
);
2015 // css::util::XModifiable:
2016 sal_Bool SAL_CALL
SfxDocumentMetaData::isModified( )
2018 ::osl::MutexGuard
g(m_aMutex
);
2020 css::uno::Reference
<css::util::XModifiable
> xMB(m_xUserDefined
,
2021 css::uno::UNO_QUERY
);
2022 return m_isModified
|| (xMB
.is() && xMB
->isModified());
2025 void SAL_CALL
SfxDocumentMetaData::setModified( sal_Bool bModified
)
2027 css::uno::Reference
<css::util::XModifiable
> xMB
;
2028 { // do not lock mutex while notifying (#i93514#) to prevent deadlock
2029 ::osl::MutexGuard
g(m_aMutex
);
2031 m_isModified
= bModified
;
2032 if ( !bModified
&& m_xUserDefined
.is() )
2034 xMB
.set(m_xUserDefined
, css::uno::UNO_QUERY
);
2036 "SfxDocumentMetaData::setModified: PropertyBag not Modifiable?");
2041 css::uno::Reference
<css::uno::XInterface
> xThis(*this);
2042 css::lang::EventObject
event(xThis
);
2043 m_NotifyListeners
.notifyEach(&css::util::XModifyListener::modified
,
2045 } catch (const css::uno::RuntimeException
&) {
2047 } catch (const css::uno::Exception
&) {
2049 TOOLS_WARN_EXCEPTION("sfx.doc", "setModified");
2053 xMB
->setModified(false);
2058 // css::util::XModifyBroadcaster:
2059 void SAL_CALL
SfxDocumentMetaData::addModifyListener(
2060 const css::uno::Reference
< css::util::XModifyListener
> & xListener
)
2062 ::osl::MutexGuard
g(m_aMutex
);
2064 m_NotifyListeners
.addInterface(xListener
);
2065 css::uno::Reference
<css::util::XModifyBroadcaster
> xMB(m_xUserDefined
,
2066 css::uno::UNO_QUERY
);
2068 xMB
->addModifyListener(xListener
);
2072 void SAL_CALL
SfxDocumentMetaData::removeModifyListener(
2073 const css::uno::Reference
< css::util::XModifyListener
> & xListener
)
2075 ::osl::MutexGuard
g(m_aMutex
);
2077 m_NotifyListeners
.removeInterface(xListener
);
2078 css::uno::Reference
<css::util::XModifyBroadcaster
> xMB(m_xUserDefined
,
2079 css::uno::UNO_QUERY
);
2081 xMB
->removeModifyListener(xListener
);
2085 // css::xml::sax::XSAXSerializable
2086 void SAL_CALL
SfxDocumentMetaData::serialize(
2087 const css::uno::Reference
<css::xml::sax::XDocumentHandler
>& i_xHandler
,
2088 const css::uno::Sequence
< css::beans::StringPair
>& i_rNamespaces
)
2090 ::osl::MutexGuard
g(m_aMutex
);
2092 updateUserDefinedAndAttributes();
2093 css::uno::Reference
<css::xml::sax::XSAXSerializable
> xSAXable(m_xDoc
,
2094 css::uno::UNO_QUERY_THROW
);
2095 xSAXable
->serialize(i_xHandler
, i_rNamespaces
);
2098 void SfxDocumentMetaData::createUserDefined()
2100 // user-defined meta data: create PropertyBag which only accepts property
2101 // values of allowed types
2102 if ( m_xUserDefined
.is() )
2105 css::uno::Sequence
<css::uno::Type
> types(13);
2106 types
[ 0] = ::cppu::UnoType
<bool>::get();
2107 types
[ 1] = ::cppu::UnoType
< OUString
>::get();
2108 types
[ 2] = ::cppu::UnoType
<css::util::DateTime
>::get();
2109 types
[ 3] = ::cppu::UnoType
<css::util::Date
>::get();
2110 types
[ 4] = ::cppu::UnoType
<css::util::DateTimeWithTimezone
>::get();
2111 types
[ 5] = ::cppu::UnoType
<css::util::DateWithTimezone
>::get();
2112 types
[ 6] = ::cppu::UnoType
<css::util::Duration
>::get();
2113 types
[ 7] = ::cppu::UnoType
<float>::get();
2114 types
[ 8] = ::cppu::UnoType
<double>::get();
2115 types
[ 9] = ::cppu::UnoType
<sal_Int16
>::get();
2116 types
[10] = ::cppu::UnoType
<sal_Int32
>::get();
2117 types
[11] = ::cppu::UnoType
<sal_Int64
>::get();
2118 // Time is supported for backward compatibility with OOo 3.x, x<=2
2119 types
[12] = ::cppu::UnoType
<css::util::Time
>::get();
2120 // #i94175#: ODF allows empty user-defined property names!
2122 css::beans::PropertyBag::createWithTypes( m_xContext
, types
, true/*AllowEmptyPropertyName*/, false/*AutomaticAddition*/ ),
2123 css::uno::UNO_QUERY_THROW
);
2125 const css::uno::Reference
<css::util::XModifyBroadcaster
> xMB(
2126 m_xUserDefined
, css::uno::UNO_QUERY
);
2129 const std::vector
<css::uno::Reference
<css::uno::XInterface
> >
2130 listeners(m_NotifyListeners
.getElements());
2131 for (const auto& l
: listeners
) {
2132 xMB
->addModifyListener(
2133 css::uno::Reference
< css::util::XModifyListener
>(l
, css::uno::UNO_QUERY
) );
2138 } // closing anonymous implementation namespace
2140 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2141 CompatWriterDocPropsImpl_get_implementation(
2142 css::uno::XComponentContext
*context
,
2143 css::uno::Sequence
<css::uno::Any
> const &)
2145 return cppu::acquire(new CompatWriterDocPropsImpl(context
));
2148 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2149 SfxDocumentMetaData_get_implementation(
2150 css::uno::XComponentContext
*context
,
2151 css::uno::Sequence
<css::uno::Any
> const &)
2153 return cppu::acquire(new SfxDocumentMetaData(context
));
2156 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */