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