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