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:type"),
997 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("simple"))));
998 attributes.push_back(std::make_pair(
999 static_cast<const char*>("xlink:href" ), m_AutoloadURL ));
1000 attributes.push_back(std::make_pair(
1001 static_cast<const char*>("meta:delay" ),
1002 durationToText(m_AutoloadSecs)));
1003 updateElement("meta:auto-reload", &attributes);
1004 } else {
1005 updateElement("meta:auto-reload");
1006 }
1007 attributes.clear();
1008
1009 if (!m_DefaultTarget.equalsAscii("")) {
1010 attributes.push_back(std::make_pair(
1011 static_cast<const char*>("office:target-frame-name"),
1012 m_DefaultTarget));
1013 // xlink:show: _blank -> new, any other value -> replace
1014 const sal_Char* show = m_DefaultTarget.equalsAscii("_blank")
1015 ? "new" : "replace";
1016 attributes.push_back(std::make_pair(
1017 static_cast<const char*>("xlink:show"),
1018 ::rtl::OUString::createFromAscii(show)));
1019 updateElement("meta:hyperlink-behaviour", &attributes);
1020 } else {
1021 updateElement("meta:hyperlink-behaviour");
1022 }
1023 attributes.clear();
1024
1025 if (!isValidDateTime(textToDateTimeDefault(getMetaText("meta:print-date")))) {
1026 static_cast<void>(setMetaText("meta:print-date", ::rtl::OUString()));
1027 }
1028 }
1029
1030 // create empty DOM tree (XDocument)
1031 css::uno::Reference<css::xml::dom::XDocument> SAL_CALL
createDOM() const1032 SfxDocumentMetaData::createDOM() const // throw (css::uno::RuntimeException)
1033 {
1034 css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
1035 m_xContext->getServiceManager());
1036 css::uno::Reference<css::xml::dom::XDocumentBuilder> xBuilder(
1037 xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii(
1038 "com.sun.star.xml.dom.DocumentBuilder"), m_xContext),
1039 css::uno::UNO_QUERY_THROW );
1040 if (!xBuilder.is()) throw css::uno::RuntimeException(
1041 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::createDOM: "
1042 "cannot create DocumentBuilder service"),
1043 *const_cast<SfxDocumentMetaData*>(this));
1044 css::uno::Reference<css::xml::dom::XDocument> xDoc =
1045 xBuilder->newDocument();
1046 if (!xDoc.is()) throw css::uno::RuntimeException(
1047 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::createDOM: "
1048 "cannot create new document"),
1049 *const_cast<SfxDocumentMetaData*>(this));
1050 return xDoc;
1051 }
1052
1053 void SAL_CALL
checkInit() const1054 SfxDocumentMetaData::checkInit() const // throw (css::uno::RuntimeException)
1055 {
1056 if (!m_isInitialized) {
1057 throw css::uno::RuntimeException(::rtl::OUString::createFromAscii(
1058 "SfxDocumentMetaData::checkInit: not initialized"),
1059 *const_cast<SfxDocumentMetaData*>(this));
1060 }
1061 DBG_ASSERT((m_xDoc.is() && m_xParent.is() ),
1062 "SfxDocumentMetaData::checkInit: reference is null");
1063 }
1064
1065 // initialize state from DOM tree
init(css::uno::Reference<css::xml::dom::XDocument> i_xDoc)1066 void SAL_CALL SfxDocumentMetaData::init(
1067 css::uno::Reference<css::xml::dom::XDocument> i_xDoc)
1068 // throw (css::uno::RuntimeException, css::io::WrongFormatException,
1069 // css::uno::Exception)
1070 {
1071 if (!i_xDoc.is()) throw css::uno::RuntimeException(
1072 ::rtl::OUString::createFromAscii(
1073 "SfxDocumentMetaData::init: no DOM tree given"), *this);
1074
1075 css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
1076 m_xContext->getServiceManager());
1077 css::uno::Reference<css::xml::xpath::XXPathAPI> xPath(
1078 xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii(
1079 "com.sun.star.xml.xpath.XPathAPI"), m_xContext),
1080 css::uno::UNO_QUERY_THROW );
1081 if (!xPath.is()) throw css::uno::RuntimeException(
1082 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::init:"
1083 " cannot create XPathAPI service"), *this);
1084
1085 m_isInitialized = false;
1086 m_xDoc = i_xDoc;
1087
1088 // select nodes for standard meta data stuff
1089 xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xlink")),
1090 ::rtl::OUString::createFromAscii(s_nsXLink));
1091 xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("dc")),
1092 ::rtl::OUString::createFromAscii(s_nsDC));
1093 xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("office")),
1094 ::rtl::OUString::createFromAscii(s_nsODF));
1095 xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("meta")),
1096 ::rtl::OUString::createFromAscii(s_nsODFMeta));
1097 // NB: we do not handle the single-XML-file ODF variant, which would
1098 // have the root element office:document.
1099 // The root of such documents must be converted in the importer!
1100 ::rtl::OUString prefix = ::rtl::OUString::createFromAscii(
1101 "/child::office:document-meta/child::office:meta");
1102 css::uno::Reference<css::xml::dom::XNode> xDocNode(
1103 m_xDoc, css::uno::UNO_QUERY_THROW);
1104 m_xParent.clear();
1105 try {
1106 m_xParent = xPath->selectSingleNode(xDocNode, prefix);
1107 } catch (com::sun::star::uno::Exception &) {
1108 // DBG_WARNING("SfxDocumentMetaData::init: "
1109 // "caught RuntimeException from libxml!");
1110 }
1111
1112 if (!m_xParent.is()) {
1113 // all this create/append stuff may throw DOMException
1114 try {
1115 css::uno::Reference<css::xml::dom::XElement> xRElem;
1116 css::uno::Reference<css::xml::dom::XNode> xNode(
1117 i_xDoc->getFirstChild());
1118 while (xNode.is()) {
1119 if (css::xml::dom::NodeType_ELEMENT_NODE ==xNode->getNodeType())
1120 {
1121 if (xNode->getNamespaceURI().equalsAscii(s_nsODF) &&
1122 xNode->getLocalName().equalsAscii("document-meta"))
1123 {
1124 xRElem.set(xNode, css::uno::UNO_QUERY_THROW);
1125 break;
1126 }
1127 else
1128 {
1129 OSL_TRACE("SfxDocumentMetaData::init(): "
1130 "deleting unexpected root element: %s",
1131 ::rtl::OUStringToOString(xNode->getLocalName(),
1132 RTL_TEXTENCODING_UTF8).getStr());
1133 i_xDoc->removeChild(xNode);
1134 xNode = i_xDoc->getFirstChild(); // start over
1135 }
1136 } else {
1137 xNode = xNode->getNextSibling();
1138 }
1139 }
1140 if (!xRElem.is()) {
1141 xRElem = i_xDoc->createElementNS(
1142 ::rtl::OUString::createFromAscii(s_nsODF),
1143 ::rtl::OUString::createFromAscii("office:document-meta"));
1144 css::uno::Reference<css::xml::dom::XNode> xRNode(xRElem,
1145 css::uno::UNO_QUERY_THROW);
1146 i_xDoc->appendChild(xRNode);
1147 }
1148 xRElem->setAttributeNS(::rtl::OUString::createFromAscii(s_nsODF),
1149 ::rtl::OUString::createFromAscii("office:version"),
1150 ::rtl::OUString::createFromAscii("1.0"));
1151 // does not exist, otherwise m_xParent would not be null
1152 css::uno::Reference<css::xml::dom::XNode> xParent (
1153 i_xDoc->createElementNS(
1154 ::rtl::OUString::createFromAscii(s_nsODF),
1155 ::rtl::OUString::createFromAscii("office:meta")),
1156 css::uno::UNO_QUERY_THROW);
1157 xRElem->appendChild(xParent);
1158 m_xParent = xParent;
1159 } catch (css::xml::dom::DOMException & e) {
1160 css::uno::Any a(e);
1161 throw css::lang::WrappedTargetRuntimeException(
1162 ::rtl::OUString::createFromAscii(
1163 "SfxDocumentMetaData::init: DOM exception"),
1164 css::uno::Reference<css::uno::XInterface>(*this), a);
1165 }
1166 }
1167
1168
1169 // select nodes for elements of which we only handle one occurrence
1170 for (const char **pName = s_stdMeta; *pName != 0; ++pName) {
1171 ::rtl::OUString name = ::rtl::OUString::createFromAscii(*pName);
1172 // NB: If a document contains more than one occurrence of a
1173 // meta-data element, we arbitrarily pick one of them here.
1174 // We do not remove the others, i.e., when we write the
1175 // document, it will contain the duplicates unchanged.
1176 // The ODF spec says that handling multiple occurrences is
1177 // application-specific.
1178 css::uno::Reference<css::xml::dom::XNode> xNode =
1179 xPath->selectSingleNode(m_xParent,
1180 ::rtl::OUString::createFromAscii("child::") + name);
1181 // Do not create an empty element if it is missing;
1182 // for certain elements, such as dateTime, this would be invalid
1183 m_meta[name] = xNode;
1184 }
1185
1186 // select nodes for elements of which we handle all occurrences
1187 for (const char **pName = s_stdMetaList; *pName != 0; ++pName) {
1188 ::rtl::OUString name = ::rtl::OUString::createFromAscii(*pName);
1189 css::uno::Reference<css::xml::dom::XNodeList> nodes =
1190 xPath->selectNodeList(m_xParent,
1191 ::rtl::OUString::createFromAscii("child::") + name);
1192 std::vector<css::uno::Reference<css::xml::dom::XNode> > v;
1193 for (sal_Int32 i = 0; i < nodes->getLength(); ++i) {
1194 v.push_back(nodes->item(i));
1195 }
1196 m_metaList[name] = v;
1197 }
1198
1199 // initialize members corresponding to attributes from DOM nodes
1200 m_TemplateName = getMetaAttr("meta:template", "xlink:title");
1201 m_TemplateURL = getMetaAttr("meta:template", "xlink:href");
1202 m_TemplateDate =
1203 textToDateTimeDefault(getMetaAttr("meta:template", "meta:date"));
1204 m_AutoloadURL = getMetaAttr("meta:auto-reload", "xlink:href");
1205 m_AutoloadSecs =
1206 textToDuration(getMetaAttr("meta:auto-reload", "meta:delay"));
1207 m_DefaultTarget =
1208 getMetaAttr("meta:hyperlink-behaviour", "office:target-frame-name");
1209
1210
1211 std::vector<css::uno::Reference<css::xml::dom::XNode> > & vec =
1212 m_metaList[::rtl::OUString::createFromAscii("meta:user-defined")];
1213 m_xUserDefined.clear(); // #i105826#: reset (may be re-initialization)
1214 if ( !vec.empty() )
1215 {
1216 createUserDefined();
1217 }
1218
1219 // user-defined meta data: initialize PropertySet from DOM nodes
1220 for (std::vector<css::uno::Reference<css::xml::dom::XNode> >::iterator
1221 it = vec.begin(); it != vec.end(); ++it) {
1222 css::uno::Reference<css::xml::dom::XElement> xElem(*it,
1223 css::uno::UNO_QUERY_THROW);
1224 css::uno::Any any;
1225 ::rtl::OUString name = xElem->getAttributeNS(
1226 ::rtl::OUString::createFromAscii(s_nsODFMeta),
1227 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("name")));
1228 ::rtl::OUString type = xElem->getAttributeNS(
1229 ::rtl::OUString::createFromAscii(s_nsODFMeta),
1230 ::rtl::OUString::createFromAscii("value-type"));
1231 ::rtl::OUString text = getNodeText(*it);
1232 if (type.equalsAscii("float")) {
1233 double d;
1234 if (::sax::Converter::convertDouble(d, text)) {
1235 any <<= d;
1236 } else {
1237 DBG_WARNING1("SfxDocumentMetaData: invalid float: %s",
1238 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
1239 continue;
1240 }
1241 } else if (type.equalsAscii("date")) {
1242 bool isDateTime;
1243 css::util::Date d;
1244 css::util::DateTime dt;
1245 if (textToDateOrDateTime(d, dt, isDateTime, text)) {
1246 if (isDateTime) {
1247 any <<= dt;
1248 } else {
1249 any <<= d;
1250 }
1251 } else {
1252 DBG_WARNING1("SfxDocumentMetaData: invalid date: %s",
1253 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
1254 continue;
1255 }
1256 } else if (type.equalsAscii("time")) {
1257 css::util::Duration ud;
1258 if (textToDuration(ud, text)) {
1259 any <<= ud;
1260 } else {
1261 DBG_WARNING1("SfxDocumentMetaData: invalid time: %s",
1262 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
1263 continue;
1264 }
1265 } else if (type.equalsAscii("boolean")) {
1266 bool b;
1267 if (::sax::Converter::convertBool(b, text)) {
1268 any <<= b;
1269 } else {
1270 DBG_WARNING1("SfxDocumentMetaData: invalid boolean: %s",
1271 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
1272 continue;
1273 }
1274 } else if (type.equalsAscii("string") || true) { // default
1275 any <<= text;
1276 }
1277 try {
1278 m_xUserDefined->addProperty(name,
1279 css::beans::PropertyAttribute::REMOVEABLE, any);
1280 } catch (css::beans::PropertyExistException &) {
1281 DBG_WARNING1("SfxDocumentMetaData: duplicate: %s",
1282 OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
1283 // ignore; duplicate
1284 } catch (css::beans::IllegalTypeException &) {
1285 DBG_ERROR1("SfxDocumentMetaData: illegal type: %s",
1286 OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
1287 } catch (css::lang::IllegalArgumentException &) {
1288 DBG_ERROR1("SfxDocumentMetaData: illegal arg: %s",
1289 OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
1290 }
1291 }
1292
1293 m_isModified = false;
1294 m_isInitialized = true;
1295 }
1296
1297
1298 ////////////////////////////////////////////////////////////////////////////
1299
SfxDocumentMetaData(css::uno::Reference<css::uno::XComponentContext> const & context)1300 SfxDocumentMetaData::SfxDocumentMetaData(
1301 css::uno::Reference< css::uno::XComponentContext > const & context)
1302 : BaseMutex()
1303 , SfxDocumentMetaData_Base(m_aMutex)
1304 , m_xContext(context)
1305 , m_NotifyListeners(m_aMutex)
1306 , m_isInitialized(false)
1307 , m_isModified(false)
1308 , m_AutoloadSecs(0)
1309 {
1310 DBG_ASSERT(context.is(), "SfxDocumentMetaData: context is null");
1311 DBG_ASSERT(context->getServiceManager().is(),
1312 "SfxDocumentMetaData: context has no service manager");
1313 init(createDOM());
1314 }
1315
1316 // com.sun.star.uno.XServiceInfo:
1317 ::rtl::OUString SAL_CALL
getImplementationName()1318 SfxDocumentMetaData::getImplementationName()
1319 {
1320 return comp_SfxDocumentMetaData::_getImplementationName();
1321 }
1322
1323 ::sal_Bool SAL_CALL
supportsService(::rtl::OUString const & serviceName)1324 SfxDocumentMetaData::supportsService(::rtl::OUString const & serviceName)
1325 {
1326 css::uno::Sequence< ::rtl::OUString > serviceNames =
1327 comp_SfxDocumentMetaData::_getSupportedServiceNames();
1328 for (::sal_Int32 i = 0; i < serviceNames.getLength(); ++i) {
1329 if (serviceNames[i] == serviceName)
1330 return sal_True;
1331 }
1332 return sal_False;
1333 }
1334
1335 css::uno::Sequence< ::rtl::OUString > SAL_CALL
getSupportedServiceNames()1336 SfxDocumentMetaData::getSupportedServiceNames()
1337 {
1338 return comp_SfxDocumentMetaData::_getSupportedServiceNames();
1339 }
1340
1341
1342 // ::com::sun::star::lang::XComponent:
dispose()1343 void SAL_CALL SfxDocumentMetaData::dispose()
1344 {
1345 ::osl::MutexGuard g(m_aMutex);
1346 if (!m_isInitialized) {
1347 return;
1348 }
1349 WeakComponentImplHelperBase::dispose(); // superclass
1350 m_NotifyListeners.disposeAndClear(css::lang::EventObject(
1351 static_cast< ::cppu::OWeakObject* >(this)));
1352 m_isInitialized = false;
1353 m_meta.clear();
1354 m_metaList.clear();
1355 m_xParent.clear();
1356 m_xDoc.clear();
1357 m_xUserDefined.clear();
1358 }
1359
1360
1361 // ::com::sun::star::document::XDocumentProperties:
1362 ::rtl::OUString SAL_CALL
getAuthor()1363 SfxDocumentMetaData::getAuthor()
1364 {
1365 ::osl::MutexGuard g(m_aMutex);
1366 return getMetaText("meta:initial-creator");
1367 }
1368
setAuthor(const::rtl::OUString & the_value)1369 void SAL_CALL SfxDocumentMetaData::setAuthor(const ::rtl::OUString & the_value)
1370 {
1371 setMetaTextAndNotify("meta:initial-creator", the_value);
1372 }
1373
1374
1375 ::rtl::OUString SAL_CALL
getGenerator()1376 SfxDocumentMetaData::getGenerator()
1377 {
1378 ::osl::MutexGuard g(m_aMutex);
1379 return getMetaText("meta:generator");
1380 }
1381
1382 void SAL_CALL
setGenerator(const::rtl::OUString & the_value)1383 SfxDocumentMetaData::setGenerator(const ::rtl::OUString & the_value)
1384 {
1385 setMetaTextAndNotify("meta:generator", the_value);
1386 }
1387
1388 css::util::DateTime SAL_CALL
getCreationDate()1389 SfxDocumentMetaData::getCreationDate()
1390 {
1391 ::osl::MutexGuard g(m_aMutex);
1392 return textToDateTimeDefault(getMetaText("meta:creation-date"));
1393 }
1394
1395 void SAL_CALL
setCreationDate(const css::util::DateTime & the_value)1396 SfxDocumentMetaData::setCreationDate(const css::util::DateTime & the_value)
1397 {
1398 setMetaTextAndNotify("meta:creation-date", dateTimeToText(the_value));
1399 }
1400
1401 ::rtl::OUString SAL_CALL
getTitle()1402 SfxDocumentMetaData::getTitle()
1403 {
1404 ::osl::MutexGuard g(m_aMutex);
1405 return getMetaText("dc:title");
1406 }
1407
setTitle(const::rtl::OUString & the_value)1408 void SAL_CALL SfxDocumentMetaData::setTitle(const ::rtl::OUString & the_value)
1409 {
1410 setMetaTextAndNotify("dc:title", the_value);
1411 }
1412
1413 ::rtl::OUString SAL_CALL
getSubject()1414 SfxDocumentMetaData::getSubject()
1415 {
1416 ::osl::MutexGuard g(m_aMutex);
1417 return getMetaText("dc:subject");
1418 }
1419
1420 void SAL_CALL
setSubject(const::rtl::OUString & the_value)1421 SfxDocumentMetaData::setSubject(const ::rtl::OUString & the_value)
1422 {
1423 setMetaTextAndNotify("dc:subject", the_value);
1424 }
1425
1426 ::rtl::OUString SAL_CALL
getDescription()1427 SfxDocumentMetaData::getDescription()
1428 {
1429 ::osl::MutexGuard g(m_aMutex);
1430 return getMetaText("dc:description");
1431 }
1432
1433 void SAL_CALL
setDescription(const::rtl::OUString & the_value)1434 SfxDocumentMetaData::setDescription(const ::rtl::OUString & the_value)
1435 {
1436 setMetaTextAndNotify("dc:description", the_value);
1437 }
1438
1439 css::uno::Sequence< ::rtl::OUString >
getKeywords()1440 SAL_CALL SfxDocumentMetaData::getKeywords()
1441 {
1442 ::osl::MutexGuard g(m_aMutex);
1443 return getMetaList("meta:keyword");
1444 }
1445
1446 void SAL_CALL
setKeywords(const css::uno::Sequence<::rtl::OUString> & the_value)1447 SfxDocumentMetaData::setKeywords(
1448 const css::uno::Sequence< ::rtl::OUString > & the_value)
1449 {
1450 ::osl::ClearableMutexGuard g(m_aMutex);
1451 if (setMetaList("meta:keyword", the_value)) {
1452 g.clear();
1453 setModified(true);
1454 }
1455 }
1456
1457 css::lang::Locale SAL_CALL
getLanguage()1458 SfxDocumentMetaData::getLanguage()
1459 {
1460 ::osl::MutexGuard g(m_aMutex);
1461 css::lang::Locale loc;
1462 ::rtl::OUString text = getMetaText("dc:language");
1463 sal_Int32 ix = text.indexOf(static_cast<sal_Unicode> ('-'));
1464 if (ix == -1) {
1465 loc.Language = text;
1466 } else {
1467 loc.Language = text.copy(0, ix);
1468 loc.Country = text.copy(ix+1);
1469 }
1470 return loc;
1471 }
1472
1473 void SAL_CALL
setLanguage(const css::lang::Locale & the_value)1474 SfxDocumentMetaData::setLanguage(const css::lang::Locale & the_value)
1475 {
1476 ::rtl::OUString text = the_value.Language;
1477 if (the_value.Country.getLength() > 0) {
1478 text += ::rtl::OUString::createFromAscii("-").concat(the_value.Country);
1479 }
1480 setMetaTextAndNotify("dc:language", text);
1481 }
1482
1483 ::rtl::OUString SAL_CALL
getModifiedBy()1484 SfxDocumentMetaData::getModifiedBy()
1485 {
1486 ::osl::MutexGuard g(m_aMutex);
1487 return getMetaText("dc:creator");
1488 }
1489
1490 void SAL_CALL
setModifiedBy(const::rtl::OUString & the_value)1491 SfxDocumentMetaData::setModifiedBy(const ::rtl::OUString & the_value)
1492 {
1493 setMetaTextAndNotify("dc:creator", the_value);
1494 }
1495
1496 css::util::DateTime SAL_CALL
getModificationDate()1497 SfxDocumentMetaData::getModificationDate()
1498 {
1499 ::osl::MutexGuard g(m_aMutex);
1500 return textToDateTimeDefault(getMetaText("dc:date"));
1501 }
1502
1503 void SAL_CALL
setModificationDate(const css::util::DateTime & the_value)1504 SfxDocumentMetaData::setModificationDate(const css::util::DateTime & the_value)
1505 {
1506 setMetaTextAndNotify("dc:date", dateTimeToText(the_value));
1507 }
1508
1509 ::rtl::OUString SAL_CALL
getPrintedBy()1510 SfxDocumentMetaData::getPrintedBy()
1511 {
1512 ::osl::MutexGuard g(m_aMutex);
1513 return getMetaText("meta:printed-by");
1514 }
1515
1516 void SAL_CALL
setPrintedBy(const::rtl::OUString & the_value)1517 SfxDocumentMetaData::setPrintedBy(const ::rtl::OUString & the_value)
1518 {
1519 setMetaTextAndNotify("meta:printed-by", the_value);
1520 }
1521
1522 css::util::DateTime SAL_CALL
getPrintDate()1523 SfxDocumentMetaData::getPrintDate()
1524 {
1525 ::osl::MutexGuard g(m_aMutex);
1526 return textToDateTimeDefault(getMetaText("meta:print-date"));
1527 }
1528
1529 void SAL_CALL
setPrintDate(const css::util::DateTime & the_value)1530 SfxDocumentMetaData::setPrintDate(const css::util::DateTime & the_value)
1531 {
1532 setMetaTextAndNotify("meta:print-date", dateTimeToText(the_value));
1533 }
1534
1535 ::rtl::OUString SAL_CALL
getTemplateName()1536 SfxDocumentMetaData::getTemplateName()
1537 {
1538 ::osl::MutexGuard g(m_aMutex);
1539 checkInit();
1540 return m_TemplateName;
1541 }
1542
1543 void SAL_CALL
setTemplateName(const::rtl::OUString & the_value)1544 SfxDocumentMetaData::setTemplateName(const ::rtl::OUString & the_value)
1545 {
1546 ::osl::ClearableMutexGuard g(m_aMutex);
1547 checkInit();
1548 if (m_TemplateName != the_value) {
1549 m_TemplateName = the_value;
1550 g.clear();
1551 setModified(true);
1552 }
1553 }
1554
1555 ::rtl::OUString SAL_CALL
getTemplateURL()1556 SfxDocumentMetaData::getTemplateURL()
1557 {
1558 ::osl::MutexGuard g(m_aMutex);
1559 checkInit();
1560 return m_TemplateURL;
1561 }
1562
1563 void SAL_CALL
setTemplateURL(const::rtl::OUString & the_value)1564 SfxDocumentMetaData::setTemplateURL(const ::rtl::OUString & the_value)
1565 {
1566 ::osl::ClearableMutexGuard g(m_aMutex);
1567 checkInit();
1568 if (m_TemplateURL != the_value) {
1569 m_TemplateURL = the_value;
1570 g.clear();
1571 setModified(true);
1572 }
1573 }
1574
1575 css::util::DateTime SAL_CALL
getTemplateDate()1576 SfxDocumentMetaData::getTemplateDate()
1577 {
1578 ::osl::MutexGuard g(m_aMutex);
1579 checkInit();
1580 return m_TemplateDate;
1581 }
1582
1583 void SAL_CALL
setTemplateDate(const css::util::DateTime & the_value)1584 SfxDocumentMetaData::setTemplateDate(const css::util::DateTime & the_value)
1585 {
1586 ::osl::ClearableMutexGuard g(m_aMutex);
1587 checkInit();
1588 if (!(m_TemplateDate == the_value)) {
1589 m_TemplateDate = the_value;
1590 g.clear();
1591 setModified(true);
1592 }
1593 }
1594
1595 ::rtl::OUString SAL_CALL
getAutoloadURL()1596 SfxDocumentMetaData::getAutoloadURL()
1597 {
1598 ::osl::MutexGuard g(m_aMutex);
1599 checkInit();
1600 return m_AutoloadURL;
1601 }
1602
1603 void SAL_CALL
setAutoloadURL(const::rtl::OUString & the_value)1604 SfxDocumentMetaData::setAutoloadURL(const ::rtl::OUString & the_value)
1605 {
1606 ::osl::ClearableMutexGuard g(m_aMutex);
1607 checkInit();
1608 if (m_AutoloadURL != the_value) {
1609 m_AutoloadURL = the_value;
1610 g.clear();
1611 setModified(true);
1612 }
1613 }
1614
1615 ::sal_Int32 SAL_CALL
getAutoloadSecs()1616 SfxDocumentMetaData::getAutoloadSecs()
1617 {
1618 ::osl::MutexGuard g(m_aMutex);
1619 checkInit();
1620 return m_AutoloadSecs;
1621 }
1622
1623 void SAL_CALL
setAutoloadSecs(::sal_Int32 the_value)1624 SfxDocumentMetaData::setAutoloadSecs(::sal_Int32 the_value)
1625 {
1626 if (the_value < 0) throw css::lang::IllegalArgumentException(
1627 ::rtl::OUString::createFromAscii(
1628 "SfxDocumentMetaData::setAutoloadSecs: argument is negative"),
1629 *this, 0);
1630 ::osl::ClearableMutexGuard g(m_aMutex);
1631 checkInit();
1632 if (m_AutoloadSecs != the_value) {
1633 m_AutoloadSecs = the_value;
1634 g.clear();
1635 setModified(true);
1636 }
1637 }
1638
1639 ::rtl::OUString SAL_CALL
getDefaultTarget()1640 SfxDocumentMetaData::getDefaultTarget()
1641 {
1642 ::osl::MutexGuard g(m_aMutex);
1643 checkInit();
1644 return m_DefaultTarget;
1645 }
1646
1647 void SAL_CALL
setDefaultTarget(const::rtl::OUString & the_value)1648 SfxDocumentMetaData::setDefaultTarget(const ::rtl::OUString & the_value)
1649 {
1650 ::osl::ClearableMutexGuard g(m_aMutex);
1651 checkInit();
1652 if (m_DefaultTarget != the_value) {
1653 m_DefaultTarget = the_value;
1654 g.clear();
1655 setModified(true);
1656 }
1657 }
1658
1659 css::uno::Sequence< css::beans::NamedValue > SAL_CALL
getDocumentStatistics()1660 SfxDocumentMetaData::getDocumentStatistics()
1661 {
1662 ::osl::MutexGuard g(m_aMutex);
1663 checkInit();
1664 ::comphelper::SequenceAsVector<css::beans::NamedValue> stats;
1665 for (size_t i = 0; s_stdStats[i] != 0; ++i) {
1666 const char * aName = s_stdStatAttrs[i];
1667 ::rtl::OUString text = getMetaAttr("meta:document-statistic", aName);
1668 if (text.equalsAscii("")) continue;
1669 css::beans::NamedValue stat;
1670 stat.Name = ::rtl::OUString::createFromAscii(s_stdStats[i]);
1671 sal_Int32 val;
1672 css::uno::Any any;
1673 if (!::sax::Converter::convertNumber(val, text, 0,
1674 std::numeric_limits<sal_Int32>::max()) || (val < 0)) {
1675 val = 0;
1676 DBG_WARNING1("SfxDocumentMetaData: invalid number: %s",
1677 OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
1678 }
1679 any <<= val;
1680 stat.Value = any;
1681 stats.push_back(stat);
1682 }
1683
1684 return stats.getAsConstList();
1685 }
1686
1687 void SAL_CALL
setDocumentStatistics(const css::uno::Sequence<css::beans::NamedValue> & the_value)1688 SfxDocumentMetaData::setDocumentStatistics(
1689 const css::uno::Sequence< css::beans::NamedValue > & the_value)
1690 {
1691 ::osl::ClearableMutexGuard g(m_aMutex);
1692 checkInit();
1693 std::vector<std::pair<const char *, ::rtl::OUString> > attributes;
1694 for (sal_Int32 i = 0; i < the_value.getLength(); ++i) {
1695 const ::rtl::OUString name = the_value[i].Name;
1696 // inefficently search for matching attribute
1697 for (size_t j = 0; s_stdStats[j] != 0; ++j) {
1698 if (name.equalsAscii(s_stdStats[j])) {
1699 const css::uno::Any any = the_value[i].Value;
1700 sal_Int32 val = 0;
1701 if (any >>= val) {
1702 ::rtl::OUStringBuffer buf;
1703 ::sax::Converter::convertNumber(buf, val);
1704 attributes.push_back(std::make_pair(s_stdStatAttrs[j],
1705 buf.makeStringAndClear()));
1706 } else {
1707 DBG_WARNING1("SfxDocumentMetaData: invalid statistic: %s",
1708 OUStringToOString(name, RTL_TEXTENCODING_UTF8)
1709 .getStr());
1710 }
1711 break;
1712 }
1713 }
1714 }
1715 updateElement("meta:document-statistic", &attributes);
1716 g.clear();
1717 setModified(true);
1718 }
1719
1720 ::sal_Int16 SAL_CALL
getEditingCycles()1721 SfxDocumentMetaData::getEditingCycles()
1722 {
1723 ::osl::MutexGuard g(m_aMutex);
1724 ::rtl::OUString text = getMetaText("meta:editing-cycles");
1725 sal_Int32 ret;
1726 if (::sax::Converter::convertNumber(ret, text,
1727 0, std::numeric_limits<sal_Int16>::max())) {
1728 return static_cast<sal_Int16>(ret);
1729 } else {
1730 return 0;
1731 }
1732 }
1733
1734 void SAL_CALL
setEditingCycles(::sal_Int16 the_value)1735 SfxDocumentMetaData::setEditingCycles(::sal_Int16 the_value)
1736 {
1737 if (the_value < 0) throw css::lang::IllegalArgumentException(
1738 ::rtl::OUString::createFromAscii(
1739 "SfxDocumentMetaData::setEditingCycles: argument is negative"),
1740 *this, 0);
1741 ::rtl::OUStringBuffer buf;
1742 ::sax::Converter::convertNumber(buf, the_value);
1743 setMetaTextAndNotify("meta:editing-cycles", buf.makeStringAndClear());
1744 }
1745
1746 ::sal_Int32 SAL_CALL
getEditingDuration()1747 SfxDocumentMetaData::getEditingDuration()
1748 {
1749 ::osl::MutexGuard g(m_aMutex);
1750 return textToDuration(getMetaText("meta:editing-duration"));
1751 }
1752
1753 void SAL_CALL
setEditingDuration(::sal_Int32 the_value)1754 SfxDocumentMetaData::setEditingDuration(::sal_Int32 the_value)
1755 {
1756 if (the_value < 0) throw css::lang::IllegalArgumentException(
1757 ::rtl::OUString::createFromAscii(
1758 "SfxDocumentMetaData::setEditingDuration: argument is negative"),
1759 *this, 0);
1760 setMetaTextAndNotify("meta:editing-duration", durationToText(the_value));
1761 }
1762
1763 void SAL_CALL
resetUserData(const::rtl::OUString & the_value)1764 SfxDocumentMetaData::resetUserData(const ::rtl::OUString & the_value)
1765 {
1766 ::osl::ClearableMutexGuard g(m_aMutex);
1767
1768 bool bModified( false );
1769 bModified |= setMetaText("meta:initial-creator", the_value);
1770 ::DateTime now = DateTime();
1771 css::util::DateTime uDT(now.Get100Sec(), now.GetSec(), now.GetMin(),
1772 now.GetHour(), now.GetDay(), now.GetMonth(), now.GetYear());
1773 bModified |= setMetaText("meta:creation-date", dateTimeToText(uDT));
1774 bModified |= setMetaText("dc:creator", ::rtl::OUString());
1775 bModified |= setMetaText("meta:printed-by", ::rtl::OUString());
1776 bModified |= setMetaText("dc:date", dateTimeToText(css::util::DateTime()));
1777 bModified |= setMetaText("meta:print-date",
1778 dateTimeToText(css::util::DateTime()));
1779 bModified |= setMetaText("meta:editing-duration", durationToText(0));
1780 bModified |= setMetaText("meta:editing-cycles",
1781 ::rtl::OUString::createFromAscii("1"));
1782
1783 if (bModified) {
1784 g.clear();
1785 setModified(true);
1786 }
1787 }
1788
1789
1790 css::uno::Reference< css::beans::XPropertyContainer > SAL_CALL
getUserDefinedProperties()1791 SfxDocumentMetaData::getUserDefinedProperties()
1792 {
1793 ::osl::MutexGuard g(m_aMutex);
1794 checkInit();
1795 createUserDefined();
1796 return m_xUserDefined;
1797 }
1798
1799
1800 void SAL_CALL
loadFromStorage(const css::uno::Reference<css::embed::XStorage> & xStorage,const css::uno::Sequence<css::beans::PropertyValue> & Medium)1801 SfxDocumentMetaData::loadFromStorage(
1802 const css::uno::Reference< css::embed::XStorage > & xStorage,
1803 const css::uno::Sequence< css::beans::PropertyValue > & Medium)
1804 {
1805 if (!xStorage.is()) throw css::lang::IllegalArgumentException(
1806 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:"
1807 " argument is null"), *this, 0);
1808 ::osl::MutexGuard g(m_aMutex);
1809
1810 // open meta data file
1811 css::uno::Reference<css::io::XStream> xStream(
1812 xStorage->openStreamElement(
1813 ::rtl::OUString::createFromAscii(s_metaXml),
1814 css::embed::ElementModes::READ) );
1815 if (!xStream.is()) throw css::uno::RuntimeException();
1816 css::uno::Reference<css::io::XInputStream> xInStream =
1817 xStream->getInputStream();
1818 if (!xInStream.is()) throw css::uno::RuntimeException();
1819
1820 // create DOM parser service
1821 css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
1822 m_xContext->getServiceManager());
1823 css::uno::Reference<css::xml::sax::XParser> xParser (
1824 xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii(
1825 "com.sun.star.xml.sax.Parser"), m_xContext),
1826 css::uno::UNO_QUERY_THROW);
1827 if (!xParser.is()) throw css::uno::RuntimeException(
1828 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:"
1829 " cannot create Parser service"), *this);
1830 css::xml::sax::InputSource input;
1831 input.aInputStream = xInStream;
1832
1833 sal_uInt64 version = SotStorage::GetVersion( xStorage );
1834 // Oasis is also the default (0)
1835 sal_Bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 );
1836 const sal_Char *pServiceName = bOasis
1837 ? "com.sun.star.document.XMLOasisMetaImporter"
1838 : "com.sun.star.document.XMLMetaImporter";
1839
1840 // set base URL
1841 css::uno::Reference<css::beans::XPropertySet> xPropArg =
1842 getURLProperties(Medium);
1843 try {
1844 xPropArg->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI")))
1845 >>= input.sSystemId;
1846 input.sSystemId += ::rtl::OUString::createFromAscii("/").concat(
1847 ::rtl::OUString::createFromAscii(s_metaXml));
1848 } catch (css::uno::Exception &) {
1849 input.sSystemId = ::rtl::OUString::createFromAscii(s_metaXml);
1850 }
1851 css::uno::Sequence< css::uno::Any > args(1);
1852 args[0] <<= xPropArg;
1853
1854 css::uno::Reference<css::xml::sax::XDocumentHandler> xDocHandler (
1855 xMsf->createInstanceWithArgumentsAndContext(
1856 ::rtl::OUString::createFromAscii(pServiceName), args, m_xContext),
1857 css::uno::UNO_QUERY_THROW);
1858 if (!xDocHandler.is()) throw css::uno::RuntimeException(
1859 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:"
1860 " cannot create XMLOasisMetaImporter service"), *this);
1861 css::uno::Reference<css::document::XImporter> xImp (xDocHandler,
1862 css::uno::UNO_QUERY_THROW);
1863 xImp->setTargetDocument(css::uno::Reference<css::lang::XComponent>(this));
1864 xParser->setDocumentHandler(xDocHandler);
1865 try {
1866 xParser->parseStream(input);
1867 } catch (css::xml::sax::SAXException &) {
1868 throw css::io::WrongFormatException(::rtl::OUString::createFromAscii(
1869 "SfxDocumentMetaData::loadFromStorage:"
1870 " XML parsing exception"), *this);
1871 }
1872 // NB: the implementation of XMLOasisMetaImporter calls initialize
1873 // init(xDocBuilder->getDocument());
1874 checkInit();
1875 }
1876
1877 void SAL_CALL
storeToStorage(const css::uno::Reference<css::embed::XStorage> & xStorage,const css::uno::Sequence<css::beans::PropertyValue> & Medium)1878 SfxDocumentMetaData::storeToStorage(
1879 const css::uno::Reference< css::embed::XStorage > & xStorage,
1880 const css::uno::Sequence< css::beans::PropertyValue > & Medium)
1881 {
1882 if (!xStorage.is()) throw css::lang::IllegalArgumentException(
1883 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::storeToStorage:"
1884 " argument is null"), *this, 0);
1885 ::osl::MutexGuard g(m_aMutex);
1886 checkInit();
1887
1888 // update user-defined meta data in DOM tree
1889 // updateUserDefinedAndAttributes(); // this will be done in serialize!
1890
1891 // write into storage
1892 css::uno::Reference<css::io::XStream> xStream =
1893 xStorage->openStreamElement(::rtl::OUString::createFromAscii(s_metaXml),
1894 css::embed::ElementModes::WRITE
1895 | css::embed::ElementModes::TRUNCATE);
1896 if (!xStream.is()) throw css::uno::RuntimeException();
1897 css::uno::Reference< css::beans::XPropertySet > xStreamProps(xStream,
1898 css::uno::UNO_QUERY_THROW);
1899 xStreamProps->setPropertyValue(
1900 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MediaType")),
1901 css::uno::makeAny(::rtl::OUString::createFromAscii("text/xml")));
1902 xStreamProps->setPropertyValue(
1903 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Compressed")),
1904 css::uno::makeAny(static_cast<sal_Bool> (sal_False)));
1905 xStreamProps->setPropertyValue(
1906 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("UseCommonStoragePasswordEncryption")),
1907 css::uno::makeAny(static_cast<sal_Bool> (sal_False)));
1908 css::uno::Reference<css::io::XOutputStream> xOutStream =
1909 xStream->getOutputStream();
1910 if (!xOutStream.is()) throw css::uno::RuntimeException();
1911 css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
1912 m_xContext->getServiceManager());
1913 css::uno::Reference<css::io::XActiveDataSource> xSaxWriter(
1914 xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii(
1915 "com.sun.star.xml.sax.Writer"), m_xContext),
1916 css::uno::UNO_QUERY_THROW);
1917 xSaxWriter->setOutputStream(xOutStream);
1918 css::uno::Reference<css::xml::sax::XDocumentHandler> xDocHandler (
1919 xSaxWriter, css::uno::UNO_QUERY_THROW);
1920
1921 const sal_uInt64 version = SotStorage::GetVersion( xStorage );
1922 // Oasis is also the default (0)
1923 const sal_Bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 );
1924 const sal_Char *pServiceName = bOasis
1925 ? "com.sun.star.document.XMLOasisMetaExporter"
1926 : "com.sun.star.document.XMLMetaExporter";
1927
1928 // set base URL
1929 css::uno::Reference<css::beans::XPropertySet> xPropArg =
1930 getURLProperties(Medium);
1931 css::uno::Sequence< css::uno::Any > args(2);
1932 args[0] <<= xDocHandler;
1933 args[1] <<= xPropArg;
1934
1935 css::uno::Reference<css::document::XExporter> xExp(
1936 xMsf->createInstanceWithArgumentsAndContext(
1937 ::rtl::OUString::createFromAscii(pServiceName), args, m_xContext),
1938 css::uno::UNO_QUERY_THROW);
1939 xExp->setSourceDocument(css::uno::Reference<css::lang::XComponent>(this));
1940 css::uno::Reference<css::document::XFilter> xFilter(xExp,
1941 css::uno::UNO_QUERY_THROW);
1942 if (xFilter->filter(css::uno::Sequence< css::beans::PropertyValue >())) {
1943 css::uno::Reference<css::embed::XTransactedObject> xTransaction(
1944 xStorage, css::uno::UNO_QUERY);
1945 if (xTransaction.is()) {
1946 xTransaction->commit();
1947 }
1948 } else {
1949 throw css::io::IOException(::rtl::OUString::createFromAscii(
1950 "SfxDocumentMetaData::storeToStorage: cannot filter"), *this);
1951 }
1952 }
1953
1954 void SAL_CALL
loadFromMedium(const::rtl::OUString & URL,const css::uno::Sequence<css::beans::PropertyValue> & Medium)1955 SfxDocumentMetaData::loadFromMedium(const ::rtl::OUString & URL,
1956 const css::uno::Sequence< css::beans::PropertyValue > & Medium)
1957 {
1958 css::uno::Reference<css::io::XInputStream> xIn;
1959 ::comphelper::MediaDescriptor md(Medium);
1960 // if we have an URL parameter, it replaces the one in the media descriptor
1961 if (!URL.equalsAscii("")) {
1962 md[ ::comphelper::MediaDescriptor::PROP_URL() ] <<= URL;
1963 }
1964 if (sal_True == md.addInputStream()) {
1965 md[ ::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn;
1966 }
1967 css::uno::Reference<css::embed::XStorage> xStorage;
1968 css::uno::Reference<css::lang::XMultiServiceFactory> xMsf (
1969 m_xContext->getServiceManager(), css::uno::UNO_QUERY_THROW);
1970 try {
1971 if (xIn.is()) {
1972 xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream(
1973 xIn, xMsf);
1974 } else { // fallback to url parameter
1975 xStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
1976 URL, css::embed::ElementModes::READ, xMsf);
1977 }
1978 } catch (css::uno::RuntimeException &) {
1979 throw;
1980 } catch (css::io::IOException &) {
1981 throw;
1982 } catch (css::uno::Exception & e) {
1983 throw css::lang::WrappedTargetException(
1984 ::rtl::OUString::createFromAscii(
1985 "SfxDocumentMetaData::loadFromMedium: exception"),
1986 css::uno::Reference<css::uno::XInterface>(*this),
1987 css::uno::makeAny(e));
1988 }
1989 if (!xStorage.is()) {
1990 throw css::uno::RuntimeException(::rtl::OUString::createFromAscii(
1991 "SfxDocumentMetaData::loadFromMedium: cannot get Storage"),
1992 *this);
1993 }
1994 loadFromStorage(xStorage, md.getAsConstPropertyValueList());
1995 }
1996
1997 void SAL_CALL
storeToMedium(const::rtl::OUString & URL,const css::uno::Sequence<css::beans::PropertyValue> & Medium)1998 SfxDocumentMetaData::storeToMedium(const ::rtl::OUString & URL,
1999 const css::uno::Sequence< css::beans::PropertyValue > & Medium)
2000 {
2001 ::comphelper::MediaDescriptor md(Medium);
2002 if (!URL.equalsAscii("")) {
2003 md[ ::comphelper::MediaDescriptor::PROP_URL() ] <<= URL;
2004 }
2005 SfxMedium aMedium(md.getAsConstPropertyValueList());
2006 css::uno::Reference<css::embed::XStorage> xStorage
2007 = aMedium.GetOutputStorage();
2008
2009
2010 if (!xStorage.is()) {
2011 throw css::uno::RuntimeException(::rtl::OUString::createFromAscii(
2012 "SfxDocumentMetaData::storeToMedium: cannot get Storage"),
2013 *this);
2014 }
2015 // set MIME type of the storage
2016 ::comphelper::MediaDescriptor::const_iterator iter
2017 = md.find(::comphelper::MediaDescriptor::PROP_MEDIATYPE());
2018 if (iter != md.end()) {
2019 css::uno::Reference< css::beans::XPropertySet > xProps(xStorage,
2020 css::uno::UNO_QUERY_THROW);
2021 xProps->setPropertyValue(
2022 ::comphelper::MediaDescriptor::PROP_MEDIATYPE(),
2023 iter->second);
2024 }
2025 storeToStorage(xStorage, md.getAsConstPropertyValueList());
2026
2027
2028 const sal_Bool bOk = aMedium.Commit();
2029 aMedium.Close();
2030 if ( !bOk ) {
2031 sal_uInt32 nError = aMedium.GetError();
2032 if ( nError == ERRCODE_NONE ) {
2033 nError = ERRCODE_IO_GENERAL;
2034 }
2035
2036 throw css::task::ErrorCodeIOException( ::rtl::OUString(),
2037 css::uno::Reference< css::uno::XInterface >(), nError);
2038
2039 }
2040 }
2041
2042 // ::com::sun::star::lang::XInitialization:
2043 void SAL_CALL
initialize(const css::uno::Sequence<::com::sun::star::uno::Any> & aArguments)2044 SfxDocumentMetaData::initialize(
2045 const css::uno::Sequence< ::com::sun::star::uno::Any > & aArguments)
2046 {
2047 // possible arguments:
2048 // - no argument: default initialization (empty DOM)
2049 // - 1 argument, XDocument: initialize with given DOM and empty base URL
2050 // NB: links in document must be absolute
2051
2052 ::osl::MutexGuard g(m_aMutex);
2053 css::uno::Reference<css::xml::dom::XDocument> xDoc;
2054
2055 for (sal_Int32 i = 0; i < aArguments.getLength(); ++i) {
2056 const css::uno::Any any = aArguments[i];
2057 if (any >>= xDoc) {
2058 if (!xDoc.is()) {
2059 throw css::lang::IllegalArgumentException(
2060 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::"
2061 "initialize: argument is null"),
2062 *this, static_cast<sal_Int16>(i));
2063 }
2064 } else {
2065 throw css::lang::IllegalArgumentException(
2066 ::rtl::OUString::createFromAscii("SfxDocumentMetaData::"
2067 "initialize: argument must be XDocument"),
2068 *this, static_cast<sal_Int16>(i));
2069 }
2070 }
2071
2072 if (!xDoc.is()) {
2073 // For a new document, we create a new DOM tree here.
2074 xDoc = createDOM();
2075 }
2076
2077 init(xDoc);
2078 }
2079
2080 // ::com::sun::star::util::XCloneable:
2081 css::uno::Reference<css::util::XCloneable> SAL_CALL
createClone()2082 SfxDocumentMetaData::createClone()
2083 {
2084 ::osl::MutexGuard g(m_aMutex);
2085 checkInit();
2086
2087 SfxDocumentMetaData *pNew = new SfxDocumentMetaData(m_xContext);
2088
2089 // NB: do not copy the modification listeners, only DOM
2090 css::uno::Reference<css::xml::dom::XDocument> xDoc = createDOM();
2091 try {
2092 updateUserDefinedAndAttributes();
2093 // deep copy of root node
2094 css::uno::Reference<css::xml::dom::XNode> xRoot(
2095 m_xDoc->getDocumentElement(), css::uno::UNO_QUERY_THROW);
2096 css::uno::Reference<css::xml::dom::XNode> xRootNew(
2097 xDoc->importNode(xRoot, true));
2098 xDoc->appendChild(xRootNew);
2099 pNew->init(xDoc);
2100 } catch (css::uno::RuntimeException &) {
2101 throw;
2102 } catch (css::uno::Exception & e) {
2103 css::uno::Any a(e);
2104 throw css::lang::WrappedTargetRuntimeException(
2105 ::rtl::OUString::createFromAscii(
2106 "SfxDocumentMetaData::createClone: exception"),
2107 css::uno::Reference<css::uno::XInterface>(*this), a);
2108 }
2109 // return static_cast< ::cppu::OWeakObject * > (pNew);
2110 return css::uno::Reference<css::util::XCloneable> (pNew);
2111 }
2112
2113 // ::com::sun::star::util::XModifiable:
isModified()2114 ::sal_Bool SAL_CALL SfxDocumentMetaData::isModified( )
2115 {
2116 ::osl::MutexGuard g(m_aMutex);
2117 checkInit();
2118 css::uno::Reference<css::util::XModifiable> xMB(m_xUserDefined,
2119 css::uno::UNO_QUERY);
2120 return m_isModified || (xMB.is() ? xMB->isModified() : sal_False);
2121 }
2122
setModified(::sal_Bool bModified)2123 void SAL_CALL SfxDocumentMetaData::setModified( ::sal_Bool bModified )
2124 {
2125 css::uno::Reference<css::util::XModifiable> xMB;
2126 { // do not lock mutex while notifying (#i93514#) to prevent deadlock
2127 ::osl::MutexGuard g(m_aMutex);
2128 checkInit();
2129 m_isModified = bModified;
2130 if ( !bModified && m_xUserDefined.is() )
2131 {
2132 xMB.set(m_xUserDefined, css::uno::UNO_QUERY);
2133 DBG_ASSERT(xMB.is(),
2134 "SfxDocumentMetaData::setModified: PropertyBag not Modifiable?");
2135 }
2136 }
2137 if (bModified) {
2138 try {
2139 css::uno::Reference<css::uno::XInterface> xThis(*this);
2140 css::lang::EventObject event(xThis);
2141 m_NotifyListeners.notifyEach(&css::util::XModifyListener::modified,
2142 event);
2143 } catch (css::uno::RuntimeException &) {
2144 throw;
2145 } catch (css::uno::Exception & e) {
2146 // ignore
2147 DBG_WARNING1("SfxDocumentMetaData::setModified: exception:\n%s",
2148 OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
2149 (void) e;
2150 }
2151 } else {
2152 if (xMB.is()) {
2153 xMB->setModified(false);
2154 }
2155 }
2156 }
2157
2158 // ::com::sun::star::util::XModifyBroadcaster:
addModifyListener(const css::uno::Reference<css::util::XModifyListener> & xListener)2159 void SAL_CALL SfxDocumentMetaData::addModifyListener(
2160 const css::uno::Reference< css::util::XModifyListener > & xListener)
2161 {
2162 ::osl::MutexGuard g(m_aMutex);
2163 checkInit();
2164 m_NotifyListeners.addInterface(xListener);
2165 css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined,
2166 css::uno::UNO_QUERY);
2167 if (xMB.is()) {
2168 xMB->addModifyListener(xListener);
2169 }
2170 }
2171
removeModifyListener(const css::uno::Reference<css::util::XModifyListener> & xListener)2172 void SAL_CALL SfxDocumentMetaData::removeModifyListener(
2173 const css::uno::Reference< css::util::XModifyListener > & xListener)
2174 {
2175 ::osl::MutexGuard g(m_aMutex);
2176 checkInit();
2177 m_NotifyListeners.removeInterface(xListener);
2178 css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined,
2179 css::uno::UNO_QUERY);
2180 if (xMB.is()) {
2181 xMB->removeModifyListener(xListener);
2182 }
2183 }
2184
2185 // ::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)2186 void SAL_CALL SfxDocumentMetaData::serialize(
2187 const css::uno::Reference<css::xml::sax::XDocumentHandler>& i_xHandler,
2188 const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces)
2189 {
2190 ::osl::MutexGuard g(m_aMutex);
2191 checkInit();
2192 updateUserDefinedAndAttributes();
2193 css::uno::Reference<css::xml::sax::XSAXSerializable> xSAXable(m_xDoc,
2194 css::uno::UNO_QUERY_THROW);
2195 xSAXable->serialize(i_xHandler, i_rNamespaces);
2196 }
2197
createUserDefined()2198 void SfxDocumentMetaData::createUserDefined()
2199 {
2200 // user-defined meta data: create PropertyBag which only accepts property
2201 // values of allowed types
2202 if ( !m_xUserDefined.is() )
2203 {
2204 css::uno::Sequence<css::uno::Type> types(11);
2205 types[0] = ::cppu::UnoType<bool>::get();
2206 types[1] = ::cppu::UnoType< ::rtl::OUString>::get();
2207 types[2] = ::cppu::UnoType<css::util::DateTime>::get();
2208 types[3] = ::cppu::UnoType<css::util::Date>::get();
2209 types[4] = ::cppu::UnoType<css::util::Duration>::get();
2210 types[5] = ::cppu::UnoType<float>::get();
2211 types[6] = ::cppu::UnoType<double>::get();
2212 types[7] = ::cppu::UnoType<sal_Int16>::get();
2213 types[8] = ::cppu::UnoType<sal_Int32>::get();
2214 types[9] = ::cppu::UnoType<sal_Int64>::get();
2215 // Time is supported for backward compatibility with OOo 3.x, x<=2
2216 types[10] = ::cppu::UnoType<css::util::Time>::get();
2217 css::uno::Sequence<css::uno::Any> args(2);
2218 args[0] <<= css::beans::NamedValue(
2219 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AllowedTypes")),
2220 css::uno::makeAny(types));
2221 // #i94175#: ODF allows empty user-defined property names!
2222 args[1] <<= css::beans::NamedValue( ::rtl::OUString(
2223 RTL_CONSTASCII_USTRINGPARAM("AllowEmptyPropertyName")),
2224 css::uno::makeAny(sal_True));
2225
2226 const css::uno::Reference<css::lang::XMultiComponentFactory> xMsf(
2227 m_xContext->getServiceManager());
2228 m_xUserDefined.set(
2229 xMsf->createInstanceWithContext(
2230 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2231 "com.sun.star.beans.PropertyBag")), m_xContext),
2232 css::uno::UNO_QUERY_THROW);
2233 const css::uno::Reference<css::lang::XInitialization> xInit(
2234 m_xUserDefined, css::uno::UNO_QUERY);
2235 if (xInit.is()) {
2236 xInit->initialize(args);
2237 }
2238
2239 const css::uno::Reference<css::util::XModifyBroadcaster> xMB(
2240 m_xUserDefined, css::uno::UNO_QUERY);
2241 if (xMB.is())
2242 {
2243 const css::uno::Sequence<css::uno::Reference<css::uno::XInterface> >
2244 listeners(m_NotifyListeners.getElements());
2245 for (css::uno::Reference< css::uno::XInterface > const * iter =
2246 ::comphelper::stl_begin(listeners);
2247 iter != ::comphelper::stl_end(listeners); ++iter) {
2248 xMB->addModifyListener(
2249 css::uno::Reference< css::util::XModifyListener >(*iter,
2250 css::uno::UNO_QUERY));
2251 }
2252 }
2253 }
2254 }
2255
2256 } // closing anonymous implementation namespace
2257
2258
2259 // component helper namespace
2260 namespace comp_SfxDocumentMetaData {
2261
_getImplementationName()2262 ::rtl::OUString SAL_CALL _getImplementationName() {
2263 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2264 "SfxDocumentMetaData"));
2265 }
2266
_getSupportedServiceNames()2267 css::uno::Sequence< ::rtl::OUString > SAL_CALL _getSupportedServiceNames()
2268 {
2269 css::uno::Sequence< ::rtl::OUString > s(1);
2270 s[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
2271 "com.sun.star.document.DocumentProperties"));
2272 return s;
2273 }
2274
_create(const css::uno::Reference<css::uno::XComponentContext> & context)2275 css::uno::Reference< css::uno::XInterface > SAL_CALL _create(
2276 const css::uno::Reference< css::uno::XComponentContext > & context)
2277 {
2278 return static_cast< ::cppu::OWeakObject * >
2279 (new SfxDocumentMetaData(context));
2280 }
2281
2282 } // closing component helper namespace
2283
2284 static ::cppu::ImplementationEntry const entries[] = {
2285 { &comp_SfxDocumentMetaData::_create,
2286 &comp_SfxDocumentMetaData::_getImplementationName,
2287 &comp_SfxDocumentMetaData::_getSupportedServiceNames,
2288 &::cppu::createSingleComponentFactory, 0, 0 },
2289 { 0, 0, 0, 0, 0, 0 }
2290 };
2291
2292 #if 0
2293 extern "C" void SAL_CALL component_getImplementationEnvironment(
2294 const char ** envTypeName, uno_Environment **)
2295 {
2296 *envTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
2297 }
2298
2299 extern "C" void * SAL_CALL component_getFactory(
2300 const char * implName, void * serviceManager, void * registryKey)
2301 {
2302 return ::cppu::component_getFactoryHelper(
2303 implName, serviceManager, registryKey, entries);
2304 }
2305 #endif
2306