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