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/Writer.hpp>
50 #include <com/sun/star/xml/sax/Parser.hpp>
51 #include <com/sun/star/xml/sax/XFastParser.hpp>
52 #include <com/sun/star/xml/dom/DOMException.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/DocumentBuilder.hpp>
56 #include <com/sun/star/xml/dom/NodeType.hpp>
57 #include <com/sun/star/xml/xpath/XPathAPI.hpp>
58 #include <com/sun/star/util/Date.hpp>
59 #include <com/sun/star/util/Time.hpp>
60 #include <com/sun/star/util/DateWithTimezone.hpp>
61 #include <com/sun/star/util/DateTimeWithTimezone.hpp>
62 #include <com/sun/star/util/Duration.hpp>
64 #include <rtl/ustrbuf.hxx>
65 #include <tools/datetime.hxx>
66 #include <tools/diagnose_ex.h>
67 #include <osl/mutex.hxx>
68 #include <comphelper/fileformat.h>
69 #include <cppuhelper/basemutex.hxx>
70 #include <comphelper/interfacecontainer2.hxx>
71 #include <comphelper/storagehelper.hxx>
72 #include <unotools/mediadescriptor.hxx>
73 #include <comphelper/sequence.hxx>
74 #include <sot/storage.hxx>
75 #include <sfx2/docfile.hxx>
76 #include <sax/tools/converter.hxx>
77 #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 rtl::Reference
<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 rtl::Reference
<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 constexpr OUStringLiteral s_nsXLink
= u
"http://www.w3.org/1999/xlink";
409 constexpr OUStringLiteral s_nsDC
= u
"http://purl.org/dc/elements/1.1/";
410 constexpr OUStringLiteral s_nsODF
= u
"urn:oasis:names:tc:opendocument:xmlns:office:1.0";
411 constexpr OUStringLiteral s_nsODFMeta
= u
"urn:oasis:names:tc:opendocument:xmlns:meta:1.0";
412 // constexpr OUStringLiteral s_nsOOo = "http://openoffice.org/2004/office"; // not used (yet?)
414 constexpr OUStringLiteral s_meta
= u
"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
) noexcept
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
;
448 assert(!ns
.isEmpty());
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
) noexcept
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
) noexcept
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
) noexcept
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
) noexcept
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) noexcept
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
) noexcept
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
) noexcept
547 ::sax::Converter::convertDuration(buf
, i_rDur
);
548 return buf
.makeStringAndClear();
551 // convert duration to string
552 OUString
durationToText(sal_Int32 i_value
) noexcept
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 std::transform(vec
.begin(), vec
.end(), ret
.getArray(),
729 [](const auto& node
) { return getNodeText(node
); });
734 SfxDocumentMetaData::setMetaList(const char* i_name
,
735 const css::uno::Sequence
<OUString
> & i_rValue
,
736 AttrVector
const* i_pAttrs
)
737 // throw (css::uno::RuntimeException)
740 assert((i_pAttrs
== nullptr) ||
741 (static_cast<size_t>(i_rValue
.getLength()) == i_pAttrs
->size()));
744 OUString name
= OUString::createFromAscii(i_name
);
745 assert(m_metaList
.find(name
) != m_metaList
.end());
746 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> > & vec
=
749 // if nothing changed, do nothing
750 // alas, this does not check for permutations, or attributes...
751 if (nullptr == i_pAttrs
) {
752 if (static_cast<size_t>(i_rValue
.getLength()) == vec
.size()) {
754 for (sal_Int32 i
= 0; i
< i_rValue
.getLength(); ++i
) {
755 css::uno::Reference
<css::xml::dom::XNode
> xNode(vec
.at(i
));
757 OUString val
= getNodeText(xNode
);
758 if (val
!= i_rValue
[i
]) {
764 if (isEqual
) return false;
768 // remove old meta data nodes
770 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> >
771 ::reverse_iterator
it(vec
.rbegin());
773 for ( ;it
!= vec
.rend(); ++it
)
775 m_xParent
->removeChild(*it
);
780 // Clean up already removed nodes
781 vec
.erase(it
.base(), vec
.end());
787 // insert new meta data nodes into DOM tree
788 for (sal_Int32 i
= 0; i
< i_rValue
.getLength(); ++i
) {
789 css::uno::Reference
<css::xml::dom::XElement
> xElem(
790 m_xDoc
->createElementNS(getNameSpace(i_name
), name
),
791 css::uno::UNO_SET_THROW
);
792 css::uno::Reference
<css::xml::dom::XNode
> xNode(xElem
,
793 css::uno::UNO_QUERY_THROW
);
794 css::uno::Reference
<css::xml::dom::XNode
> xTextNode(
795 m_xDoc
->createTextNode(i_rValue
[i
]), css::uno::UNO_QUERY_THROW
);
797 if (i_pAttrs
!= nullptr) {
798 for (auto const& elem
: (*i_pAttrs
)[i
])
800 xElem
->setAttributeNS(getNameSpace(elem
.first
),
801 OUString::createFromAscii(elem
.first
),
805 xNode
->appendChild(xTextNode
);
806 m_xParent
->appendChild(xNode
);
807 vec
.push_back(xNode
);
811 } catch (const css::xml::dom::DOMException
&) {
812 css::uno::Any anyEx
= cppu::getCaughtException();
813 throw css::lang::WrappedTargetRuntimeException(
814 "SfxDocumentMetaData::setMetaList: DOM exception",
815 css::uno::Reference
<css::uno::XInterface
>(*this), anyEx
);
819 // convert property list to string list and attribute list
820 std::pair
<css::uno::Sequence
< OUString
>, AttrVector
>
821 propsToStrings(css::uno::Reference
<css::beans::XPropertySet
> const & i_xPropSet
)
823 ::std::vector
< OUString
> values
;
826 css::uno::Reference
<css::beans::XPropertySetInfo
> xSetInfo
827 = i_xPropSet
->getPropertySetInfo();
828 css::uno::Sequence
<css::beans::Property
> props
= xSetInfo
->getProperties();
830 for (sal_Int32 i
= 0; i
< props
.getLength(); ++i
) {
831 if (props
[i
].Attributes
& css::beans::PropertyAttribute::TRANSIENT
) {
834 const OUString name
= props
[i
].Name
;
837 any
= i_xPropSet
->getPropertyValue(name
);
838 } catch (const css::uno::Exception
&) {
841 const css::uno::Type
& type
= any
.getValueType();
842 std::vector
<std::pair
<const char*, OUString
> > as
;
843 as
.emplace_back("meta:name", name
);
844 const char* vt
= "meta:value-type";
846 // convert according to type
847 if (type
== ::cppu::UnoType
<bool>::get()) {
851 ::sax::Converter::convertBool(buf
, b
);
852 values
.push_back(buf
.makeStringAndClear());
853 as
.emplace_back(vt
, OUString("boolean"));
854 } else if (type
== ::cppu::UnoType
< OUString
>::get()) {
858 // #i90847# OOo 2.x does stupid things if value-type="string";
859 // fortunately string is default anyway, so we can just omit it
860 // #i107502#: however, OOo 2.x only reads 4 user-defined without @value-type
861 // => best backward compatibility: first 4 without @value-type, rest with
864 as
.emplace_back(vt
, OUString("string"));
866 } else if (type
== ::cppu::UnoType
<css::util::DateTime
>::get()) {
867 css::util::DateTime dt
;
869 values
.push_back(dateTimeToText(dt
));
870 as
.emplace_back(vt
, OUString("date"));
871 } else if (type
== ::cppu::UnoType
<css::util::Date
>::get()) {
874 values
.push_back(dateToText(d
, nullptr));
875 as
.emplace_back(vt
,OUString("date"));
876 } else if (type
== ::cppu::UnoType
<css::util::DateTimeWithTimezone
>::get()) {
877 css::util::DateTimeWithTimezone dttz
;
879 values
.push_back(dateTimeToText(dttz
.DateTimeInTZ
, &dttz
.Timezone
));
880 as
.emplace_back(vt
, OUString("date"));
881 } else if (type
== ::cppu::UnoType
<css::util::DateWithTimezone
>::get()) {
882 css::util::DateWithTimezone dtz
;
884 values
.push_back(dateToText(dtz
.DateInTZ
, &dtz
.Timezone
));
885 as
.emplace_back(vt
, OUString("date"));
886 } else if (type
== ::cppu::UnoType
<css::util::Time
>::get()) {
887 // #i97029#: replaced by Duration
888 // Time is supported for backward compatibility with OOo 3.x, x<=2
891 css::util::Duration ud
;
893 ud
.Minutes
= ut
.Minutes
;
894 ud
.Seconds
= ut
.Seconds
;
895 ud
.NanoSeconds
= ut
.NanoSeconds
;
896 values
.push_back(durationToText(ud
));
897 as
.emplace_back(vt
, OUString("time"));
898 } else if (type
== ::cppu::UnoType
<css::util::Duration
>::get()) {
899 css::util::Duration ud
;
901 values
.push_back(durationToText(ud
));
902 as
.emplace_back(vt
, OUString("time"));
903 } else if (::cppu::UnoType
<double>::get().isAssignableFrom(type
)) {
904 // support not just double, but anything that can be converted
908 ::sax::Converter::convertDouble(buf
, d
);
909 values
.push_back(buf
.makeStringAndClear());
910 as
.emplace_back(vt
, OUString("float"));
912 SAL_WARN("sfx.doc", "Unsupported property type: " << any
.getValueTypeName() );
918 return std::make_pair(comphelper::containerToSequence(values
), attrs
);
921 // remove the given element from the DOM, and iff i_pAttrs != 0 insert new one
923 SfxDocumentMetaData::updateElement(const char *i_name
,
924 std::vector
<std::pair
<const char *, OUString
> >* i_pAttrs
)
926 OUString name
= OUString::createFromAscii(i_name
);
928 // remove old element
929 css::uno::Reference
<css::xml::dom::XNode
> xNode
=
930 m_meta
.find(name
)->second
;
932 m_xParent
->removeChild(xNode
);
936 if (nullptr != i_pAttrs
) {
937 css::uno::Reference
<css::xml::dom::XElement
> xElem(
938 m_xDoc
->createElementNS(getNameSpace(i_name
), name
),
939 css::uno::UNO_SET_THROW
);
940 xNode
.set(xElem
, css::uno::UNO_QUERY_THROW
);
942 for (auto const& elem
: *i_pAttrs
)
944 xElem
->setAttributeNS(getNameSpace(elem
.first
),
945 OUString::createFromAscii(elem
.first
), elem
.second
);
947 m_xParent
->appendChild(xNode
);
949 m_meta
[name
] = xNode
;
950 } catch (const css::xml::dom::DOMException
&) {
951 css::uno::Any anyEx
= cppu::getCaughtException();
952 throw css::lang::WrappedTargetRuntimeException(
953 "SfxDocumentMetaData::updateElement: DOM exception",
954 css::uno::Reference
<css::uno::XInterface
>(*this), anyEx
);
958 // update user-defined meta data in DOM tree
959 void SfxDocumentMetaData::updateUserDefinedAndAttributes()
962 const css::uno::Reference
<css::beans::XPropertySet
> xPSet(m_xUserDefined
,
963 css::uno::UNO_QUERY_THROW
);
964 const std::pair
<css::uno::Sequence
< OUString
>, AttrVector
>
965 udStringsAttrs( propsToStrings(xPSet
) );
966 (void) setMetaList("meta:user-defined", udStringsAttrs
.first
,
967 &udStringsAttrs
.second
);
969 // update elements with attributes
970 std::vector
<std::pair
<const char *, OUString
> > attributes
;
971 if (!m_TemplateName
.isEmpty() || !m_TemplateURL
.isEmpty()
972 || isValidDateTime(m_TemplateDate
)) {
973 attributes
.emplace_back("xlink:type", OUString("simple"));
974 attributes
.emplace_back("xlink:actuate", OUString("onRequest"));
975 attributes
.emplace_back("xlink:title", m_TemplateName
);
976 attributes
.emplace_back("xlink:href", m_TemplateURL
);
977 if (isValidDateTime(m_TemplateDate
)) {
978 attributes
.emplace_back(
979 "meta:date", dateTimeToText(m_TemplateDate
));
981 updateElement("meta:template", &attributes
);
983 updateElement("meta:template");
987 if (!m_AutoloadURL
.isEmpty() || (0 != m_AutoloadSecs
)) {
988 attributes
.emplace_back("xlink:href", m_AutoloadURL
);
989 attributes
.emplace_back("meta:delay",
990 durationToText(m_AutoloadSecs
));
991 updateElement("meta:auto-reload", &attributes
);
993 updateElement("meta:auto-reload");
997 if (!m_DefaultTarget
.isEmpty()) {
998 attributes
.emplace_back(
999 "office:target-frame-name",
1001 // xlink:show: _blank -> new, any other value -> replace
1002 const char* show
= m_DefaultTarget
== "_blank" ? "new" : "replace";
1003 attributes
.emplace_back(
1005 OUString::createFromAscii(show
));
1006 updateElement("meta:hyperlink-behaviour", &attributes
);
1008 updateElement("meta:hyperlink-behaviour");
1013 // create empty DOM tree (XDocument)
1014 css::uno::Reference
<css::xml::dom::XDocument
>
1015 SfxDocumentMetaData::createDOM() const // throw (css::uno::RuntimeException)
1017 css::uno::Reference
<css::xml::dom::XDocumentBuilder
> xBuilder( css::xml::dom::DocumentBuilder::create(m_xContext
) );
1018 css::uno::Reference
<css::xml::dom::XDocument
> xDoc
= xBuilder
->newDocument();
1020 throw css::uno::RuntimeException(
1021 "SfxDocumentMetaData::createDOM: cannot create new document",
1022 *const_cast<SfxDocumentMetaData
*>(this));
1027 SfxDocumentMetaData::checkInit() const // throw (css::uno::RuntimeException)
1029 if (!m_isInitialized
) {
1030 throw css::uno::RuntimeException(
1031 "SfxDocumentMetaData::checkInit: not initialized",
1032 *const_cast<SfxDocumentMetaData
*>(this));
1034 assert(m_xDoc
.is() && m_xParent
.is());
1037 // initialize state from DOM tree
1038 void SfxDocumentMetaData::init(
1039 const css::uno::Reference
<css::xml::dom::XDocument
>& i_xDoc
)
1042 throw css::uno::RuntimeException("SfxDocumentMetaData::init: no DOM tree given", *this);
1044 css::uno::Reference
<css::xml::xpath::XXPathAPI
> xPath
= css::xml::xpath::XPathAPI::create(m_xContext
);
1046 m_isInitialized
= false;
1049 // select nodes for standard meta data stuff
1050 xPath
->registerNS("xlink", s_nsXLink
);
1051 xPath
->registerNS("dc", s_nsDC
);
1052 xPath
->registerNS("office", s_nsODF
);
1053 xPath
->registerNS("meta", s_nsODFMeta
);
1054 // NB: we do not handle the single-XML-file ODF variant, which would
1055 // have the root element office:document.
1056 // The root of such documents must be converted in the importer!
1057 css::uno::Reference
<css::xml::dom::XNode
> xDocNode(
1058 m_xDoc
, css::uno::UNO_QUERY_THROW
);
1061 m_xParent
= xPath
->selectSingleNode(xDocNode
, "/child::office:document-meta/child::office:meta");
1062 } catch (const css::uno::Exception
&) {
1065 if (!m_xParent
.is()) {
1066 // all this create/append stuff may throw DOMException
1068 css::uno::Reference
<css::xml::dom::XElement
> xRElem
;
1069 css::uno::Reference
<css::xml::dom::XNode
> xNode(
1070 i_xDoc
->getFirstChild());
1071 while (xNode
.is()) {
1072 if (css::xml::dom::NodeType_ELEMENT_NODE
==xNode
->getNodeType())
1074 if ( xNode
->getNamespaceURI() == s_nsODF
&& xNode
->getLocalName() == "document-meta" )
1076 xRElem
.set(xNode
, css::uno::UNO_QUERY_THROW
);
1081 SAL_INFO("sfx.doc", "SfxDocumentMetaData::init(): "
1082 "deleting unexpected root element: "
1083 << xNode
->getLocalName());
1084 i_xDoc
->removeChild(xNode
);
1085 xNode
= i_xDoc
->getFirstChild(); // start over
1088 xNode
= xNode
->getNextSibling();
1092 xRElem
= i_xDoc
->createElementNS(
1093 s_nsODF
, "office:document-meta");
1094 css::uno::Reference
<css::xml::dom::XNode
> xRNode(xRElem
,
1095 css::uno::UNO_QUERY_THROW
);
1096 i_xDoc
->appendChild(xRNode
);
1098 xRElem
->setAttributeNS(s_nsODF
, "office:version", "1.0");
1099 // does not exist, otherwise m_xParent would not be null
1100 css::uno::Reference
<css::xml::dom::XNode
> xParent (
1101 i_xDoc
->createElementNS(s_nsODF
, "office:meta"),
1102 css::uno::UNO_QUERY_THROW
);
1103 xRElem
->appendChild(xParent
);
1104 m_xParent
= xParent
;
1105 } catch (const css::xml::dom::DOMException
&) {
1106 css::uno::Any anyEx
= cppu::getCaughtException();
1107 throw css::lang::WrappedTargetRuntimeException(
1108 "SfxDocumentMetaData::init: DOM exception",
1109 css::uno::Reference
<css::uno::XInterface
>(*this), anyEx
);
1114 // select nodes for elements of which we only handle one occurrence
1115 for (const char **pName
= s_stdMeta
; *pName
!= nullptr; ++pName
) {
1116 OUString name
= OUString::createFromAscii(*pName
);
1117 // NB: If a document contains more than one occurrence of a
1118 // meta-data element, we arbitrarily pick one of them here.
1119 // We do not remove the others, i.e., when we write the
1120 // document, it will contain the duplicates unchanged.
1121 // The ODF spec says that handling multiple occurrences is
1122 // application-specific.
1123 css::uno::Reference
<css::xml::dom::XNode
> xNode
=
1124 xPath
->selectSingleNode(m_xParent
, "child::" + name
);
1125 // Do not create an empty element if it is missing;
1126 // for certain elements, such as dateTime, this would be invalid
1127 m_meta
[name
] = xNode
;
1130 // select nodes for elements of which we handle all occurrences
1131 for (const char **pName
= s_stdMetaList
; *pName
!= nullptr; ++pName
) {
1132 OUString name
= OUString::createFromAscii(*pName
);
1133 css::uno::Reference
<css::xml::dom::XNodeList
> nodes
=
1134 xPath
->selectNodeList(m_xParent
, "child::" + name
);
1135 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> > v
;
1136 v
.reserve(nodes
->getLength());
1137 for (sal_Int32 i
= 0; i
< nodes
->getLength(); ++i
)
1139 v
.push_back(nodes
->item(i
));
1141 m_metaList
[name
] = v
;
1144 // initialize members corresponding to attributes from DOM nodes
1145 m_TemplateName
= getMetaAttr("meta:template", "xlink:title");
1146 m_TemplateURL
= getMetaAttr("meta:template", "xlink:href");
1148 textToDateTimeDefault(getMetaAttr("meta:template", "meta:date"));
1149 m_AutoloadURL
= getMetaAttr("meta:auto-reload", "xlink:href");
1151 textToDuration(getMetaAttr("meta:auto-reload", "meta:delay"));
1153 getMetaAttr("meta:hyperlink-behaviour", "office:target-frame-name");
1156 std::vector
<css::uno::Reference
<css::xml::dom::XNode
> > & vec
=
1157 m_metaList
[OUString("meta:user-defined")];
1158 m_xUserDefined
.clear(); // #i105826#: reset (may be re-initialization)
1161 createUserDefined();
1164 // user-defined meta data: initialize PropertySet from DOM nodes
1165 for (auto const& elem
: vec
)
1167 css::uno::Reference
<css::xml::dom::XElement
> xElem(elem
,
1168 css::uno::UNO_QUERY_THROW
);
1170 OUString name
= xElem
->getAttributeNS(s_nsODFMeta
, "name");
1171 OUString type
= xElem
->getAttributeNS(s_nsODFMeta
, "value-type");
1172 OUString text
= getNodeText(elem
);
1173 if ( type
== "float" ) {
1175 if (::sax::Converter::convertDouble(d
, text
)) {
1178 SAL_WARN("sfx.doc", "Invalid float: " << text
);
1181 } else if ( type
== "date" ) {
1184 css::util::DateTime dt
;
1185 std::optional
<sal_Int16
> nTimeZone
;
1186 if (textToDateOrDateTime(d
, dt
, isDateTime
, nTimeZone
, text
)) {
1189 any
<<= css::util::DateTimeWithTimezone(dt
,
1196 any
<<= css::util::DateWithTimezone(d
, *nTimeZone
);
1202 SAL_WARN("sfx.doc", "Invalid date: " << text
);
1205 } else if ( type
== "time" ) {
1206 css::util::Duration ud
;
1207 if (textToDuration(ud
, text
)) {
1210 SAL_WARN("sfx.doc", "Invalid time: " << text
);
1213 } else if ( type
== "boolean" ) {
1215 if (::sax::Converter::convertBool(b
, text
)) {
1218 SAL_WARN("sfx.doc", "Invalid boolean: " << text
);
1225 m_xUserDefined
->addProperty(name
,
1226 css::beans::PropertyAttribute::REMOVABLE
, any
);
1227 } catch (const css::beans::PropertyExistException
&) {
1228 SAL_WARN("sfx.doc", "Duplicate: " << name
);
1229 // ignore; duplicate
1230 } catch (const css::beans::IllegalTypeException
&) {
1231 SAL_INFO("sfx.doc", "SfxDocumentMetaData: illegal type: " << name
);
1232 } catch (const css::lang::IllegalArgumentException
&) {
1233 SAL_INFO("sfx.doc", "SfxDocumentMetaData: illegal arg: " << name
);
1237 m_isModified
= false;
1238 m_isInitialized
= true;
1242 SfxDocumentMetaData::SfxDocumentMetaData(
1243 css::uno::Reference
< css::uno::XComponentContext
> const & context
)
1245 , SfxDocumentMetaData_Base(m_aMutex
)
1246 , m_xContext(context
)
1247 , m_NotifyListeners(m_aMutex
)
1248 , m_isInitialized(false)
1249 , m_isModified(false)
1252 assert(context
.is());
1253 assert(context
->getServiceManager().is());
1257 // com.sun.star.uno.XServiceInfo:
1259 SfxDocumentMetaData::getImplementationName()
1261 return "SfxDocumentMetaData";
1265 SfxDocumentMetaData::supportsService(OUString
const & serviceName
)
1267 return cppu::supportsService(this, serviceName
);
1270 css::uno::Sequence
< OUString
> SAL_CALL
1271 SfxDocumentMetaData::getSupportedServiceNames()
1273 css::uno::Sequence
< OUString
> s
{ "com.sun.star.document.DocumentProperties" };
1278 // css::lang::XComponent:
1279 void SAL_CALL
SfxDocumentMetaData::dispose()
1281 ::osl::MutexGuard
g(m_aMutex
);
1282 if (!m_isInitialized
) {
1285 WeakComponentImplHelperBase::dispose(); // superclass
1286 m_NotifyListeners
.disposeAndClear(css::lang::EventObject(
1287 static_cast< ::cppu::OWeakObject
* >(this)));
1288 m_isInitialized
= false;
1293 m_xUserDefined
.clear();
1297 // css::document::XDocumentProperties:
1299 SfxDocumentMetaData::getAuthor()
1301 ::osl::MutexGuard
g(m_aMutex
);
1302 return getMetaText("meta:initial-creator");
1305 void SAL_CALL
SfxDocumentMetaData::setAuthor(const OUString
& the_value
)
1307 setMetaTextAndNotify("meta:initial-creator", the_value
);
1312 SfxDocumentMetaData::getGenerator()
1314 ::osl::MutexGuard
g(m_aMutex
);
1315 return getMetaText("meta:generator");
1319 SfxDocumentMetaData::setGenerator(const OUString
& the_value
)
1321 setMetaTextAndNotify("meta:generator", the_value
);
1324 css::util::DateTime SAL_CALL
1325 SfxDocumentMetaData::getCreationDate()
1327 ::osl::MutexGuard
g(m_aMutex
);
1328 return textToDateTimeDefault(getMetaText("meta:creation-date"));
1332 SfxDocumentMetaData::setCreationDate(const css::util::DateTime
& the_value
)
1334 setMetaTextAndNotify("meta:creation-date", dateTimeToText(the_value
));
1338 SfxDocumentMetaData::getTitle()
1340 ::osl::MutexGuard
g(m_aMutex
);
1341 return getMetaText("dc:title");
1344 void SAL_CALL
SfxDocumentMetaData::setTitle(const OUString
& the_value
)
1346 setMetaTextAndNotify("dc:title", the_value
);
1350 SfxDocumentMetaData::getSubject()
1352 ::osl::MutexGuard
g(m_aMutex
);
1353 return getMetaText("dc:subject");
1357 SfxDocumentMetaData::setSubject(const OUString
& the_value
)
1359 setMetaTextAndNotify("dc:subject", the_value
);
1363 SfxDocumentMetaData::getDescription()
1365 ::osl::MutexGuard
g(m_aMutex
);
1366 return getMetaText("dc:description");
1370 SfxDocumentMetaData::setDescription(const OUString
& the_value
)
1372 setMetaTextAndNotify("dc:description", the_value
);
1375 css::uno::Sequence
< OUString
>
1376 SAL_CALL
SfxDocumentMetaData::getKeywords()
1378 ::osl::MutexGuard
g(m_aMutex
);
1379 return getMetaList("meta:keyword");
1383 SfxDocumentMetaData::setKeywords(
1384 const css::uno::Sequence
< OUString
> & the_value
)
1386 ::osl::ClearableMutexGuard
g(m_aMutex
);
1387 if (setMetaList("meta:keyword", the_value
, nullptr)) {
1393 css::lang::Locale SAL_CALL
1394 SfxDocumentMetaData::getLanguage()
1396 ::osl::MutexGuard
g(m_aMutex
);
1397 css::lang::Locale
loc( LanguageTag::convertToLocale( getMetaText("dc:language"), false));
1402 SfxDocumentMetaData::setLanguage(const css::lang::Locale
& the_value
)
1404 OUString
text( LanguageTag::convertToBcp47( the_value
, false));
1405 setMetaTextAndNotify("dc:language", text
);
1409 SfxDocumentMetaData::getModifiedBy()
1411 ::osl::MutexGuard
g(m_aMutex
);
1412 return getMetaText("dc:creator");
1416 SfxDocumentMetaData::setModifiedBy(const OUString
& the_value
)
1418 setMetaTextAndNotify("dc:creator", the_value
);
1421 css::util::DateTime SAL_CALL
1422 SfxDocumentMetaData::getModificationDate()
1424 ::osl::MutexGuard
g(m_aMutex
);
1425 return textToDateTimeDefault(getMetaText("dc:date"));
1429 SfxDocumentMetaData::setModificationDate(const css::util::DateTime
& the_value
)
1431 setMetaTextAndNotify("dc:date", dateTimeToText(the_value
));
1435 SfxDocumentMetaData::getPrintedBy()
1437 ::osl::MutexGuard
g(m_aMutex
);
1438 return getMetaText("meta:printed-by");
1442 SfxDocumentMetaData::setPrintedBy(const OUString
& the_value
)
1444 setMetaTextAndNotify("meta:printed-by", the_value
);
1447 css::util::DateTime SAL_CALL
1448 SfxDocumentMetaData::getPrintDate()
1450 ::osl::MutexGuard
g(m_aMutex
);
1451 return textToDateTimeDefault(getMetaText("meta:print-date"));
1455 SfxDocumentMetaData::setPrintDate(const css::util::DateTime
& the_value
)
1457 setMetaTextAndNotify("meta:print-date", dateTimeToText(the_value
));
1461 SfxDocumentMetaData::getTemplateName()
1463 ::osl::MutexGuard
g(m_aMutex
);
1465 return m_TemplateName
;
1469 SfxDocumentMetaData::setTemplateName(const OUString
& the_value
)
1471 ::osl::ClearableMutexGuard
g(m_aMutex
);
1473 if (m_TemplateName
!= the_value
) {
1474 m_TemplateName
= the_value
;
1481 SfxDocumentMetaData::getTemplateURL()
1483 ::osl::MutexGuard
g(m_aMutex
);
1485 return m_TemplateURL
;
1489 SfxDocumentMetaData::setTemplateURL(const OUString
& the_value
)
1491 ::osl::ClearableMutexGuard
g(m_aMutex
);
1493 if (m_TemplateURL
!= the_value
) {
1494 m_TemplateURL
= the_value
;
1500 css::util::DateTime SAL_CALL
1501 SfxDocumentMetaData::getTemplateDate()
1503 ::osl::MutexGuard
g(m_aMutex
);
1505 return m_TemplateDate
;
1509 SfxDocumentMetaData::setTemplateDate(const css::util::DateTime
& the_value
)
1511 ::osl::ClearableMutexGuard
g(m_aMutex
);
1513 if (m_TemplateDate
!= the_value
) {
1514 m_TemplateDate
= the_value
;
1521 SfxDocumentMetaData::getAutoloadURL()
1523 ::osl::MutexGuard
g(m_aMutex
);
1525 return m_AutoloadURL
;
1529 SfxDocumentMetaData::setAutoloadURL(const OUString
& the_value
)
1531 ::osl::ClearableMutexGuard
g(m_aMutex
);
1533 if (m_AutoloadURL
!= the_value
) {
1534 m_AutoloadURL
= the_value
;
1540 ::sal_Int32 SAL_CALL
1541 SfxDocumentMetaData::getAutoloadSecs()
1543 ::osl::MutexGuard
g(m_aMutex
);
1545 return m_AutoloadSecs
;
1549 SfxDocumentMetaData::setAutoloadSecs(::sal_Int32 the_value
)
1552 throw css::lang::IllegalArgumentException(
1553 "SfxDocumentMetaData::setAutoloadSecs: argument is negative",
1555 ::osl::ClearableMutexGuard
g(m_aMutex
);
1557 if (m_AutoloadSecs
!= the_value
) {
1558 m_AutoloadSecs
= the_value
;
1565 SfxDocumentMetaData::getDefaultTarget()
1567 ::osl::MutexGuard
g(m_aMutex
);
1569 return m_DefaultTarget
;
1573 SfxDocumentMetaData::setDefaultTarget(const OUString
& the_value
)
1575 ::osl::ClearableMutexGuard
g(m_aMutex
);
1577 if (m_DefaultTarget
!= the_value
) {
1578 m_DefaultTarget
= the_value
;
1584 css::uno::Sequence
< css::beans::NamedValue
> SAL_CALL
1585 SfxDocumentMetaData::getDocumentStatistics()
1587 ::osl::MutexGuard
g(m_aMutex
);
1589 ::std::vector
<css::beans::NamedValue
> stats
;
1590 for (size_t i
= 0; s_stdStats
[i
] != nullptr; ++i
) {
1591 const char * aName
= s_stdStatAttrs
[i
];
1592 OUString text
= getMetaAttr("meta:document-statistic", aName
);
1593 if (text
.isEmpty()) continue;
1594 css::beans::NamedValue stat
;
1595 stat
.Name
= OUString::createFromAscii(s_stdStats
[i
]);
1598 if (!::sax::Converter::convertNumber(val
, text
, 0) || (val
< 0)) {
1600 SAL_WARN("sfx.doc", "Invalid number: " << text
);
1604 stats
.push_back(stat
);
1607 return ::comphelper::containerToSequence(stats
);
1611 SfxDocumentMetaData::setDocumentStatistics(
1612 const css::uno::Sequence
< css::beans::NamedValue
> & the_value
)
1615 osl::MutexGuard
g(m_aMutex
);
1617 std::vector
<std::pair
<const char *, OUString
> > attributes
;
1618 for (const auto& rValue
: the_value
) {
1619 const OUString name
= rValue
.Name
;
1620 // inefficiently search for matching attribute
1621 for (size_t j
= 0; s_stdStats
[j
] != nullptr; ++j
) {
1622 if (name
.equalsAscii(s_stdStats
[j
])) {
1623 const css::uno::Any any
= rValue
.Value
;
1626 attributes
.emplace_back(s_stdStatAttrs
[j
],
1627 OUString::number(val
));
1630 SAL_WARN("sfx.doc", "Invalid statistic: " << name
);
1636 updateElement("meta:document-statistic", &attributes
);
1641 ::sal_Int16 SAL_CALL
1642 SfxDocumentMetaData::getEditingCycles()
1644 ::osl::MutexGuard
g(m_aMutex
);
1645 OUString text
= getMetaText("meta:editing-cycles");
1647 if (::sax::Converter::convertNumber(ret
, text
,
1648 0, std::numeric_limits
<sal_Int16
>::max())) {
1649 return static_cast<sal_Int16
>(ret
);
1656 SfxDocumentMetaData::setEditingCycles(::sal_Int16 the_value
)
1659 throw css::lang::IllegalArgumentException(
1660 "SfxDocumentMetaData::setEditingCycles: argument is negative",
1662 setMetaTextAndNotify("meta:editing-cycles", OUString::number(the_value
));
1665 ::sal_Int32 SAL_CALL
1666 SfxDocumentMetaData::getEditingDuration()
1668 ::osl::MutexGuard
g(m_aMutex
);
1669 return textToDuration(getMetaText("meta:editing-duration"));
1673 SfxDocumentMetaData::setEditingDuration(::sal_Int32 the_value
)
1676 throw css::lang::IllegalArgumentException(
1677 "SfxDocumentMetaData::setEditingDuration: argument is negative",
1679 setMetaTextAndNotify("meta:editing-duration", durationToText(the_value
));
1683 SfxDocumentMetaData::resetUserData(const OUString
& the_value
)
1685 ::osl::ClearableMutexGuard
g(m_aMutex
);
1687 bool bModified( false );
1688 bModified
|= setMetaText("meta:initial-creator", the_value
);
1689 ::DateTime
now( ::DateTime::SYSTEM
);
1690 css::util::DateTime
uDT(now
.GetUNODateTime());
1691 bModified
|= setMetaText("meta:creation-date", dateTimeToText(uDT
));
1692 bModified
|= setMetaText("dc:creator", OUString());
1693 bModified
|= setMetaText("meta:printed-by", OUString());
1694 bModified
|= setMetaText("dc:date", dateTimeToText(css::util::DateTime()));
1695 bModified
|= setMetaText("meta:print-date",
1696 dateTimeToText(css::util::DateTime()));
1697 bModified
|= setMetaText("meta:editing-duration", durationToText(0));
1698 bModified
|= setMetaText("meta:editing-cycles",
1708 css::uno::Reference
< css::beans::XPropertyContainer
> SAL_CALL
1709 SfxDocumentMetaData::getUserDefinedProperties()
1711 ::osl::MutexGuard
g(m_aMutex
);
1713 createUserDefined();
1714 return m_xUserDefined
;
1719 SfxDocumentMetaData::loadFromStorage(
1720 const css::uno::Reference
< css::embed::XStorage
> & xStorage
,
1721 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
)
1724 throw css::lang::IllegalArgumentException("SfxDocumentMetaData::loadFromStorage: argument is null", *this, 0);
1725 ::osl::MutexGuard
g(m_aMutex
);
1727 // open meta data file
1728 css::uno::Reference
<css::io::XStream
> xStream(
1729 xStorage
->openStreamElement(
1731 css::embed::ElementModes::READ
) );
1732 if (!xStream
.is()) throw css::uno::RuntimeException();
1733 css::uno::Reference
<css::io::XInputStream
> xInStream
=
1734 xStream
->getInputStream();
1735 if (!xInStream
.is()) throw css::uno::RuntimeException();
1737 // create DOM parser service
1738 css::uno::Reference
<css::lang::XMultiComponentFactory
> xMsf (
1739 m_xContext
->getServiceManager());
1740 css::xml::sax::InputSource input
;
1741 input
.aInputStream
= xInStream
;
1743 sal_uInt64 version
= SotStorage::GetVersion( xStorage
);
1744 // Oasis is also the default (0)
1745 bool bOasis
= ( version
> SOFFICE_FILEFORMAT_60
|| version
== 0 );
1746 const char *pServiceName
= bOasis
1747 ? "com.sun.star.document.XMLOasisMetaImporter"
1748 : "com.sun.star.document.XMLMetaImporter";
1751 css::uno::Reference
<css::beans::XPropertySet
> xPropArg
=
1752 getURLProperties(Medium
);
1754 xPropArg
->getPropertyValue("BaseURI")
1755 >>= input
.sSystemId
;
1756 input
.sSystemId
+= OUString::Concat("/") + s_meta
;
1757 } catch (const css::uno::Exception
&) {
1758 input
.sSystemId
= s_meta
;
1760 css::uno::Sequence
< css::uno::Any
> args
{ css::uno::Any(xPropArg
) };
1762 // the underlying SvXMLImport implements XFastParser, XImporter, XFastDocumentHandler
1763 css::uno::Reference
<XInterface
> xFilter
=
1764 xMsf
->createInstanceWithArgumentsAndContext(
1765 OUString::createFromAscii(pServiceName
), args
, m_xContext
);
1767 css::uno::Reference
<css::xml::sax::XFastParser
> xFastParser(xFilter
, css::uno::UNO_QUERY
);
1768 css::uno::Reference
<css::document::XImporter
> xImp(xFilter
, css::uno::UNO_QUERY_THROW
);
1769 xImp
->setTargetDocument(css::uno::Reference
<css::lang::XComponent
>(this));
1772 xFastParser
->parseStream(input
);
1775 css::uno::Reference
<css::xml::sax::XDocumentHandler
> xDocHandler(xFilter
, css::uno::UNO_QUERY_THROW
);
1776 css::uno::Reference
<css::xml::sax::XParser
> xParser
= css::xml::sax::Parser::create(m_xContext
);
1777 xParser
->setDocumentHandler(xDocHandler
);
1778 xParser
->parseStream(input
);
1780 } catch (const css::xml::sax::SAXException
&) {
1781 throw css::io::WrongFormatException(
1782 "SfxDocumentMetaData::loadFromStorage:"
1783 " XML parsing exception", *this);
1785 // NB: the implementation of XMLOasisMetaImporter calls initialize
1790 SfxDocumentMetaData::storeToStorage(
1791 const css::uno::Reference
< css::embed::XStorage
> & xStorage
,
1792 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
)
1795 throw css::lang::IllegalArgumentException(
1796 "SfxDocumentMetaData::storeToStorage: argument is null", *this, 0);
1797 ::osl::MutexGuard
g(m_aMutex
);
1800 // update user-defined meta data in DOM tree
1801 // updateUserDefinedAndAttributes(); // this will be done in serialize!
1803 // write into storage
1804 css::uno::Reference
<css::io::XStream
> xStream
=
1805 xStorage
->openStreamElement(s_meta
,
1806 css::embed::ElementModes::WRITE
1807 | css::embed::ElementModes::TRUNCATE
);
1808 if (!xStream
.is()) throw css::uno::RuntimeException();
1809 css::uno::Reference
< css::beans::XPropertySet
> xStreamProps(xStream
,
1810 css::uno::UNO_QUERY_THROW
);
1811 xStreamProps
->setPropertyValue(
1813 css::uno::makeAny(OUString("text/xml")));
1814 xStreamProps
->setPropertyValue(
1816 css::uno::makeAny(false));
1817 xStreamProps
->setPropertyValue(
1818 "UseCommonStoragePasswordEncryption",
1819 css::uno::makeAny(false));
1820 css::uno::Reference
<css::io::XOutputStream
> xOutStream
=
1821 xStream
->getOutputStream();
1822 if (!xOutStream
.is()) throw css::uno::RuntimeException();
1823 css::uno::Reference
<css::lang::XMultiComponentFactory
> xMsf (
1824 m_xContext
->getServiceManager());
1825 css::uno::Reference
<css::xml::sax::XWriter
> xSaxWriter(
1826 css::xml::sax::Writer::create(m_xContext
));
1827 xSaxWriter
->setOutputStream(xOutStream
);
1829 const sal_uInt64 version
= SotStorage::GetVersion( xStorage
);
1830 // Oasis is also the default (0)
1831 const bool bOasis
= ( version
> SOFFICE_FILEFORMAT_60
|| version
== 0 );
1832 const char *pServiceName
= bOasis
1833 ? "com.sun.star.document.XMLOasisMetaExporter"
1834 : "com.sun.star.document.XMLMetaExporter";
1837 css::uno::Reference
<css::beans::XPropertySet
> xPropArg
=
1838 getURLProperties(Medium
);
1839 css::uno::Sequence
< css::uno::Any
> args
{ css::uno::Any(xSaxWriter
), css::uno::Any(xPropArg
) };
1841 css::uno::Reference
<css::document::XExporter
> xExp(
1842 xMsf
->createInstanceWithArgumentsAndContext(
1843 OUString::createFromAscii(pServiceName
), args
, m_xContext
),
1844 css::uno::UNO_QUERY_THROW
);
1845 xExp
->setSourceDocument(css::uno::Reference
<css::lang::XComponent
>(this));
1846 css::uno::Reference
<css::document::XFilter
> xFilter(xExp
,
1847 css::uno::UNO_QUERY_THROW
);
1848 if (!xFilter
->filter(css::uno::Sequence
< css::beans::PropertyValue
>())) {
1849 throw css::io::IOException(
1850 "SfxDocumentMetaData::storeToStorage: cannot filter", *this);
1852 css::uno::Reference
<css::embed::XTransactedObject
> xTransaction(
1853 xStorage
, css::uno::UNO_QUERY
);
1854 if (xTransaction
.is()) {
1855 xTransaction
->commit();
1860 SfxDocumentMetaData::loadFromMedium(const OUString
& URL
,
1861 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
)
1863 css::uno::Reference
<css::io::XInputStream
> xIn
;
1864 utl::MediaDescriptor
md(Medium
);
1865 // if we have a URL parameter, it replaces the one in the media descriptor
1866 if (!URL
.isEmpty()) {
1867 md
[ utl::MediaDescriptor::PROP_URL
] <<= URL
;
1868 md
[ utl::MediaDescriptor::PROP_READONLY
] <<= true;
1870 if (md
.addInputStream()) {
1871 md
[ utl::MediaDescriptor::PROP_INPUTSTREAM
] >>= xIn
;
1873 css::uno::Reference
<css::embed::XStorage
> xStorage
;
1876 xStorage
= ::comphelper::OStorageHelper::GetStorageFromInputStream(
1878 } else { // fallback to url parameter
1879 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL(
1880 URL
, css::embed::ElementModes::READ
, m_xContext
);
1882 } catch (const css::uno::RuntimeException
&) {
1884 } catch (const css::io::IOException
&) {
1886 } catch (const css::uno::Exception
&) {
1887 css::uno::Any anyEx
= cppu::getCaughtException();
1888 throw css::lang::WrappedTargetException(
1889 "SfxDocumentMetaData::loadFromMedium: exception",
1890 css::uno::Reference
<css::uno::XInterface
>(*this),
1893 if (!xStorage
.is()) {
1894 throw css::uno::RuntimeException(
1895 "SfxDocumentMetaData::loadFromMedium: cannot get Storage",
1898 loadFromStorage(xStorage
, md
.getAsConstPropertyValueList());
1902 SfxDocumentMetaData::storeToMedium(const OUString
& URL
,
1903 const css::uno::Sequence
< css::beans::PropertyValue
> & Medium
)
1905 utl::MediaDescriptor
md(Medium
);
1906 if (!URL
.isEmpty()) {
1907 md
[ utl::MediaDescriptor::PROP_URL
] <<= URL
;
1909 SfxMedium
aMedium(md
.getAsConstPropertyValueList());
1910 css::uno::Reference
<css::embed::XStorage
> xStorage
1911 = aMedium
.GetOutputStorage();
1914 if (!xStorage
.is()) {
1915 throw css::uno::RuntimeException(
1916 "SfxDocumentMetaData::storeToMedium: cannot get Storage",
1919 // set MIME type of the storage
1920 utl::MediaDescriptor::const_iterator iter
1921 = md
.find(utl::MediaDescriptor::PROP_MEDIATYPE
);
1922 if (iter
!= md
.end()) {
1923 css::uno::Reference
< css::beans::XPropertySet
> xProps(xStorage
,
1924 css::uno::UNO_QUERY_THROW
);
1925 xProps
->setPropertyValue(
1926 utl::MediaDescriptor::PROP_MEDIATYPE
,
1929 storeToStorage(xStorage
, md
.getAsConstPropertyValueList());
1932 const bool bOk
= aMedium
.Commit();
1935 ErrCode nError
= aMedium
.GetError();
1936 if ( nError
== ERRCODE_NONE
) {
1937 nError
= ERRCODE_IO_GENERAL
;
1940 throw css::task::ErrorCodeIOException(
1941 "SfxDocumentMetaData::storeToMedium <" + URL
+ "> Commit failed: " + nError
.toHexString(),
1942 css::uno::Reference
< css::uno::XInterface
>(), sal_uInt32(nError
));
1947 // css::lang::XInitialization:
1948 void SAL_CALL
SfxDocumentMetaData::initialize( const css::uno::Sequence
< css::uno::Any
> & aArguments
)
1950 // possible arguments:
1951 // - no argument: default initialization (empty DOM)
1952 // - 1 argument, XDocument: initialize with given DOM and empty base URL
1953 // NB: links in document must be absolute
1955 ::osl::MutexGuard
g(m_aMutex
);
1956 css::uno::Reference
<css::xml::dom::XDocument
> xDoc
;
1958 for (sal_Int32 i
= 0; i
< aArguments
.getLength(); ++i
) {
1959 const css::uno::Any any
= aArguments
[i
];
1960 if (!(any
>>= xDoc
)) {
1961 throw css::lang::IllegalArgumentException(
1962 "SfxDocumentMetaData::initialize: argument must be XDocument",
1963 *this, static_cast<sal_Int16
>(i
));
1966 throw css::lang::IllegalArgumentException(
1967 "SfxDocumentMetaData::initialize: argument is null",
1968 *this, static_cast<sal_Int16
>(i
));
1973 // For a new document, we create a new DOM tree here.
1980 // css::util::XCloneable:
1981 css::uno::Reference
<css::util::XCloneable
> SAL_CALL
1982 SfxDocumentMetaData::createClone()
1984 ::osl::MutexGuard
g(m_aMutex
);
1987 rtl::Reference
<SfxDocumentMetaData
> pNew
= createMe(m_xContext
);
1989 // NB: do not copy the modification listeners, only DOM
1990 css::uno::Reference
<css::xml::dom::XDocument
> xDoc
= createDOM();
1992 updateUserDefinedAndAttributes();
1993 // deep copy of root node
1994 css::uno::Reference
<css::xml::dom::XNode
> xRoot(
1995 m_xDoc
->getDocumentElement(), css::uno::UNO_QUERY_THROW
);
1996 css::uno::Reference
<css::xml::dom::XNode
> xRootNew(
1997 xDoc
->importNode(xRoot
, true));
1998 xDoc
->appendChild(xRootNew
);
2000 } catch (const css::uno::RuntimeException
&) {
2002 } catch (const css::uno::Exception
&) {
2003 css::uno::Any anyEx
= cppu::getCaughtException();
2004 throw css::lang::WrappedTargetRuntimeException(
2005 "SfxDocumentMetaData::createClone: exception",
2006 css::uno::Reference
<css::uno::XInterface
>(*this), anyEx
);
2008 return css::uno::Reference
<css::util::XCloneable
> (pNew
);
2011 // css::util::XModifiable:
2012 sal_Bool SAL_CALL
SfxDocumentMetaData::isModified( )
2014 ::osl::MutexGuard
g(m_aMutex
);
2016 css::uno::Reference
<css::util::XModifiable
> xMB(m_xUserDefined
,
2017 css::uno::UNO_QUERY
);
2018 return m_isModified
|| (xMB
.is() && xMB
->isModified());
2021 void SAL_CALL
SfxDocumentMetaData::setModified( sal_Bool bModified
)
2023 css::uno::Reference
<css::util::XModifiable
> xMB
;
2024 { // do not lock mutex while notifying (#i93514#) to prevent deadlock
2025 ::osl::MutexGuard
g(m_aMutex
);
2027 m_isModified
= bModified
;
2028 if ( !bModified
&& m_xUserDefined
.is() )
2030 xMB
.set(m_xUserDefined
, css::uno::UNO_QUERY
);
2032 "SfxDocumentMetaData::setModified: PropertyBag not Modifiable?");
2037 css::uno::Reference
<css::uno::XInterface
> xThis(*this);
2038 css::lang::EventObject
event(xThis
);
2039 m_NotifyListeners
.notifyEach(&css::util::XModifyListener::modified
,
2041 } catch (const css::uno::RuntimeException
&) {
2043 } catch (const css::uno::Exception
&) {
2045 TOOLS_WARN_EXCEPTION("sfx.doc", "setModified");
2049 xMB
->setModified(false);
2054 // css::util::XModifyBroadcaster:
2055 void SAL_CALL
SfxDocumentMetaData::addModifyListener(
2056 const css::uno::Reference
< css::util::XModifyListener
> & xListener
)
2058 ::osl::MutexGuard
g(m_aMutex
);
2060 m_NotifyListeners
.addInterface(xListener
);
2061 css::uno::Reference
<css::util::XModifyBroadcaster
> xMB(m_xUserDefined
,
2062 css::uno::UNO_QUERY
);
2064 xMB
->addModifyListener(xListener
);
2068 void SAL_CALL
SfxDocumentMetaData::removeModifyListener(
2069 const css::uno::Reference
< css::util::XModifyListener
> & xListener
)
2071 ::osl::MutexGuard
g(m_aMutex
);
2073 m_NotifyListeners
.removeInterface(xListener
);
2074 css::uno::Reference
<css::util::XModifyBroadcaster
> xMB(m_xUserDefined
,
2075 css::uno::UNO_QUERY
);
2077 xMB
->removeModifyListener(xListener
);
2081 // css::xml::sax::XSAXSerializable
2082 void SAL_CALL
SfxDocumentMetaData::serialize(
2083 const css::uno::Reference
<css::xml::sax::XDocumentHandler
>& i_xHandler
,
2084 const css::uno::Sequence
< css::beans::StringPair
>& i_rNamespaces
)
2086 ::osl::MutexGuard
g(m_aMutex
);
2088 updateUserDefinedAndAttributes();
2089 css::uno::Reference
<css::xml::sax::XSAXSerializable
> xSAXable(m_xDoc
,
2090 css::uno::UNO_QUERY_THROW
);
2091 xSAXable
->serialize(i_xHandler
, i_rNamespaces
);
2094 void SfxDocumentMetaData::createUserDefined()
2096 // user-defined meta data: create PropertyBag which only accepts property
2097 // values of allowed types
2098 if ( m_xUserDefined
.is() )
2101 css::uno::Sequence
<css::uno::Type
> types
{
2102 ::cppu::UnoType
<bool>::get(),
2103 ::cppu::UnoType
< OUString
>::get(),
2104 ::cppu::UnoType
<css::util::DateTime
>::get(),
2105 ::cppu::UnoType
<css::util::Date
>::get(),
2106 ::cppu::UnoType
<css::util::DateTimeWithTimezone
>::get(),
2107 ::cppu::UnoType
<css::util::DateWithTimezone
>::get(),
2108 ::cppu::UnoType
<css::util::Duration
>::get(),
2109 ::cppu::UnoType
<float>::get(),
2110 ::cppu::UnoType
<double>::get(),
2111 ::cppu::UnoType
<sal_Int16
>::get(),
2112 ::cppu::UnoType
<sal_Int32
>::get(),
2113 ::cppu::UnoType
<sal_Int64
>::get(),
2114 // Time is supported for backward compatibility with OOo 3.x, x<=2
2115 ::cppu::UnoType
<css::util::Time
>::get()
2117 // #i94175#: ODF allows empty user-defined property names!
2119 css::beans::PropertyBag::createWithTypes( m_xContext
, types
, true/*AllowEmptyPropertyName*/, false/*AutomaticAddition*/ ),
2120 css::uno::UNO_QUERY_THROW
);
2122 const css::uno::Reference
<css::util::XModifyBroadcaster
> xMB(
2123 m_xUserDefined
, css::uno::UNO_QUERY
);
2126 const std::vector
<css::uno::Reference
<css::uno::XInterface
> >
2127 listeners(m_NotifyListeners
.getElements());
2128 for (const auto& l
: listeners
) {
2129 xMB
->addModifyListener(
2130 css::uno::Reference
< css::util::XModifyListener
>(l
, css::uno::UNO_QUERY
) );
2135 } // closing anonymous implementation namespace
2137 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2138 CompatWriterDocPropsImpl_get_implementation(
2139 css::uno::XComponentContext
*context
,
2140 css::uno::Sequence
<css::uno::Any
> const &)
2142 return cppu::acquire(new CompatWriterDocPropsImpl(context
));
2145 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
2146 SfxDocumentMetaData_get_implementation(
2147 css::uno::XComponentContext
*context
,
2148 css::uno::Sequence
<css::uno::Any
> const &)
2150 return cppu::acquire(new SfxDocumentMetaData(context
));
2153 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */