| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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; |
| |
| // 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; |
| css::uno::Reference<css::xml::dom::XNode> xNode( |
| i_xDoc->getFirstChild()); |
| while (xNode.is()) { |
| if (css::xml::dom::NodeType_ELEMENT_NODE ==xNode->getNodeType()) |
| { |
| if (xNode->getNamespaceURI().equalsAscii(s_nsODF) && |
| xNode->getLocalName().equalsAscii("document-meta")) |
| { |
| xRElem.set(xNode, css::uno::UNO_QUERY_THROW); |
| break; |
| } |
| else |
| { |
| OSL_TRACE("SfxDocumentMetaData::init(): " |
| "deleting unexpected root element: %s", |
| ::rtl::OUStringToOString(xNode->getLocalName(), |
| RTL_TEXTENCODING_UTF8).getStr()); |
| i_xDoc->removeChild(xNode); |
| xNode = i_xDoc->getFirstChild(); // start over |
| } |
| } else { |
| xNode = xNode->getNextSibling(); |
| } |
| } |
| if (!xRElem.is()) { |
| 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); |
| i_xDoc->appendChild(xRNode); |
| } |
| xRElem->setAttributeNS(::rtl::OUString::createFromAscii(s_nsODF), |
| ::rtl::OUString::createFromAscii("office:version"), |
| ::rtl::OUString::createFromAscii("1.0")); |
| // does not exist, otherwise m_xParent would not be null |
| 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); |
| xRElem->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); |
| } |
| #endif |
| |