summaryrefslogtreecommitdiff
path: root/sfx2/source/doc/SfxDocumentMetaData.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sfx2/source/doc/SfxDocumentMetaData.cxx')
-rw-r--r--sfx2/source/doc/SfxDocumentMetaData.cxx2391
1 files changed, 2391 insertions, 0 deletions
diff --git a/sfx2/source/doc/SfxDocumentMetaData.cxx b/sfx2/source/doc/SfxDocumentMetaData.cxx
new file mode 100644
index 000000000000..14474dd2904d
--- /dev/null
+++ b/sfx2/source/doc/SfxDocumentMetaData.cxx
@@ -0,0 +1,2391 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include "precompiled_sfx2.hxx"
+
+#include "sal/config.h"
+#include "cppuhelper/factory.hxx"
+#include "cppuhelper/implementationentry.hxx"
+#include "cppuhelper/compbase6.hxx"
+#include "com/sun/star/lang/XServiceInfo.hpp"
+#include "com/sun/star/document/XDocumentProperties.hpp"
+#include "com/sun/star/lang/XInitialization.hpp"
+#include "com/sun/star/util/XCloneable.hpp"
+#include "com/sun/star/util/XModifiable.hpp"
+#include "com/sun/star/xml/sax/XSAXSerializable.hpp"
+
+#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
+#include "com/sun/star/lang/EventObject.hpp"
+#include "com/sun/star/beans/XPropertySet.hpp"
+#include "com/sun/star/beans/XPropertySetInfo.hpp"
+#include "com/sun/star/beans/PropertyAttribute.hpp"
+#include "com/sun/star/task/ErrorCodeIOException.hpp"
+#include "com/sun/star/embed/XStorage.hpp"
+#include "com/sun/star/embed/XTransactedObject.hpp"
+#include "com/sun/star/embed/ElementModes.hpp"
+#include "com/sun/star/io/XActiveDataControl.hpp"
+#include "com/sun/star/io/XActiveDataSource.hpp"
+#include "com/sun/star/io/XStream.hpp"
+#include "com/sun/star/document/XImporter.hpp"
+#include "com/sun/star/document/XExporter.hpp"
+#include "com/sun/star/document/XFilter.hpp"
+#include "com/sun/star/xml/sax/XParser.hpp"
+#include "com/sun/star/xml/dom/XDocument.hpp"
+#include "com/sun/star/xml/dom/XElement.hpp"
+#include "com/sun/star/xml/dom/XDocumentBuilder.hpp"
+#include "com/sun/star/xml/dom/XSAXDocumentBuilder.hpp"
+#include "com/sun/star/xml/dom/NodeType.hpp"
+#include "com/sun/star/xml/xpath/XXPathAPI.hpp"
+#include "com/sun/star/util/Date.hpp"
+#include "com/sun/star/util/Time.hpp"
+#include "com/sun/star/util/Duration.hpp"
+
+#include "SfxDocumentMetaData.hxx"
+#include "rtl/ustrbuf.hxx"
+#include "tools/debug.hxx"
+#include "tools/string.hxx" // for DBG
+#include "tools/datetime.hxx"
+#include "tools/urlobj.hxx"
+#include "osl/mutex.hxx"
+#include "cppuhelper/basemutex.hxx"
+#include "cppuhelper/interfacecontainer.hxx"
+#include "comphelper/storagehelper.hxx"
+#include "comphelper/mediadescriptor.hxx"
+#include "comphelper/sequenceasvector.hxx"
+#include "comphelper/stlunosequence.hxx"
+#include "sot/storage.hxx"
+#include "sfx2/docfile.hxx"
+#include "sax/tools/converter.hxx"
+
+#include <utility>
+#include <vector>
+#include <map>
+#include <cstring>
+#include <limits>
+
+/**
+ * This file contains the implementation of the service
+ * com.sun.star.document.DocumentProperties.
+ * This service enables access to the meta-data stored in documents.
+ * Currently, this service only handles documents in ODF format.
+ *
+ * The implementation uses an XML DOM to store the properties.
+ * This approach was taken because it allows for preserving arbitrary XML data
+ * in loaded documents, which will be stored unmodified when saving the
+ * document again.
+ *
+ * Upon access, some properties are directly read from and updated in the DOM.
+ * Exception: it seems impossible to get notified upon addition of a property
+ * to a com.sun.star.beans.PropertyBag, which is used for storing user-defined
+ * properties; because of this, user-defined properties are updated in the
+ * XML DOM only when storing the document.
+ * Exception 2: when setting certain properties which correspond to attributes
+ * in the XML DOM, we want to remove the corresponding XML element. Detecting
+ * this condition can get messy, so we store all such properties as members,
+ * and update the DOM tree only when storing the document (in
+ * <method>updateUserDefinedAndAttributes</method>).
+ *
+ * @author mst
+ */
+
+/// anonymous implementation namespace
+namespace {
+
+namespace css = ::com::sun::star;
+
+
+/// a list of attribute-lists, where attribute means name and content
+typedef std::vector<std::vector<std::pair<const char*, ::rtl::OUString> > >
+ AttrVector;
+
+typedef ::cppu::WeakComponentImplHelper6<
+ css::lang::XServiceInfo,
+ css::document::XDocumentProperties,
+ css::lang::XInitialization,
+ css::util::XCloneable,
+ css::util::XModifiable,
+ css::xml::sax::XSAXSerializable>
+ SfxDocumentMetaData_Base;
+
+class SfxDocumentMetaData:
+ private ::cppu::BaseMutex,
+ public SfxDocumentMetaData_Base
+{
+public:
+ explicit SfxDocumentMetaData(
+ css::uno::Reference< css::uno::XComponentContext > const & context);
+
+ // ::com::sun::star::lang::XServiceInfo:
+ virtual ::rtl::OUString SAL_CALL getImplementationName()
+ throw (css::uno::RuntimeException);
+ virtual ::sal_Bool SAL_CALL supportsService(
+ const ::rtl::OUString & ServiceName) throw (css::uno::RuntimeException);
+ virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL
+ getSupportedServiceNames() throw (css::uno::RuntimeException);
+
+ // ::com::sun::star::lang::XComponent:
+ virtual void SAL_CALL dispose() throw (css::uno::RuntimeException);
+
+ // ::com::sun::star::document::XDocumentProperties:
+ virtual ::rtl::OUString SAL_CALL getAuthor()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setAuthor(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getGenerator()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setGenerator(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual css::util::DateTime SAL_CALL getCreationDate()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setCreationDate(const css::util::DateTime & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getTitle()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setTitle(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getSubject()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setSubject(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getDescription()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setDescription(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual css::uno::Sequence< ::rtl::OUString > SAL_CALL getKeywords()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setKeywords(
+ const css::uno::Sequence< ::rtl::OUString > & the_value)
+ throw (css::uno::RuntimeException);
+ virtual css::lang::Locale SAL_CALL getLanguage()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setLanguage(const css::lang::Locale & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getModifiedBy()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setModifiedBy(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual css::util::DateTime SAL_CALL getModificationDate()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setModificationDate(
+ const css::util::DateTime & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getPrintedBy()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setPrintedBy(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual css::util::DateTime SAL_CALL getPrintDate()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setPrintDate(const css::util::DateTime & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getTemplateName()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setTemplateName(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getTemplateURL()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setTemplateURL(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual css::util::DateTime SAL_CALL getTemplateDate()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setTemplateDate(const css::util::DateTime & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::rtl::OUString SAL_CALL getAutoloadURL()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setAutoloadURL(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::sal_Int32 SAL_CALL getAutoloadSecs()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setAutoloadSecs(::sal_Int32 the_value)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException);
+ virtual ::rtl::OUString SAL_CALL getDefaultTarget()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setDefaultTarget(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual css::uno::Sequence< css::beans::NamedValue > SAL_CALL
+ getDocumentStatistics() throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setDocumentStatistics(
+ const css::uno::Sequence< css::beans::NamedValue > & the_value)
+ throw (css::uno::RuntimeException);
+ virtual ::sal_Int16 SAL_CALL getEditingCycles()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setEditingCycles(::sal_Int16 the_value)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException);
+ virtual ::sal_Int32 SAL_CALL getEditingDuration()
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setEditingDuration(::sal_Int32 the_value)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException);
+ virtual void SAL_CALL resetUserData(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException);
+ virtual css::uno::Reference< css::beans::XPropertyContainer > SAL_CALL
+ getUserDefinedProperties() throw (css::uno::RuntimeException);
+ virtual void SAL_CALL loadFromStorage(
+ const css::uno::Reference< css::embed::XStorage > & Storage,
+ const css::uno::Sequence< css::beans::PropertyValue > & Medium)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException,
+ css::io::WrongFormatException,
+ css::lang::WrappedTargetException, css::io::IOException);
+ virtual void SAL_CALL loadFromMedium(const ::rtl::OUString & URL,
+ const css::uno::Sequence< css::beans::PropertyValue > & Medium)
+ throw (css::uno::RuntimeException,
+ css::io::WrongFormatException,
+ css::lang::WrappedTargetException, css::io::IOException);
+ virtual void SAL_CALL storeToStorage(
+ const css::uno::Reference< css::embed::XStorage > & Storage,
+ const css::uno::Sequence< css::beans::PropertyValue > & Medium)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException,
+ css::lang::WrappedTargetException, css::io::IOException);
+ virtual void SAL_CALL storeToMedium(const ::rtl::OUString & URL,
+ const css::uno::Sequence< css::beans::PropertyValue > & Medium)
+ throw (css::uno::RuntimeException,
+ css::lang::WrappedTargetException, css::io::IOException);
+
+ // ::com::sun::star::lang::XInitialization:
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence< css::uno::Any > & aArguments)
+ throw (css::uno::RuntimeException, css::uno::Exception);
+
+ // ::com::sun::star::util::XCloneable:
+ virtual css::uno::Reference<css::util::XCloneable> SAL_CALL createClone()
+ throw (css::uno::RuntimeException);
+
+ // ::com::sun::star::util::XModifiable:
+ virtual ::sal_Bool SAL_CALL isModified( )
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL setModified( ::sal_Bool bModified )
+ throw (css::beans::PropertyVetoException, css::uno::RuntimeException);
+
+ // ::com::sun::star::util::XModifyBroadcaster:
+ virtual void SAL_CALL addModifyListener(
+ const css::uno::Reference< css::util::XModifyListener > & xListener)
+ throw (css::uno::RuntimeException);
+ virtual void SAL_CALL removeModifyListener(
+ const css::uno::Reference< css::util::XModifyListener > & xListener)
+ throw (css::uno::RuntimeException);
+
+ // ::com::sun::star::xml::sax::XSAXSerializable
+ virtual void SAL_CALL serialize(
+ const css::uno::Reference<css::xml::sax::XDocumentHandler>& i_xHandler,
+ const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces)
+ throw (css::uno::RuntimeException, css::xml::sax::SAXException);
+
+private:
+ SfxDocumentMetaData(SfxDocumentMetaData &); // not defined
+ SfxDocumentMetaData& operator =(SfxDocumentMetaData &); // not defined
+
+ virtual ~SfxDocumentMetaData() {}
+
+ const css::uno::Reference< css::uno::XComponentContext > m_xContext;
+
+ /// for notification
+ ::cppu::OInterfaceContainerHelper m_NotifyListeners;
+ /// flag: false means not initialized yet, or disposed
+ bool m_isInitialized;
+ /// flag
+ bool m_isModified;
+ /// meta-data DOM tree
+ css::uno::Reference< css::xml::dom::XDocument > m_xDoc;
+ /// meta-data super node in the meta-data DOM tree
+ css::uno::Reference< css::xml::dom::XNode> m_xParent;
+ /// standard meta data (single occurrence)
+ std::map< ::rtl::OUString, css::uno::Reference<css::xml::dom::XNode> >
+ m_meta;
+ /// standard meta data (multiple occurrences)
+ std::map< ::rtl::OUString,
+ std::vector<css::uno::Reference<css::xml::dom::XNode> > > m_metaList;
+ /// user-defined meta data (meta:user-defined) @ATTENTION may be null!
+ css::uno::Reference<css::beans::XPropertyContainer> m_xUserDefined;
+ // now for some meta-data attributes; these are not updated directly in the
+ // DOM because updates (detecting "empty" elements) would be quite messy
+ ::rtl::OUString m_TemplateName;
+ ::rtl::OUString m_TemplateURL;
+ css::util::DateTime m_TemplateDate;
+ ::rtl::OUString m_AutoloadURL;
+ sal_Int32 m_AutoloadSecs;
+ ::rtl::OUString m_DefaultTarget;
+
+ /// check if we are initialized properly
+ void SAL_CALL checkInit() const;
+ // throw (css::uno::RuntimeException);
+ /// initialize state from given DOM tree
+ void SAL_CALL init(css::uno::Reference<css::xml::dom::XDocument> i_xDom);
+ // throw (css::uno::RuntimeException, css::io::WrongFormatException,
+ // css::uno::Exception);
+ /// update element in DOM tree
+ void SAL_CALL updateElement(const char *i_name,
+ std::vector<std::pair<const char *, ::rtl::OUString> >* i_pAttrs = 0);
+ /// update user-defined meta data and attributes in DOM tree
+ void SAL_CALL updateUserDefinedAndAttributes();
+ /// create empty DOM tree (XDocument)
+ css::uno::Reference<css::xml::dom::XDocument> SAL_CALL createDOM() const;
+ /// extract base URL (necessary for converting relative links)
+ css::uno::Reference<css::beans::XPropertySet> SAL_CALL getURLProperties(
+ const css::uno::Sequence<css::beans::PropertyValue> & i_rMedium) const;
+ // throw (css::uno::RuntimeException);
+ /// get text of standard meta data element
+ ::rtl::OUString SAL_CALL getMetaText(const char* i_name) const;
+ // throw (css::uno::RuntimeException);
+ /// set text of standard meta data element iff not equal to existing text
+ bool SAL_CALL setMetaText(const char* i_name,
+ const ::rtl::OUString & i_rValue);
+ // throw (css::uno::RuntimeException);
+ /// set text of standard meta data element iff not equal to existing text
+ void SAL_CALL setMetaTextAndNotify(const char* i_name,
+ const ::rtl::OUString & i_rValue);
+ // throw (css::uno::RuntimeException);
+ /// get text of standard meta data element's attribute
+ ::rtl::OUString SAL_CALL getMetaAttr(const char* i_name,
+ const char* i_attr) const;
+ // throw (css::uno::RuntimeException);
+ /// get text of a list of standard meta data elements (multiple occ.)
+ css::uno::Sequence< ::rtl::OUString > SAL_CALL getMetaList(
+ const char* i_name) const;
+ // throw (css::uno::RuntimeException);
+ /// set text of a list of standard meta data elements (multiple occ.)
+ bool SAL_CALL setMetaList(const char* i_name,
+ const css::uno::Sequence< ::rtl::OUString > & i_rValue,
+ AttrVector const* = 0);
+ // throw (css::uno::RuntimeException);
+ void createUserDefined();
+};
+
+////////////////////////////////////////////////////////////////////////////
+
+bool operator== (const css::util::DateTime &i_rLeft,
+ const css::util::DateTime &i_rRight)
+{
+ return i_rLeft.Year == i_rRight.Year
+ && i_rLeft.Month == i_rRight.Month
+ && i_rLeft.Day == i_rRight.Day
+ && i_rLeft.Hours == i_rRight.Hours
+ && i_rLeft.Minutes == i_rRight.Minutes
+ && i_rLeft.Seconds == i_rRight.Seconds
+ && i_rLeft.HundredthSeconds == i_rRight.HundredthSeconds;
+}
+
+// NB: keep these two arrays in sync!
+const char* s_stdStatAttrs[] = {
+ "meta:page-count",
+ "meta:table-count",
+ "meta:draw-count",
+ "meta:image-count",
+ "meta:object-count",
+ "meta:ole-object-count",
+ "meta:paragraph-count",
+ "meta:word-count",
+ "meta:character-count",
+ "meta:row-count",
+ "meta:frame-count",
+ "meta:sentence-count",
+ "meta:syllable-count",
+ "meta:non-whitespace-character-count",
+ "meta:cell-count",
+ 0
+};
+
+// NB: keep these two arrays in sync!
+const char* s_stdStats[] = {
+ "PageCount",
+ "TableCount",
+ "DrawCount",
+ "ImageCount",
+ "ObjectCount",
+ "OLEObjectCount",
+ "ParagraphCount",
+ "WordCount",
+ "CharacterCount",
+ "RowCount",
+ "FrameCount",
+ "SentenceCount",
+ "SyllableCount",
+ "NonWhitespaceCharacterCount",
+ "CellCount",
+ 0
+};
+
+const char* s_stdMeta[] = {
+ "meta:generator", // string
+ "dc:title", // string
+ "dc:description", // string
+ "dc:subject", // string
+ "meta:initial-creator", // string
+ "dc:creator", // string
+ "meta:printed-by", // string
+ "meta:creation-date", // dateTime
+ "dc:date", // dateTime
+ "meta:print-date", // dateTime
+ "meta:template", // XLink
+ "meta:auto-reload", // ...
+ "meta:hyperlink-behaviour", // ...
+ "dc:language", // language
+ "meta:editing-cycles", // nonNegativeInteger
+ "meta:editing-duration", // duration
+ "meta:document-statistic", // ... // note: statistic is singular, no s!
+ 0
+};
+
+const char* s_stdMetaList[] = {
+ "meta:keyword", // string*
+ "meta:user-defined", // ...*
+ 0
+};
+
+const char* s_nsXLink = "http://www.w3.org/1999/xlink";
+const char* s_nsDC = "http://purl.org/dc/elements/1.1/";
+const char* s_nsODF = "urn:oasis:names:tc:opendocument:xmlns:office:1.0";
+const char* s_nsODFMeta = "urn:oasis:names:tc:opendocument:xmlns:meta:1.0";
+// const char* s_nsOOo = "http://openoffice.org/2004/office"; // not used (yet?)
+
+const char* s_metaXml = "meta.xml";
+
+
+bool isValidDate(const css::util::Date & i_rDate)
+{
+ return i_rDate.Month > 0;
+}
+
+bool isValidDateTime(const css::util::DateTime & i_rDateTime)
+{
+ return i_rDateTime.Month > 0;
+}
+
+std::pair< ::rtl::OUString, ::rtl::OUString > SAL_CALL
+getQualifier(const char* i_name) {
+ ::rtl::OUString nm = ::rtl::OUString::createFromAscii(i_name);
+ sal_Int32 ix = nm.indexOf(static_cast<sal_Unicode> (':'));
+ if (ix == -1) {
+ return std::make_pair(::rtl::OUString(), nm);
+ } else {
+ return std::make_pair(nm.copy(0,ix), nm.copy(ix+1));
+ }
+}
+
+// get namespace for standard qualified names
+// NB: only call this with statically known strings!
+::rtl::OUString SAL_CALL getNameSpace(const char* i_qname) throw ()
+{
+ DBG_ASSERT(i_qname, "SfxDocumentMetaData: getNameSpace: argument is null");
+ const char * ns = "";
+ ::rtl::OUString n = getQualifier(i_qname).first;
+ if (n.equalsAscii("xlink" )) ns = s_nsXLink;
+ if (n.equalsAscii("dc" )) ns = s_nsDC;
+ if (n.equalsAscii("office")) ns = s_nsODF;
+ if (n.equalsAscii("meta" )) ns = s_nsODFMeta;
+ DBG_ASSERT(*ns, "SfxDocumentMetaData: unknown namespace prefix");
+ return ::rtl::OUString::createFromAscii(ns);
+}
+
+bool SAL_CALL
+textToDateOrDateTime(css::util::Date & io_rd, css::util::DateTime & io_rdt,
+ bool & o_rIsDateTime, ::rtl::OUString i_text) throw ()
+{
+ if (::sax::Converter::convertDateOrDateTime(
+ io_rd, io_rdt, o_rIsDateTime, i_text)) {
+ return true;
+ } else {
+ DBG_WARNING1("SfxDocumentMetaData: invalid date: %s",
+ OUStringToOString(i_text, RTL_TEXTENCODING_UTF8).getStr());
+ return false;
+ }
+}
+
+// convert string to date/time
+bool SAL_CALL
+textToDateTime(css::util::DateTime & io_rdt, ::rtl::OUString i_text) throw ()
+{
+ if (::sax::Converter::convertDateTime(io_rdt, i_text)) {
+ return true;
+ } else {
+ DBG_WARNING1("SfxDocumentMetaData: invalid date: %s",
+ OUStringToOString(i_text, RTL_TEXTENCODING_UTF8).getStr());
+ return false;
+ }
+}
+
+// convert string to date/time with default return value
+css::util::DateTime SAL_CALL
+textToDateTimeDefault(::rtl::OUString i_text) throw ()
+{
+ css::util::DateTime dt;
+ static_cast<void> (textToDateTime(dt, i_text));
+ // on conversion error: return default value (unchanged)
+ return dt;
+}
+
+// convert date to string
+::rtl::OUString SAL_CALL
+dateToText(css::util::Date const& i_rd) throw ()
+{
+ if (isValidDate(i_rd)) {
+ ::rtl::OUStringBuffer buf;
+ ::sax::Converter::convertDate(buf, i_rd);
+ return buf.makeStringAndClear();
+ } else {
+ return ::rtl::OUString();
+ }
+}
+
+
+// convert date/time to string
+::rtl::OUString SAL_CALL
+dateTimeToText(css::util::DateTime const& i_rdt) throw ()
+{
+ if (isValidDateTime(i_rdt)) {
+ ::rtl::OUStringBuffer buf;
+ ::sax::Converter::convertDateTime(buf, i_rdt, true);
+ return buf.makeStringAndClear();
+ } else {
+ return ::rtl::OUString();
+ }
+}
+
+// convert string to duration
+bool
+textToDuration(css::util::Duration& io_rDur, ::rtl::OUString const& i_rText)
+throw ()
+{
+ if (::sax::Converter::convertDuration(io_rDur, i_rText)) {
+ return true;
+ } else {
+ DBG_WARNING1("SfxDocumentMetaData: invalid duration: %s",
+ OUStringToOString(i_rText, RTL_TEXTENCODING_UTF8).getStr());
+ return false;
+ }
+}
+
+sal_Int32 textToDuration(::rtl::OUString const& i_rText) throw ()
+{
+ css::util::Duration d;
+ if (textToDuration(d, i_rText)) {
+ // #i107372#: approximate years/months
+ const sal_Int32 days( (d.Years * 365) + (d.Months * 30) + d.Days );
+ return (days * (24*3600))
+ + (d.Hours * 3600) + (d.Minutes * 60) + d.Seconds;
+ } else {
+ return 0; // default
+ }
+}
+
+// convert duration to string
+::rtl::OUString durationToText(css::util::Duration const& i_rDur) throw ()
+{
+ ::rtl::OUStringBuffer buf;
+ ::sax::Converter::convertDuration(buf, i_rDur);
+ return buf.makeStringAndClear();
+}
+
+// convert duration to string
+::rtl::OUString SAL_CALL durationToText(sal_Int32 i_value) throw ()
+{
+ css::util::Duration ud;
+ ud.Days = static_cast<sal_Int16>(i_value / (24 * 3600));
+ ud.Hours = static_cast<sal_Int16>((i_value % (24 * 3600)) / 3600);
+ ud.Minutes = static_cast<sal_Int16>((i_value % 3600) / 60);
+ ud.Seconds = static_cast<sal_Int16>(i_value % 60);
+ ud.MilliSeconds = 0;
+ return durationToText(ud);
+}
+
+// extract base URL (necessary for converting relative links)
+css::uno::Reference< css::beans::XPropertySet > SAL_CALL
+SfxDocumentMetaData::getURLProperties(
+ const css::uno::Sequence< css::beans::PropertyValue > & i_rMedium) const
+{
+ css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
+ m_xContext->getServiceManager());
+ css::uno::Reference< css::beans::XPropertyContainer> xPropArg(
+ xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii(
+ "com.sun.star.beans.PropertyBag"), m_xContext),
+ css::uno::UNO_QUERY_THROW);
+ try {
+ ::rtl::OUString dburl =
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("DocumentBaseURL"));
+ ::rtl::OUString hdn =
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("HierarchicalDocumentName"));
+ for (sal_Int32 i = 0; i < i_rMedium.getLength(); ++i) {
+ if (i_rMedium[i].Name.equals(dburl)) {
+ xPropArg->addProperty(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI")),
+ css::beans::PropertyAttribute::MAYBEVOID,
+ i_rMedium[i].Value);
+ } else if (i_rMedium[i].Name.equals(hdn)) {
+ xPropArg->addProperty(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StreamRelPath")),
+ css::beans::PropertyAttribute::MAYBEVOID,
+ i_rMedium[i].Value);
+ }
+ }
+ xPropArg->addProperty(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StreamName")),
+ css::beans::PropertyAttribute::MAYBEVOID,
+ css::uno::makeAny(::rtl::OUString::createFromAscii(s_metaXml)));
+ } catch (css::uno::Exception &) {
+ // ignore
+ }
+ return css::uno::Reference< css::beans::XPropertySet>(xPropArg,
+ css::uno::UNO_QUERY_THROW);
+}
+
+// return the text of the (hopefully unique, i.e., normalize first!) text
+// node _below_ the given node
+::rtl::OUString SAL_CALL
+getNodeText(css::uno::Reference<css::xml::dom::XNode> i_xNode)
+ throw (css::uno::RuntimeException)
+{
+ if (!i_xNode.is()) throw css::uno::RuntimeException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::getNodeText: argument is null"), i_xNode);
+ for (css::uno::Reference<css::xml::dom::XNode> c = i_xNode->getFirstChild();
+ c.is();
+ c = c->getNextSibling()) {
+ if (c->getNodeType() == css::xml::dom::NodeType_TEXT_NODE) {
+ try {
+ return c->getNodeValue();
+ } catch (css::xml::dom::DOMException &) { // too big?
+ return ::rtl::OUString();
+ }
+ }
+ }
+ return ::rtl::OUString();
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getMetaText(const char* i_name) const
+// throw (css::uno::RuntimeException)
+{
+ checkInit();
+
+ const ::rtl::OUString name( ::rtl::OUString::createFromAscii(i_name) );
+ DBG_ASSERT(m_meta.find(name) != m_meta.end(),
+ "SfxDocumentMetaData::getMetaText: not found");
+ css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second;
+ return (xNode.is()) ? getNodeText(xNode) : ::rtl::OUString();
+}
+
+bool SAL_CALL
+SfxDocumentMetaData::setMetaText(const char* i_name,
+ const ::rtl::OUString & i_rValue)
+ // throw (css::uno::RuntimeException)
+{
+ checkInit();
+
+ const ::rtl::OUString name( ::rtl::OUString::createFromAscii(i_name) );
+ DBG_ASSERT(m_meta.find(name) != m_meta.end(),
+ "SfxDocumentMetaData::setMetaText: not found");
+ css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second;
+
+ try {
+ if (i_rValue.equalsAscii("")) {
+ if (xNode.is()) { // delete
+ m_xParent->removeChild(xNode);
+ xNode.clear();
+ m_meta[name] = xNode;
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ if (xNode.is()) { // update
+ for (css::uno::Reference<css::xml::dom::XNode> c =
+ xNode->getFirstChild();
+ c.is();
+ c = c->getNextSibling()) {
+ if (c->getNodeType() == css::xml::dom::NodeType_TEXT_NODE) {
+ if (!c->getNodeValue().equals(i_rValue)) {
+ c->setNodeValue(i_rValue);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ } else { // insert
+ xNode.set(m_xDoc->createElementNS(getNameSpace(i_name), name),
+ css::uno::UNO_QUERY_THROW);
+ m_xParent->appendChild(xNode);
+ m_meta[name] = xNode;
+ }
+ css::uno::Reference<css::xml::dom::XNode> xTextNode(
+ m_xDoc->createTextNode(i_rValue), css::uno::UNO_QUERY_THROW);
+ xNode->appendChild(xTextNode);
+ return true;
+ }
+ } catch (css::xml::dom::DOMException & e) {
+ css::uno::Any a(e);
+ throw css::lang::WrappedTargetRuntimeException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::setMetaText: DOM exception"),
+ css::uno::Reference<css::uno::XInterface>(*this), a);
+ }
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setMetaTextAndNotify(const char* i_name,
+ const ::rtl::OUString & i_rValue)
+ // throw (css::uno::RuntimeException)
+{
+ ::osl::ClearableMutexGuard g(m_aMutex);
+ if (setMetaText(i_name, i_rValue)) {
+ g.clear();
+ setModified(true);
+ }
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getMetaAttr(const char* i_name, const char* i_attr) const
+// throw (css::uno::RuntimeException)
+{
+// checkInit();
+ ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name);
+ DBG_ASSERT(m_meta.find(name) != m_meta.end(),
+ "SfxDocumentMetaData::getMetaAttr: not found");
+ css::uno::Reference<css::xml::dom::XNode> xNode = m_meta.find(name)->second;
+ if (xNode.is()) {
+ css::uno::Reference<css::xml::dom::XElement> xElem(xNode,
+ css::uno::UNO_QUERY_THROW);
+ return xElem->getAttributeNS(getNameSpace(i_attr),
+ getQualifier(i_attr).second);
+ } else {
+ return ::rtl::OUString();
+ }
+}
+
+css::uno::Sequence< ::rtl::OUString> SAL_CALL
+SfxDocumentMetaData::getMetaList(const char* i_name) const
+// throw (css::uno::RuntimeException)
+{
+ checkInit();
+ ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name);
+ DBG_ASSERT(m_metaList.find(name) != m_metaList.end(),
+ "SfxDocumentMetaData::getMetaList: not found");
+ std::vector<css::uno::Reference<css::xml::dom::XNode> > const & vec =
+ m_metaList.find(name)->second;
+ css::uno::Sequence< ::rtl::OUString> ret(vec.size());
+ for (size_t i = 0; i < vec.size(); ++i) {
+ ret[i] = getNodeText(vec.at(i));
+ }
+ return ret;
+}
+
+bool SAL_CALL
+SfxDocumentMetaData::setMetaList(const char* i_name,
+ const css::uno::Sequence< ::rtl::OUString> & i_rValue,
+ AttrVector const* i_pAttrs)
+ // throw (css::uno::RuntimeException)
+{
+ checkInit();
+ DBG_ASSERT((i_pAttrs == 0) ||
+ (static_cast<size_t>(i_rValue.getLength()) == i_pAttrs->size()),
+ "SfxDocumentMetaData::setMetaList: invalid args");
+
+ try {
+ ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name);
+ DBG_ASSERT(m_metaList.find(name) != m_metaList.end(),
+ "SfxDocumentMetaData::setMetaList: not found");
+ std::vector<css::uno::Reference<css::xml::dom::XNode> > & vec =
+ m_metaList[name];
+
+ // if nothing changed, do nothing
+ // alas, this does not check for permutations, or attributes...
+ if ((0 == i_pAttrs)) {
+ if (static_cast<size_t>(i_rValue.getLength()) == vec.size()) {
+ bool isEqual(true);
+ for (sal_Int32 i = 0; i < i_rValue.getLength(); ++i) {
+ css::uno::Reference<css::xml::dom::XNode> xNode(vec.at(i));
+ if (xNode.is()) {
+ ::rtl::OUString val = getNodeText(xNode);
+ if (!val.equals(i_rValue[i])) {
+ isEqual = false;
+ break;
+ }
+ }
+ }
+ if (isEqual) return false;
+ }
+ }
+
+ // remove old meta data nodes
+ {
+ std::vector<css::uno::Reference<css::xml::dom::XNode> >
+ ::reverse_iterator it(vec.rbegin());
+ try {
+ for ( ;it != vec.rend(); ++it)
+ {
+ m_xParent->removeChild(*it);
+ }
+ }
+ catch (...)
+ {
+ // Clean up already removed nodes
+ vec.erase(it.base(), vec.end());
+ throw;
+ }
+ vec.clear();
+ }
+
+ // insert new meta data nodes into DOM tree
+ for (sal_Int32 i = 0; i < i_rValue.getLength(); ++i) {
+ css::uno::Reference<css::xml::dom::XElement> xElem(
+ m_xDoc->createElementNS(getNameSpace(i_name), name),
+ css::uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::xml::dom::XNode> xNode(xElem,
+ css::uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::xml::dom::XNode> xTextNode(
+ m_xDoc->createTextNode(i_rValue[i]), css::uno::UNO_QUERY_THROW);
+ // set attributes
+ if (i_pAttrs != 0) {
+ for (std::vector<std::pair<const char*, ::rtl::OUString> >
+ ::const_iterator it = (*i_pAttrs)[i].begin();
+ it != (*i_pAttrs)[i].end(); ++it) {
+ xElem->setAttributeNS(getNameSpace(it->first),
+ ::rtl::OUString::createFromAscii(it->first),
+ it->second);
+ }
+ }
+ xNode->appendChild(xTextNode);
+ m_xParent->appendChild(xNode);
+ vec.push_back(xNode);
+ }
+
+ return true;
+ } catch (css::xml::dom::DOMException & e) {
+ css::uno::Any a(e);
+ throw css::lang::WrappedTargetRuntimeException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::setMetaList: DOM exception"),
+ css::uno::Reference<css::uno::XInterface>(*this), a);
+ }
+}
+
+// convert property list to string list and attribute list
+std::pair<css::uno::Sequence< ::rtl::OUString>, AttrVector> SAL_CALL
+propsToStrings(css::uno::Reference<css::beans::XPropertySet> const & i_xPropSet)
+{
+ ::comphelper::SequenceAsVector< ::rtl::OUString > values;
+ AttrVector attrs;
+
+ css::uno::Reference<css::beans::XPropertySetInfo> xSetInfo
+ = i_xPropSet->getPropertySetInfo();
+ css::uno::Sequence<css::beans::Property> props = xSetInfo->getProperties();
+
+ for (sal_Int32 i = 0; i < props.getLength(); ++i) {
+ if (props[i].Attributes & css::beans::PropertyAttribute::TRANSIENT) {
+ continue;
+ }
+ const ::rtl::OUString name = props[i].Name;
+ css::uno::Any any;
+ try {
+ any = i_xPropSet->getPropertyValue(name);
+ } catch (css::uno::Exception &) {
+ // ignore
+ }
+ const css::uno::Type & type = any.getValueType();
+ std::vector<std::pair<const char*, ::rtl::OUString> > as;
+ as.push_back(std::make_pair(static_cast<const char*>("meta:name"),
+ name));
+ const char* vt = "meta:value-type";
+
+ // convert according to type
+ if (type == ::cppu::UnoType<bool>::get()) {
+ bool b = false;
+ any >>= b;
+ ::rtl::OUStringBuffer buf;
+ ::sax::Converter::convertBool(buf, b);
+ values.push_back(buf.makeStringAndClear());
+ as.push_back(std::make_pair(vt,
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("boolean"))));
+ } else if (type == ::cppu::UnoType< ::rtl::OUString>::get()) {
+ ::rtl::OUString s;
+ any >>= s;
+ values.push_back(s);
+// #i90847# OOo 2.x does stupid things if value-type="string";
+// fortunately string is default anyway, so we can just omit it
+// #i107502#: however, OOo 2.x only reads 4 user-defined without @value-type
+// => best backward compatibility: first 4 without @value-type, rest with
+ if (4 <= i)
+ {
+ as.push_back(std::make_pair(vt,
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("string"))));
+ }
+ } else if (type == ::cppu::UnoType<css::util::DateTime>::get()) {
+ css::util::DateTime dt;
+ any >>= dt;
+ values.push_back(dateTimeToText(dt));
+ as.push_back(std::make_pair(vt,
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("date"))));
+ } else if (type == ::cppu::UnoType<css::util::Date>::get()) {
+ css::util::Date d;
+ any >>= d;
+ values.push_back(dateToText(d));
+ as.push_back(std::make_pair(vt,
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("date"))));
+ } else if (type == ::cppu::UnoType<css::util::Time>::get()) {
+ // #i97029#: replaced by Duration
+ // Time is supported for backward compatibility with OOo 3.x, x<=2
+ css::util::Time ut;
+ any >>= ut;
+ css::util::Duration ud;
+ ud.Hours = ut.Hours;
+ ud.Minutes = ut.Minutes;
+ ud.Seconds = ut.Seconds;
+ ud.MilliSeconds = 10 * ut.HundredthSeconds;
+ values.push_back(durationToText(ud));
+ as.push_back(std::make_pair(vt,
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("time"))));
+ } else if (type == ::cppu::UnoType<css::util::Duration>::get()) {
+ css::util::Duration ud;
+ any >>= ud;
+ values.push_back(durationToText(ud));
+ as.push_back(std::make_pair(vt,
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("time"))));
+ } else if (::cppu::UnoType<double>::get().isAssignableFrom(type)) {
+ // support not just double, but anything that can be converted
+ double d = 0;
+ any >>= d;
+ ::rtl::OUStringBuffer buf;
+ ::sax::Converter::convertDouble(buf, d);
+ values.push_back(buf.makeStringAndClear());
+ as.push_back(std::make_pair(vt,
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("float"))));
+ } else {
+ DBG_WARNING1("SfxDocumentMetaData: unsupported property type: %s",
+ OUStringToOString(any.getValueTypeName(),
+ RTL_TEXTENCODING_UTF8).getStr());
+ continue;
+ }
+ attrs.push_back(as);
+ }
+
+ return std::make_pair(values.getAsConstList(), attrs);
+}
+
+// remove the given element from the DOM, and iff i_pAttrs != 0 insert new one
+void SAL_CALL
+SfxDocumentMetaData::updateElement(const char *i_name,
+ std::vector<std::pair<const char *, ::rtl::OUString> >* i_pAttrs)
+{
+ ::rtl::OUString name = ::rtl::OUString::createFromAscii(i_name);
+ try {
+ // remove old element
+ css::uno::Reference<css::xml::dom::XNode> xNode =
+ m_meta.find(name)->second;
+ if (xNode.is()) {
+ m_xParent->removeChild(xNode);
+ xNode.clear();
+ }
+ // add new element
+ if (0 != i_pAttrs) {
+ css::uno::Reference<css::xml::dom::XElement> xElem(
+ m_xDoc->createElementNS(getNameSpace(i_name), name),
+ css::uno::UNO_QUERY_THROW);
+ xNode.set(xElem, css::uno::UNO_QUERY_THROW);
+ // set attributes
+ for (std::vector<std::pair<const char *, ::rtl::OUString> >
+ ::const_iterator it = i_pAttrs->begin();
+ it != i_pAttrs->end(); ++it) {
+ xElem->setAttributeNS(getNameSpace(it->first),
+ ::rtl::OUString::createFromAscii(it->first), it->second);
+ }
+ m_xParent->appendChild(xNode);
+ }
+ m_meta[name] = xNode;
+ } catch (css::xml::dom::DOMException & e) {
+ css::uno::Any a(e);
+ throw css::lang::WrappedTargetRuntimeException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::updateElement: DOM exception"),
+ css::uno::Reference<css::uno::XInterface>(*this), a);
+ }
+}
+
+// update user-defined meta data in DOM tree
+void SAL_CALL SfxDocumentMetaData::updateUserDefinedAndAttributes()
+{
+ createUserDefined();
+ const css::uno::Reference<css::beans::XPropertySet> xPSet(m_xUserDefined,
+ css::uno::UNO_QUERY_THROW);
+ const std::pair<css::uno::Sequence< ::rtl::OUString>, AttrVector>
+ udStringsAttrs( propsToStrings(xPSet) );
+ (void) setMetaList("meta:user-defined", udStringsAttrs.first,
+ &udStringsAttrs.second);
+
+ // update elements with attributes
+ std::vector<std::pair<const char *, ::rtl::OUString> > attributes;
+ if (!m_TemplateName.equalsAscii("") || !m_TemplateURL.equalsAscii("")
+ || isValidDateTime(m_TemplateDate)) {
+ attributes.push_back(std::make_pair(
+ static_cast<const char*>("xlink:type"),
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("simple"))));
+ attributes.push_back(std::make_pair(
+ static_cast<const char*>("xlink:actuate"),
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("onRequest"))));
+ attributes.push_back(std::make_pair(
+ static_cast<const char*>("xlink:title"), m_TemplateName));
+ attributes.push_back(std::make_pair(
+ static_cast<const char*>("xlink:href" ), m_TemplateURL ));
+ if (isValidDateTime(m_TemplateDate)) {
+ attributes.push_back(std::make_pair(
+ static_cast<const char*>("meta:date" ),
+ dateTimeToText(m_TemplateDate)));
+ }
+ updateElement("meta:template", &attributes);
+ } else {
+ updateElement("meta:template");
+ }
+ attributes.clear();
+
+ if (!m_AutoloadURL.equalsAscii("") || (0 != m_AutoloadSecs)) {
+ attributes.push_back(std::make_pair(
+ static_cast<const char*>("xlink:href" ), m_AutoloadURL ));
+ attributes.push_back(std::make_pair(
+ static_cast<const char*>("meta:delay" ),
+ durationToText(m_AutoloadSecs)));
+ updateElement("meta:auto-reload", &attributes);
+ } else {
+ updateElement("meta:auto-reload");
+ }
+ attributes.clear();
+
+ if (!m_DefaultTarget.equalsAscii("")) {
+ attributes.push_back(std::make_pair(
+ static_cast<const char*>("office:target-frame-name"),
+ m_DefaultTarget));
+ // xlink:show: _blank -> new, any other value -> replace
+ const sal_Char* show = m_DefaultTarget.equalsAscii("_blank")
+ ? "new" : "replace";
+ attributes.push_back(std::make_pair(
+ static_cast<const char*>("xlink:show"),
+ ::rtl::OUString::createFromAscii(show)));
+ updateElement("meta:hyperlink-behaviour", &attributes);
+ } else {
+ updateElement("meta:hyperlink-behaviour");
+ }
+ attributes.clear();
+}
+
+// create empty DOM tree (XDocument)
+css::uno::Reference<css::xml::dom::XDocument> SAL_CALL
+SfxDocumentMetaData::createDOM() const // throw (css::uno::RuntimeException)
+{
+ css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
+ m_xContext->getServiceManager());
+ css::uno::Reference<css::xml::dom::XDocumentBuilder> xBuilder(
+ xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii(
+ "com.sun.star.xml.dom.DocumentBuilder"), m_xContext),
+ css::uno::UNO_QUERY_THROW );
+ if (!xBuilder.is()) throw css::uno::RuntimeException(
+ ::rtl::OUString::createFromAscii("SfxDocumentMetaData::createDOM: "
+ "cannot create DocumentBuilder service"),
+ *const_cast<SfxDocumentMetaData*>(this));
+ css::uno::Reference<css::xml::dom::XDocument> xDoc =
+ xBuilder->newDocument();
+ if (!xDoc.is()) throw css::uno::RuntimeException(
+ ::rtl::OUString::createFromAscii("SfxDocumentMetaData::createDOM: "
+ "cannot create new document"),
+ *const_cast<SfxDocumentMetaData*>(this));
+ return xDoc;
+}
+
+void SAL_CALL
+SfxDocumentMetaData::checkInit() const // throw (css::uno::RuntimeException)
+{
+ if (!m_isInitialized) {
+ throw css::uno::RuntimeException(::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::checkInit: not initialized"),
+ *const_cast<SfxDocumentMetaData*>(this));
+ }
+ DBG_ASSERT((m_xDoc.is() && m_xParent.is() ),
+ "SfxDocumentMetaData::checkInit: reference is null");
+}
+
+// initialize state from DOM tree
+void SAL_CALL SfxDocumentMetaData::init(
+ css::uno::Reference<css::xml::dom::XDocument> i_xDoc)
+// throw (css::uno::RuntimeException, css::io::WrongFormatException,
+// css::uno::Exception)
+{
+ if (!i_xDoc.is()) throw css::uno::RuntimeException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::init: no DOM tree given"), *this);
+
+ css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
+ m_xContext->getServiceManager());
+ css::uno::Reference<css::xml::xpath::XXPathAPI> xPath(
+ xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii(
+ "com.sun.star.xml.xpath.XPathAPI"), m_xContext),
+ css::uno::UNO_QUERY_THROW );
+ if (!xPath.is()) throw css::uno::RuntimeException(
+ ::rtl::OUString::createFromAscii("SfxDocumentMetaData::init:"
+ " cannot create XPathAPI service"), *this);
+
+ m_isInitialized = false;
+ m_xDoc = i_xDoc;
+ m_xDoc->normalize();
+
+ // select nodes for standard meta data stuff
+ xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("xlink")),
+ ::rtl::OUString::createFromAscii(s_nsXLink));
+ xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("dc")),
+ ::rtl::OUString::createFromAscii(s_nsDC));
+ xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("office")),
+ ::rtl::OUString::createFromAscii(s_nsODF));
+ xPath->registerNS(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("meta")),
+ ::rtl::OUString::createFromAscii(s_nsODFMeta));
+ // NB: we do not handle the single-XML-file ODF variant, which would
+ // have the root element office:document.
+ // The root of such documents must be converted in the importer!
+ ::rtl::OUString prefix = ::rtl::OUString::createFromAscii(
+ "/child::office:document-meta/child::office:meta");
+ css::uno::Reference<css::xml::dom::XNode> xDocNode(
+ m_xDoc, css::uno::UNO_QUERY_THROW);
+ m_xParent.clear();
+ try {
+ m_xParent = xPath->selectSingleNode(xDocNode, prefix);
+ } catch (com::sun::star::uno::Exception &) {
+// DBG_WARNING("SfxDocumentMetaData::init: "
+// "caught RuntimeException from libxml!");
+ }
+
+ if (!m_xParent.is()) {
+ // all this create/append stuff may throw DOMException
+ try {
+ css::uno::Reference<css::xml::dom::XElement> xRElem(
+ i_xDoc->createElementNS(
+ ::rtl::OUString::createFromAscii(s_nsODF),
+ ::rtl::OUString::createFromAscii("office:document-meta")));
+ css::uno::Reference<css::xml::dom::XNode> xRNode(xRElem,
+ css::uno::UNO_QUERY_THROW);
+ // NB: the following is a _bad_idea_ with our DOM implementation
+ // do _not_ create attributes with xmlns prefix!
+// xRElem->setAttribute(::rtl::OUString::createFromAscii("xmlns:office"),
+// ::rtl::OUString::createFromAscii(s_nsODF));
+ xRElem->setAttributeNS(::rtl::OUString::createFromAscii(s_nsODF),
+ ::rtl::OUString::createFromAscii("office:version"),
+ ::rtl::OUString::createFromAscii("1.0"));
+ i_xDoc->appendChild(xRNode);
+ css::uno::Reference<css::xml::dom::XNode> xParent (
+ i_xDoc->createElementNS(
+ ::rtl::OUString::createFromAscii(s_nsODF),
+ ::rtl::OUString::createFromAscii("office:meta")),
+ css::uno::UNO_QUERY_THROW);
+ xRNode->appendChild(xParent);
+ m_xParent = xParent;
+ } catch (css::xml::dom::DOMException & e) {
+ css::uno::Any a(e);
+ throw css::lang::WrappedTargetRuntimeException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::init: DOM exception"),
+ css::uno::Reference<css::uno::XInterface>(*this), a);
+ }
+ }
+
+
+ // select nodes for elements of which we only handle one occurrence
+ for (const char **pName = s_stdMeta; *pName != 0; ++pName) {
+ ::rtl::OUString name = ::rtl::OUString::createFromAscii(*pName);
+ // NB: If a document contains more than one occurrence of a
+ // meta-data element, we arbitrarily pick one of them here.
+ // We do not remove the others, i.e., when we write the
+ // document, it will contain the duplicates unchanged.
+ // The ODF spec says that handling multiple occurrences is
+ // application-specific.
+ css::uno::Reference<css::xml::dom::XNode> xNode =
+ xPath->selectSingleNode(m_xParent,
+ ::rtl::OUString::createFromAscii("child::") + name);
+ // Do not create an empty element if it is missing;
+ // for certain elements, such as dateTime, this would be invalid
+ m_meta[name] = xNode;
+ }
+
+ // select nodes for elements of which we handle all occurrences
+ for (const char **pName = s_stdMetaList; *pName != 0; ++pName) {
+ ::rtl::OUString name = ::rtl::OUString::createFromAscii(*pName);
+ css::uno::Reference<css::xml::dom::XNodeList> nodes =
+ xPath->selectNodeList(m_xParent,
+ ::rtl::OUString::createFromAscii("child::") + name);
+ std::vector<css::uno::Reference<css::xml::dom::XNode> > v;
+ for (sal_Int32 i = 0; i < nodes->getLength(); ++i) {
+ v.push_back(nodes->item(i));
+ }
+ m_metaList[name] = v;
+ }
+
+ // initialize members corresponding to attributes from DOM nodes
+ m_TemplateName = getMetaAttr("meta:template", "xlink:title");
+ m_TemplateURL = getMetaAttr("meta:template", "xlink:href");
+ m_TemplateDate =
+ textToDateTimeDefault(getMetaAttr("meta:template", "meta:date"));
+ m_AutoloadURL = getMetaAttr("meta:auto-reload", "xlink:href");
+ m_AutoloadSecs =
+ textToDuration(getMetaAttr("meta:auto-reload", "meta:delay"));
+ m_DefaultTarget =
+ getMetaAttr("meta:hyperlink-behaviour", "office:target-frame-name");
+
+
+ std::vector<css::uno::Reference<css::xml::dom::XNode> > & vec =
+ m_metaList[::rtl::OUString::createFromAscii("meta:user-defined")];
+ m_xUserDefined.clear(); // #i105826#: reset (may be re-initialization)
+ if ( !vec.empty() )
+ {
+ createUserDefined();
+ }
+
+ // user-defined meta data: initialize PropertySet from DOM nodes
+ for (std::vector<css::uno::Reference<css::xml::dom::XNode> >::iterator
+ it = vec.begin(); it != vec.end(); ++it) {
+ css::uno::Reference<css::xml::dom::XElement> xElem(*it,
+ css::uno::UNO_QUERY_THROW);
+ css::uno::Any any;
+ ::rtl::OUString name = xElem->getAttributeNS(
+ ::rtl::OUString::createFromAscii(s_nsODFMeta),
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("name")));
+ ::rtl::OUString type = xElem->getAttributeNS(
+ ::rtl::OUString::createFromAscii(s_nsODFMeta),
+ ::rtl::OUString::createFromAscii("value-type"));
+ ::rtl::OUString text = getNodeText(*it);
+ if (type.equalsAscii("float")) {
+ double d;
+ if (::sax::Converter::convertDouble(d, text)) {
+ any <<= d;
+ } else {
+ DBG_WARNING1("SfxDocumentMetaData: invalid float: %s",
+ OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
+ continue;
+ }
+ } else if (type.equalsAscii("date")) {
+ bool isDateTime;
+ css::util::Date d;
+ css::util::DateTime dt;
+ if (textToDateOrDateTime(d, dt, isDateTime, text)) {
+ if (isDateTime) {
+ any <<= dt;
+ } else {
+ any <<= d;
+ }
+ } else {
+ DBG_WARNING1("SfxDocumentMetaData: invalid date: %s",
+ OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
+ continue;
+ }
+ } else if (type.equalsAscii("time")) {
+ css::util::Duration ud;
+ if (textToDuration(ud, text)) {
+ any <<= ud;
+ } else {
+ DBG_WARNING1("SfxDocumentMetaData: invalid time: %s",
+ OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
+ continue;
+ }
+ } else if (type.equalsAscii("boolean")) {
+ bool b;
+ if (::sax::Converter::convertBool(b, text)) {
+ any <<= b;
+ } else {
+ DBG_WARNING1("SfxDocumentMetaData: invalid boolean: %s",
+ OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
+ continue;
+ }
+ } else if (type.equalsAscii("string") || true) { // default
+ any <<= text;
+ }
+ try {
+ m_xUserDefined->addProperty(name,
+ css::beans::PropertyAttribute::REMOVEABLE, any);
+ } catch (css::beans::PropertyExistException &) {
+ DBG_WARNING1("SfxDocumentMetaData: duplicate: %s",
+ OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
+ // ignore; duplicate
+ } catch (css::beans::IllegalTypeException &) {
+ DBG_ERROR1("SfxDocumentMetaData: illegal type: %s",
+ OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
+ } catch (css::lang::IllegalArgumentException &) {
+ DBG_ERROR1("SfxDocumentMetaData: illegal arg: %s",
+ OUStringToOString(name, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+
+ m_isModified = false;
+ m_isInitialized = true;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+
+SfxDocumentMetaData::SfxDocumentMetaData(
+ css::uno::Reference< css::uno::XComponentContext > const & context)
+ : BaseMutex()
+ , SfxDocumentMetaData_Base(m_aMutex)
+ , m_xContext(context)
+ , m_NotifyListeners(m_aMutex)
+ , m_isInitialized(false)
+ , m_isModified(false)
+ , m_AutoloadSecs(0)
+{
+ DBG_ASSERT(context.is(), "SfxDocumentMetaData: context is null");
+ DBG_ASSERT(context->getServiceManager().is(),
+ "SfxDocumentMetaData: context has no service manager");
+ init(createDOM());
+}
+
+// com.sun.star.uno.XServiceInfo:
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getImplementationName() throw (css::uno::RuntimeException)
+{
+ return comp_SfxDocumentMetaData::_getImplementationName();
+}
+
+::sal_Bool SAL_CALL
+SfxDocumentMetaData::supportsService(::rtl::OUString const & serviceName)
+ throw (css::uno::RuntimeException)
+{
+ css::uno::Sequence< ::rtl::OUString > serviceNames =
+ comp_SfxDocumentMetaData::_getSupportedServiceNames();
+ for (::sal_Int32 i = 0; i < serviceNames.getLength(); ++i) {
+ if (serviceNames[i] == serviceName)
+ return sal_True;
+ }
+ return sal_False;
+}
+
+css::uno::Sequence< ::rtl::OUString > SAL_CALL
+SfxDocumentMetaData::getSupportedServiceNames()
+ throw (css::uno::RuntimeException)
+{
+ return comp_SfxDocumentMetaData::_getSupportedServiceNames();
+}
+
+
+// ::com::sun::star::lang::XComponent:
+void SAL_CALL SfxDocumentMetaData::dispose() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ if (!m_isInitialized) {
+ return;
+ }
+ WeakComponentImplHelperBase::dispose(); // superclass
+ m_NotifyListeners.disposeAndClear(css::lang::EventObject(
+ static_cast< ::cppu::OWeakObject* >(this)));
+ m_isInitialized = false;
+ m_meta.clear();
+ m_metaList.clear();
+ m_xParent.clear();
+ m_xDoc.clear();
+ m_xUserDefined.clear();
+}
+
+
+// ::com::sun::star::document::XDocumentProperties:
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getAuthor() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return getMetaText("meta:initial-creator");
+}
+
+void SAL_CALL SfxDocumentMetaData::setAuthor(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("meta:initial-creator", the_value);
+}
+
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getGenerator() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return getMetaText("meta:generator");
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setGenerator(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("meta:generator", the_value);
+}
+
+css::util::DateTime SAL_CALL
+SfxDocumentMetaData::getCreationDate() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return textToDateTimeDefault(getMetaText("meta:creation-date"));
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setCreationDate(const css::util::DateTime & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("meta:creation-date", dateTimeToText(the_value));
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getTitle() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return getMetaText("dc:title");
+}
+
+void SAL_CALL SfxDocumentMetaData::setTitle(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("dc:title", the_value);
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getSubject() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return getMetaText("dc:subject");
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setSubject(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("dc:subject", the_value);
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getDescription() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return getMetaText("dc:description");
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setDescription(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("dc:description", the_value);
+}
+
+css::uno::Sequence< ::rtl::OUString >
+SAL_CALL SfxDocumentMetaData::getKeywords() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return getMetaList("meta:keyword");
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setKeywords(
+ const css::uno::Sequence< ::rtl::OUString > & the_value)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::ClearableMutexGuard g(m_aMutex);
+ if (setMetaList("meta:keyword", the_value)) {
+ g.clear();
+ setModified(true);
+ }
+}
+
+css::lang::Locale SAL_CALL
+ SfxDocumentMetaData::getLanguage() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ css::lang::Locale loc;
+ ::rtl::OUString text = getMetaText("dc:language");
+ sal_Int32 ix = text.indexOf(static_cast<sal_Unicode> ('-'));
+ if (ix == -1) {
+ loc.Language = text;
+ } else {
+ loc.Language = text.copy(0, ix);
+ loc.Country = text.copy(ix+1);
+ }
+ return loc;
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setLanguage(const css::lang::Locale & the_value)
+ throw (css::uno::RuntimeException)
+{
+ ::rtl::OUString text = the_value.Language;
+ if (the_value.Country.getLength() > 0) {
+ text += ::rtl::OUString::createFromAscii("-").concat(the_value.Country);
+ }
+ setMetaTextAndNotify("dc:language", text);
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getModifiedBy() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return getMetaText("dc:creator");
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setModifiedBy(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("dc:creator", the_value);
+}
+
+css::util::DateTime SAL_CALL
+SfxDocumentMetaData::getModificationDate() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return textToDateTimeDefault(getMetaText("dc:date"));
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setModificationDate(const css::util::DateTime & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("dc:date", dateTimeToText(the_value));
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getPrintedBy() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return getMetaText("meta:printed-by");
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setPrintedBy(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("meta:printed-by", the_value);
+}
+
+css::util::DateTime SAL_CALL
+SfxDocumentMetaData::getPrintDate() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return textToDateTimeDefault(getMetaText("meta:print-date"));
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setPrintDate(const css::util::DateTime & the_value)
+ throw (css::uno::RuntimeException)
+{
+ setMetaTextAndNotify("meta:print-date", dateTimeToText(the_value));
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getTemplateName() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ return m_TemplateName;
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setTemplateName(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::ClearableMutexGuard g(m_aMutex);
+ checkInit();
+ if (m_TemplateName != the_value) {
+ m_TemplateName = the_value;
+ g.clear();
+ setModified(true);
+ }
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getTemplateURL() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ return m_TemplateURL;
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setTemplateURL(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::ClearableMutexGuard g(m_aMutex);
+ checkInit();
+ if (m_TemplateURL != the_value) {
+ m_TemplateURL = the_value;
+ g.clear();
+ setModified(true);
+ }
+}
+
+css::util::DateTime SAL_CALL
+SfxDocumentMetaData::getTemplateDate() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ return m_TemplateDate;
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setTemplateDate(const css::util::DateTime & the_value)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::ClearableMutexGuard g(m_aMutex);
+ checkInit();
+ if (!(m_TemplateDate == the_value)) {
+ m_TemplateDate = the_value;
+ g.clear();
+ setModified(true);
+ }
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getAutoloadURL() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ return m_AutoloadURL;
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setAutoloadURL(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::ClearableMutexGuard g(m_aMutex);
+ checkInit();
+ if (m_AutoloadURL != the_value) {
+ m_AutoloadURL = the_value;
+ g.clear();
+ setModified(true);
+ }
+}
+
+::sal_Int32 SAL_CALL
+SfxDocumentMetaData::getAutoloadSecs() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ return m_AutoloadSecs;
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setAutoloadSecs(::sal_Int32 the_value)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException)
+{
+ if (the_value < 0) throw css::lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::setAutoloadSecs: argument is negative"),
+ *this, 0);
+ ::osl::ClearableMutexGuard g(m_aMutex);
+ checkInit();
+ if (m_AutoloadSecs != the_value) {
+ m_AutoloadSecs = the_value;
+ g.clear();
+ setModified(true);
+ }
+}
+
+::rtl::OUString SAL_CALL
+SfxDocumentMetaData::getDefaultTarget() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ return m_DefaultTarget;
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setDefaultTarget(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::ClearableMutexGuard g(m_aMutex);
+ checkInit();
+ if (m_DefaultTarget != the_value) {
+ m_DefaultTarget = the_value;
+ g.clear();
+ setModified(true);
+ }
+}
+
+css::uno::Sequence< css::beans::NamedValue > SAL_CALL
+SfxDocumentMetaData::getDocumentStatistics() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ ::comphelper::SequenceAsVector<css::beans::NamedValue> stats;
+ for (size_t i = 0; s_stdStats[i] != 0; ++i) {
+ const char * aName = s_stdStatAttrs[i];
+ ::rtl::OUString text = getMetaAttr("meta:document-statistic", aName);
+ if (text.equalsAscii("")) continue;
+ css::beans::NamedValue stat;
+ stat.Name = ::rtl::OUString::createFromAscii(s_stdStats[i]);
+ sal_Int32 val;
+ css::uno::Any any;
+ if (!::sax::Converter::convertNumber(val, text, 0,
+ std::numeric_limits<sal_Int32>::max()) || (val < 0)) {
+ val = 0;
+ DBG_WARNING1("SfxDocumentMetaData: invalid number: %s",
+ OUStringToOString(text, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ any <<= val;
+ stat.Value = any;
+ stats.push_back(stat);
+ }
+
+ return stats.getAsConstList();
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setDocumentStatistics(
+ const css::uno::Sequence< css::beans::NamedValue > & the_value)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::ClearableMutexGuard g(m_aMutex);
+ checkInit();
+ std::vector<std::pair<const char *, ::rtl::OUString> > attributes;
+ for (sal_Int32 i = 0; i < the_value.getLength(); ++i) {
+ const ::rtl::OUString name = the_value[i].Name;
+ // inefficently search for matching attribute
+ for (size_t j = 0; s_stdStats[j] != 0; ++j) {
+ if (name.equalsAscii(s_stdStats[j])) {
+ const css::uno::Any any = the_value[i].Value;
+ sal_Int32 val = 0;
+ if (any >>= val) {
+ ::rtl::OUStringBuffer buf;
+ ::sax::Converter::convertNumber(buf, val);
+ attributes.push_back(std::make_pair(s_stdStatAttrs[j],
+ buf.makeStringAndClear()));
+ } else {
+ DBG_WARNING1("SfxDocumentMetaData: invalid statistic: %s",
+ OUStringToOString(name, RTL_TEXTENCODING_UTF8)
+ .getStr());
+ }
+ break;
+ }
+ }
+ }
+ updateElement("meta:document-statistic", &attributes);
+ g.clear();
+ setModified(true);
+}
+
+::sal_Int16 SAL_CALL
+SfxDocumentMetaData::getEditingCycles() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ ::rtl::OUString text = getMetaText("meta:editing-cycles");
+ sal_Int32 ret;
+ if (::sax::Converter::convertNumber(ret, text,
+ 0, std::numeric_limits<sal_Int16>::max())) {
+ return static_cast<sal_Int16>(ret);
+ } else {
+ return 0;
+ }
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setEditingCycles(::sal_Int16 the_value)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException)
+{
+ if (the_value < 0) throw css::lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::setEditingCycles: argument is negative"),
+ *this, 0);
+ ::rtl::OUStringBuffer buf;
+ ::sax::Converter::convertNumber(buf, the_value);
+ setMetaTextAndNotify("meta:editing-cycles", buf.makeStringAndClear());
+}
+
+::sal_Int32 SAL_CALL
+SfxDocumentMetaData::getEditingDuration() throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ return textToDuration(getMetaText("meta:editing-duration"));
+}
+
+void SAL_CALL
+SfxDocumentMetaData::setEditingDuration(::sal_Int32 the_value)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException)
+{
+ if (the_value < 0) throw css::lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::setEditingDuration: argument is negative"),
+ *this, 0);
+ setMetaTextAndNotify("meta:editing-duration", durationToText(the_value));
+}
+
+void SAL_CALL
+SfxDocumentMetaData::resetUserData(const ::rtl::OUString & the_value)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::ClearableMutexGuard g(m_aMutex);
+
+ bool bModified( false );
+ bModified |= setMetaText("meta:initial-creator", the_value);
+ ::DateTime now = DateTime();
+ css::util::DateTime uDT(now.Get100Sec(), now.GetSec(), now.GetMin(),
+ now.GetHour(), now.GetDay(), now.GetMonth(), now.GetYear());
+ bModified |= setMetaText("meta:creation-date", dateTimeToText(uDT));
+ bModified |= setMetaText("dc:creator", ::rtl::OUString());
+ bModified |= setMetaText("meta:printed-by", ::rtl::OUString());
+ bModified |= setMetaText("dc:date", dateTimeToText(css::util::DateTime()));
+ bModified |= setMetaText("meta:print-date",
+ dateTimeToText(css::util::DateTime()));
+ bModified |= setMetaText("meta:editing-duration", durationToText(0));
+ bModified |= setMetaText("meta:editing-cycles",
+ ::rtl::OUString::createFromAscii("1"));
+
+ if (bModified) {
+ g.clear();
+ setModified(true);
+ }
+}
+
+
+css::uno::Reference< css::beans::XPropertyContainer > SAL_CALL
+SfxDocumentMetaData::getUserDefinedProperties()
+ throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ createUserDefined();
+ return m_xUserDefined;
+}
+
+
+void SAL_CALL
+SfxDocumentMetaData::loadFromStorage(
+ const css::uno::Reference< css::embed::XStorage > & xStorage,
+ const css::uno::Sequence< css::beans::PropertyValue > & Medium)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException,
+ css::io::WrongFormatException,
+ css::lang::WrappedTargetException, css::io::IOException)
+{
+ if (!xStorage.is()) throw css::lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:"
+ " argument is null"), *this, 0);
+ ::osl::MutexGuard g(m_aMutex);
+
+ // open meta data file
+ css::uno::Reference<css::io::XStream> xStream(
+ xStorage->openStreamElement(
+ ::rtl::OUString::createFromAscii(s_metaXml),
+ css::embed::ElementModes::READ) );
+ if (!xStream.is()) throw css::uno::RuntimeException();
+ css::uno::Reference<css::io::XInputStream> xInStream =
+ xStream->getInputStream();
+ if (!xInStream.is()) throw css::uno::RuntimeException();
+
+ // create DOM parser service
+ css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
+ m_xContext->getServiceManager());
+ css::uno::Reference<css::xml::sax::XParser> xParser (
+ xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii(
+ "com.sun.star.xml.sax.Parser"), m_xContext),
+ css::uno::UNO_QUERY_THROW);
+ if (!xParser.is()) throw css::uno::RuntimeException(
+ ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:"
+ " cannot create Parser service"), *this);
+ css::xml::sax::InputSource input;
+ input.aInputStream = xInStream;
+
+ sal_uInt64 version = SotStorage::GetVersion( xStorage );
+ // Oasis is also the default (0)
+ sal_Bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 );
+ const sal_Char *pServiceName = bOasis
+ ? "com.sun.star.document.XMLOasisMetaImporter"
+ : "com.sun.star.document.XMLMetaImporter";
+
+ // set base URL
+ css::uno::Reference<css::beans::XPropertySet> xPropArg =
+ getURLProperties(Medium);
+ try {
+ xPropArg->getPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("BaseURI")))
+ >>= input.sSystemId;
+ input.sSystemId += ::rtl::OUString::createFromAscii("/").concat(
+ ::rtl::OUString::createFromAscii(s_metaXml));
+ } catch (css::uno::Exception &) {
+ input.sSystemId = ::rtl::OUString::createFromAscii(s_metaXml);
+ }
+ css::uno::Sequence< css::uno::Any > args(1);
+ args[0] <<= xPropArg;
+
+ css::uno::Reference<css::xml::sax::XDocumentHandler> xDocHandler (
+ xMsf->createInstanceWithArgumentsAndContext(
+ ::rtl::OUString::createFromAscii(pServiceName), args, m_xContext),
+ css::uno::UNO_QUERY_THROW);
+ if (!xDocHandler.is()) throw css::uno::RuntimeException(
+ ::rtl::OUString::createFromAscii("SfxDocumentMetaData::loadFromStorage:"
+ " cannot create XMLOasisMetaImporter service"), *this);
+ css::uno::Reference<css::document::XImporter> xImp (xDocHandler,
+ css::uno::UNO_QUERY_THROW);
+ xImp->setTargetDocument(css::uno::Reference<css::lang::XComponent>(this));
+ xParser->setDocumentHandler(xDocHandler);
+ try {
+ xParser->parseStream(input);
+ } catch (css::xml::sax::SAXException &) {
+ throw css::io::WrongFormatException(::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::loadFromStorage:"
+ " XML parsing exception"), *this);
+ }
+ // NB: the implementation of XMLOasisMetaImporter calls initialize
+// init(xDocBuilder->getDocument());
+ checkInit();
+}
+
+void SAL_CALL
+SfxDocumentMetaData::storeToStorage(
+ const css::uno::Reference< css::embed::XStorage > & xStorage,
+ const css::uno::Sequence< css::beans::PropertyValue > & Medium)
+ throw (css::uno::RuntimeException, css::lang::IllegalArgumentException,
+ css::lang::WrappedTargetException, css::io::IOException)
+{
+ if (!xStorage.is()) throw css::lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii("SfxDocumentMetaData::storeToStorage:"
+ " argument is null"), *this, 0);
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+
+ // update user-defined meta data in DOM tree
+// updateUserDefinedAndAttributes(); // this will be done in serialize!
+
+ // write into storage
+ css::uno::Reference<css::io::XStream> xStream =
+ xStorage->openStreamElement(::rtl::OUString::createFromAscii(s_metaXml),
+ css::embed::ElementModes::WRITE
+ | css::embed::ElementModes::TRUNCATE);
+ if (!xStream.is()) throw css::uno::RuntimeException();
+ css::uno::Reference< css::beans::XPropertySet > xStreamProps(xStream,
+ css::uno::UNO_QUERY_THROW);
+ xStreamProps->setPropertyValue(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("MediaType")),
+ css::uno::makeAny(::rtl::OUString::createFromAscii("text/xml")));
+ xStreamProps->setPropertyValue(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Compressed")),
+ css::uno::makeAny(static_cast<sal_Bool> (sal_False)));
+ xStreamProps->setPropertyValue(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("UseCommonStoragePasswordEncryption")),
+ css::uno::makeAny(static_cast<sal_Bool> (sal_False)));
+ css::uno::Reference<css::io::XOutputStream> xOutStream =
+ xStream->getOutputStream();
+ if (!xOutStream.is()) throw css::uno::RuntimeException();
+ css::uno::Reference<css::lang::XMultiComponentFactory> xMsf (
+ m_xContext->getServiceManager());
+ css::uno::Reference<css::io::XActiveDataSource> xSaxWriter(
+ xMsf->createInstanceWithContext(::rtl::OUString::createFromAscii(
+ "com.sun.star.xml.sax.Writer"), m_xContext),
+ css::uno::UNO_QUERY_THROW);
+ xSaxWriter->setOutputStream(xOutStream);
+ css::uno::Reference<css::xml::sax::XDocumentHandler> xDocHandler (
+ xSaxWriter, css::uno::UNO_QUERY_THROW);
+
+ const sal_uInt64 version = SotStorage::GetVersion( xStorage );
+ // Oasis is also the default (0)
+ const sal_Bool bOasis = ( version > SOFFICE_FILEFORMAT_60 || version == 0 );
+ const sal_Char *pServiceName = bOasis
+ ? "com.sun.star.document.XMLOasisMetaExporter"
+ : "com.sun.star.document.XMLMetaExporter";
+
+ // set base URL
+ css::uno::Reference<css::beans::XPropertySet> xPropArg =
+ getURLProperties(Medium);
+ css::uno::Sequence< css::uno::Any > args(2);
+ args[0] <<= xDocHandler;
+ args[1] <<= xPropArg;
+
+ css::uno::Reference<css::document::XExporter> xExp(
+ xMsf->createInstanceWithArgumentsAndContext(
+ ::rtl::OUString::createFromAscii(pServiceName), args, m_xContext),
+ css::uno::UNO_QUERY_THROW);
+ xExp->setSourceDocument(css::uno::Reference<css::lang::XComponent>(this));
+ css::uno::Reference<css::document::XFilter> xFilter(xExp,
+ css::uno::UNO_QUERY_THROW);
+ if (xFilter->filter(css::uno::Sequence< css::beans::PropertyValue >())) {
+ css::uno::Reference<css::embed::XTransactedObject> xTransaction(
+ xStorage, css::uno::UNO_QUERY);
+ if (xTransaction.is()) {
+ xTransaction->commit();
+ }
+ } else {
+ throw css::io::IOException(::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::storeToStorage: cannot filter"), *this);
+ }
+}
+
+void SAL_CALL
+SfxDocumentMetaData::loadFromMedium(const ::rtl::OUString & URL,
+ const css::uno::Sequence< css::beans::PropertyValue > & Medium)
+ throw (css::uno::RuntimeException, css::io::WrongFormatException,
+ css::lang::WrappedTargetException, css::io::IOException)
+{
+ css::uno::Reference<css::io::XInputStream> xIn;
+ ::comphelper::MediaDescriptor md(Medium);
+ // if we have an URL parameter, it replaces the one in the media descriptor
+ if (!URL.equalsAscii("")) {
+ md[ ::comphelper::MediaDescriptor::PROP_URL() ] <<= URL;
+ }
+ if (sal_True == md.addInputStream()) {
+ md[ ::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn;
+ }
+ css::uno::Reference<css::embed::XStorage> xStorage;
+ css::uno::Reference<css::lang::XMultiServiceFactory> xMsf (
+ m_xContext->getServiceManager(), css::uno::UNO_QUERY_THROW);
+ try {
+ if (xIn.is()) {
+ xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream(
+ xIn, xMsf);
+ } else { // fallback to url parameter
+ xStorage = ::comphelper::OStorageHelper::GetStorageFromURL(
+ URL, css::embed::ElementModes::READ, xMsf);
+ }
+ } catch (css::uno::RuntimeException &) {
+ throw;
+ } catch (css::io::IOException &) {
+ throw;
+ } catch (css::uno::Exception & e) {
+ throw css::lang::WrappedTargetException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::loadFromMedium: exception"),
+ css::uno::Reference<css::uno::XInterface>(*this),
+ css::uno::makeAny(e));
+ }
+ if (!xStorage.is()) {
+ throw css::uno::RuntimeException(::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::loadFromMedium: cannot get Storage"),
+ *this);
+ }
+ loadFromStorage(xStorage, md.getAsConstPropertyValueList());
+}
+
+void SAL_CALL
+SfxDocumentMetaData::storeToMedium(const ::rtl::OUString & URL,
+ const css::uno::Sequence< css::beans::PropertyValue > & Medium)
+ throw (css::uno::RuntimeException,
+ css::lang::WrappedTargetException, css::io::IOException)
+{
+ ::comphelper::MediaDescriptor md(Medium);
+ if (!URL.equalsAscii("")) {
+ md[ ::comphelper::MediaDescriptor::PROP_URL() ] <<= URL;
+ }
+ SfxMedium aMedium(md.getAsConstPropertyValueList());
+ css::uno::Reference<css::embed::XStorage> xStorage
+ = aMedium.GetOutputStorage();
+
+
+ if (!xStorage.is()) {
+ throw css::uno::RuntimeException(::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::storeToMedium: cannot get Storage"),
+ *this);
+ }
+ // set MIME type of the storage
+ ::comphelper::MediaDescriptor::const_iterator iter
+ = md.find(::comphelper::MediaDescriptor::PROP_MEDIATYPE());
+ if (iter != md.end()) {
+ css::uno::Reference< css::beans::XPropertySet > xProps(xStorage,
+ css::uno::UNO_QUERY_THROW);
+ xProps->setPropertyValue(
+ ::comphelper::MediaDescriptor::PROP_MEDIATYPE(),
+ iter->second);
+ }
+ storeToStorage(xStorage, md.getAsConstPropertyValueList());
+
+
+ const sal_Bool bOk = aMedium.Commit();
+ aMedium.Close();
+ if ( !bOk ) {
+ sal_uInt32 nError = aMedium.GetError();
+ if ( nError == ERRCODE_NONE ) {
+ nError = ERRCODE_IO_GENERAL;
+ }
+
+ throw css::task::ErrorCodeIOException( ::rtl::OUString(),
+ css::uno::Reference< css::uno::XInterface >(), nError);
+
+ }
+}
+
+// ::com::sun::star::lang::XInitialization:
+void SAL_CALL
+SfxDocumentMetaData::initialize(
+ const css::uno::Sequence< ::com::sun::star::uno::Any > & aArguments)
+ throw (css::uno::RuntimeException, css::uno::Exception)
+{
+ // possible arguments:
+ // - no argument: default initialization (empty DOM)
+ // - 1 argument, XDocument: initialize with given DOM and empty base URL
+ // NB: links in document must be absolute
+
+ ::osl::MutexGuard g(m_aMutex);
+ css::uno::Reference<css::xml::dom::XDocument> xDoc;
+
+ for (sal_Int32 i = 0; i < aArguments.getLength(); ++i) {
+ const css::uno::Any any = aArguments[i];
+ if (any >>= xDoc) {
+ if (!xDoc.is()) {
+ throw css::lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii("SfxDocumentMetaData::"
+ "initialize: argument is null"),
+ *this, static_cast<sal_Int16>(i));
+ }
+ } else {
+ throw css::lang::IllegalArgumentException(
+ ::rtl::OUString::createFromAscii("SfxDocumentMetaData::"
+ "initialize: argument must be XDocument"),
+ *this, static_cast<sal_Int16>(i));
+ }
+ }
+
+ if (!xDoc.is()) {
+ // For a new document, we create a new DOM tree here.
+ xDoc = createDOM();
+ }
+
+ init(xDoc);
+}
+
+// ::com::sun::star::util::XCloneable:
+css::uno::Reference<css::util::XCloneable> SAL_CALL
+SfxDocumentMetaData::createClone()
+ throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+
+ SfxDocumentMetaData *pNew = new SfxDocumentMetaData(m_xContext);
+
+ // NB: do not copy the modification listeners, only DOM
+ css::uno::Reference<css::xml::dom::XDocument> xDoc = createDOM();
+ try {
+ updateUserDefinedAndAttributes();
+ // deep copy of root node
+ css::uno::Reference<css::xml::dom::XNode> xRoot(
+ m_xDoc->getDocumentElement(), css::uno::UNO_QUERY_THROW);
+ css::uno::Reference<css::xml::dom::XNode> xRootNew(
+ xDoc->importNode(xRoot, true));
+ xDoc->appendChild(xRootNew);
+ pNew->init(xDoc);
+ } catch (css::uno::RuntimeException &) {
+ throw;
+ } catch (css::uno::Exception & e) {
+ css::uno::Any a(e);
+ throw css::lang::WrappedTargetRuntimeException(
+ ::rtl::OUString::createFromAscii(
+ "SfxDocumentMetaData::createClone: exception"),
+ css::uno::Reference<css::uno::XInterface>(*this), a);
+ }
+// return static_cast< ::cppu::OWeakObject * > (pNew);
+ return css::uno::Reference<css::util::XCloneable> (pNew);
+}
+
+// ::com::sun::star::util::XModifiable:
+::sal_Bool SAL_CALL SfxDocumentMetaData::isModified( )
+ throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ css::uno::Reference<css::util::XModifiable> xMB(m_xUserDefined,
+ css::uno::UNO_QUERY);
+ return m_isModified || (xMB.is() ? xMB->isModified() : sal_False);
+}
+
+void SAL_CALL SfxDocumentMetaData::setModified( ::sal_Bool bModified )
+ throw (css::beans::PropertyVetoException, css::uno::RuntimeException)
+{
+ css::uno::Reference<css::util::XModifiable> xMB;
+ { // do not lock mutex while notifying (#i93514#) to prevent deadlock
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ m_isModified = bModified;
+ if ( !bModified && m_xUserDefined.is() )
+ {
+ xMB.set(m_xUserDefined, css::uno::UNO_QUERY);
+ DBG_ASSERT(xMB.is(),
+ "SfxDocumentMetaData::setModified: PropertyBag not Modifiable?");
+ }
+ }
+ if (bModified) {
+ try {
+ css::uno::Reference<css::uno::XInterface> xThis(*this);
+ css::lang::EventObject event(xThis);
+ m_NotifyListeners.notifyEach(&css::util::XModifyListener::modified,
+ event);
+ } catch (css::uno::RuntimeException &) {
+ throw;
+ } catch (css::uno::Exception & e) {
+ // ignore
+ DBG_WARNING1("SfxDocumentMetaData::setModified: exception:\n%s",
+ OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
+ (void) e;
+ }
+ } else {
+ if (xMB.is()) {
+ xMB->setModified(false);
+ }
+ }
+}
+
+// ::com::sun::star::util::XModifyBroadcaster:
+void SAL_CALL SfxDocumentMetaData::addModifyListener(
+ const css::uno::Reference< css::util::XModifyListener > & xListener)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ m_NotifyListeners.addInterface(xListener);
+ css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined,
+ css::uno::UNO_QUERY);
+ if (xMB.is()) {
+ xMB->addModifyListener(xListener);
+ }
+}
+
+void SAL_CALL SfxDocumentMetaData::removeModifyListener(
+ const css::uno::Reference< css::util::XModifyListener > & xListener)
+ throw (css::uno::RuntimeException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ m_NotifyListeners.removeInterface(xListener);
+ css::uno::Reference<css::util::XModifyBroadcaster> xMB(m_xUserDefined,
+ css::uno::UNO_QUERY);
+ if (xMB.is()) {
+ xMB->removeModifyListener(xListener);
+ }
+}
+
+// ::com::sun::star::xml::sax::XSAXSerializable
+void SAL_CALL SfxDocumentMetaData::serialize(
+ const css::uno::Reference<css::xml::sax::XDocumentHandler>& i_xHandler,
+ const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces)
+ throw (css::uno::RuntimeException, css::xml::sax::SAXException)
+{
+ ::osl::MutexGuard g(m_aMutex);
+ checkInit();
+ updateUserDefinedAndAttributes();
+ css::uno::Reference<css::xml::sax::XSAXSerializable> xSAXable(m_xDoc,
+ css::uno::UNO_QUERY_THROW);
+ xSAXable->serialize(i_xHandler, i_rNamespaces);
+}
+
+void SfxDocumentMetaData::createUserDefined()
+{
+ // user-defined meta data: create PropertyBag which only accepts property
+ // values of allowed types
+ if ( !m_xUserDefined.is() )
+ {
+ css::uno::Sequence<css::uno::Type> types(11);
+ types[0] = ::cppu::UnoType<bool>::get();
+ types[1] = ::cppu::UnoType< ::rtl::OUString>::get();
+ types[2] = ::cppu::UnoType<css::util::DateTime>::get();
+ types[3] = ::cppu::UnoType<css::util::Date>::get();
+ types[4] = ::cppu::UnoType<css::util::Duration>::get();
+ types[5] = ::cppu::UnoType<float>::get();
+ types[6] = ::cppu::UnoType<double>::get();
+ types[7] = ::cppu::UnoType<sal_Int16>::get();
+ types[8] = ::cppu::UnoType<sal_Int32>::get();
+ types[9] = ::cppu::UnoType<sal_Int64>::get();
+ // Time is supported for backward compatibility with OOo 3.x, x<=2
+ types[10] = ::cppu::UnoType<css::util::Time>::get();
+ css::uno::Sequence<css::uno::Any> args(2);
+ args[0] <<= css::beans::NamedValue(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("AllowedTypes")),
+ css::uno::makeAny(types));
+ // #i94175#: ODF allows empty user-defined property names!
+ args[1] <<= css::beans::NamedValue( ::rtl::OUString(
+ RTL_CONSTASCII_USTRINGPARAM("AllowEmptyPropertyName")),
+ css::uno::makeAny(sal_True));
+
+ const css::uno::Reference<css::lang::XMultiComponentFactory> xMsf(
+ m_xContext->getServiceManager());
+ m_xUserDefined.set(
+ xMsf->createInstanceWithContext(
+ ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.beans.PropertyBag")), m_xContext),
+ css::uno::UNO_QUERY_THROW);
+ const css::uno::Reference<css::lang::XInitialization> xInit(
+ m_xUserDefined, css::uno::UNO_QUERY);
+ if (xInit.is()) {
+ xInit->initialize(args);
+ }
+
+ const css::uno::Reference<css::util::XModifyBroadcaster> xMB(
+ m_xUserDefined, css::uno::UNO_QUERY);
+ if (xMB.is())
+ {
+ const css::uno::Sequence<css::uno::Reference<css::uno::XInterface> >
+ listeners(m_NotifyListeners.getElements());
+ for (css::uno::Reference< css::uno::XInterface > const * iter =
+ ::comphelper::stl_begin(listeners);
+ iter != ::comphelper::stl_end(listeners); ++iter) {
+ xMB->addModifyListener(
+ css::uno::Reference< css::util::XModifyListener >(*iter,
+ css::uno::UNO_QUERY));
+ }
+ }
+ }
+}
+
+} // closing anonymous implementation namespace
+
+
+// component helper namespace
+namespace comp_SfxDocumentMetaData {
+
+::rtl::OUString SAL_CALL _getImplementationName() {
+ return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
+ "SfxDocumentMetaData"));
+}
+
+css::uno::Sequence< ::rtl::OUString > SAL_CALL _getSupportedServiceNames()
+{
+ css::uno::Sequence< ::rtl::OUString > s(1);
+ s[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
+ "com.sun.star.document.DocumentProperties"));
+ return s;
+}
+
+css::uno::Reference< css::uno::XInterface > SAL_CALL _create(
+ const css::uno::Reference< css::uno::XComponentContext > & context)
+ SAL_THROW((css::uno::Exception))
+{
+ return static_cast< ::cppu::OWeakObject * >
+ (new SfxDocumentMetaData(context));
+}
+
+} // closing component helper namespace
+
+static ::cppu::ImplementationEntry const entries[] = {
+ { &comp_SfxDocumentMetaData::_create,
+ &comp_SfxDocumentMetaData::_getImplementationName,
+ &comp_SfxDocumentMetaData::_getSupportedServiceNames,
+ &::cppu::createSingleComponentFactory, 0, 0 },
+ { 0, 0, 0, 0, 0, 0 }
+};
+
+#if 0
+extern "C" void SAL_CALL component_getImplementationEnvironment(
+ const char ** envTypeName, uno_Environment **)
+{
+ *envTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+}
+
+extern "C" void * SAL_CALL component_getFactory(
+ const char * implName, void * serviceManager, void * registryKey)
+{
+ return ::cppu::component_getFactoryHelper(
+ implName, serviceManager, registryKey, entries);
+}
+
+extern "C" sal_Bool SAL_CALL component_writeInfo(
+ void * serviceManager, void * registryKey)
+{
+ return ::cppu::component_writeInfoHelper(serviceManager, registryKey,
+ entries);
+}
+#endif
+