diff options
Diffstat (limited to 'sfx2')
46 files changed, 5966 insertions, 515 deletions
diff --git a/sfx2/inc/sfx2/DocumentMetadataAccess.hxx b/sfx2/inc/sfx2/DocumentMetadataAccess.hxx new file mode 100644 index 000000000000..1f0d3d38e44e --- /dev/null +++ b/sfx2/inc/sfx2/DocumentMetadataAccess.hxx @@ -0,0 +1,218 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DocumentMetadataAccess.hxx,v $ + * $Revision: 1.1.2.6 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SFX_DOCUMENTMETADATAACCESS_HXX_ +#define _SFX_DOCUMENTMETADATAACCESS_HXX_ + +#include <sal/config.h> + +#include <sfx2/dllapi.h> + +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/rdf/XDocumentMetadataAccess.hpp> +#include <com/sun/star/rdf/XRepositorySupplier.hpp> + +#include <cppuhelper/implbase1.hxx> + +#include <boost/utility.hpp> + +#include <memory> + + +/** Implementation of the interface com.sun.star.rdf.XDocumentMetadataAccess + + This is not a service only because it needs some kind of XML ID registry + from the document, and i do not like defining an API for that. + Also, the implementation does _no_ locking, so make sure access is + protected externally. + + @author mst + */ + +namespace com { namespace sun { namespace star { namespace embed { + class XStorage; +} } } } + +namespace sfx2 { + + +/** create a base URI for loading metadata from an ODF (sub)document. + + @param i_xContext component context + @param i_xStorage storage for the document; FileSystemStorage is allowed + @param i_rPkgURI the URI for the package + @param i_rSubDocument (optional) path of the subdocument in package + + @return a base URI suitable for XDocumentMetadataAccess::loadFromStorage + */ +::com::sun::star::uno::Reference< ::com::sun::star::rdf::XURI> SFX2_DLLPUBLIC +createBaseURI( + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext> + const & i_xContext, + ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage> + const & i_xStorage, + ::rtl::OUString const & i_rPkgURI, + ::rtl::OUString const & i_rSubDocument = ::rtl::OUString()); + + +class IXmlIdRegistrySupplier; +struct DocumentMetadataAccess_Impl; + + +class SFX2_DLLPUBLIC DocumentMetadataAccess : + private boost::noncopyable, + public ::cppu::WeakImplHelper1< + ::com::sun::star::rdf::XDocumentMetadataAccess> +{ +public: + explicit DocumentMetadataAccess(::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > const & i_xContext, + IXmlIdRegistrySupplier const & i_rRegistrySupplier, + ::rtl::OUString const & i_rBaseURI); + // N.B.: in contrast to previous, this constructor does _not_ initialize! + // caller must immediately call loadFromStorage/Medium! + explicit DocumentMetadataAccess(::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > const & i_xContext, + IXmlIdRegistrySupplier const & i_rRegistrySupplier); + virtual ~DocumentMetadataAccess(); + + // ::com::sun::star::rdf::XNode: + virtual ::rtl::OUString SAL_CALL getStringValue() + throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::rdf::XURI: + virtual ::rtl::OUString SAL_CALL getNamespace() + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getLocalName() + throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::rdf::XRepositorySupplier: + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XRepository > SAL_CALL getRDFRepository() + throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::rdf::XDocumentMetadataAccess: + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > SAL_CALL + getElementByMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > SAL_CALL + getElementByURI(const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xURI) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > > SAL_CALL getMetadataGraphsWithType( + const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xType) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI> SAL_CALL + addMetadataFile(const ::rtl::OUString & i_rFileName, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< ::com::sun::star::rdf::XURI > + > & i_rTypes) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::ElementExistException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI> SAL_CALL + importMetadataFile(::sal_Int16 i_Format, + const ::com::sun::star::uno::Reference< + ::com::sun::star::io::XInputStream > & i_xInStream, + const ::rtl::OUString & i_rFileName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xBaseURI, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< ::com::sun::star::rdf::XURI > + > & i_rTypes) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::datatransfer::UnsupportedFlavorException, + ::com::sun::star::container::ElementExistException, + ::com::sun::star::rdf::ParseException, + ::com::sun::star::io::IOException); + virtual void SAL_CALL removeMetadataFile( + const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xGraphName) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException); + virtual void SAL_CALL addContentOrStylesFile( + const ::rtl::OUString & i_rFileName) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::ElementExistException); + virtual void SAL_CALL removeContentOrStylesFile( + const ::rtl::OUString & i_rFileName) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException); + + virtual void SAL_CALL loadMetadataFromStorage( + const ::com::sun::star::uno::Reference< + ::com::sun::star::embed::XStorage > & i_xStorage, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xBaseURI, + const ::com::sun::star::uno::Reference< + ::com::sun::star::task::XInteractionHandler> & i_xHandler) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::lang::WrappedTargetException); + virtual void SAL_CALL storeMetadataToStorage( + const ::com::sun::star::uno::Reference< + ::com::sun::star::embed::XStorage > & i_xStorage) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::lang::WrappedTargetException); + virtual void SAL_CALL loadMetadataFromMedium( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue > & i_rMedium) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::lang::WrappedTargetException); + virtual void SAL_CALL storeMetadataToMedium( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue > & i_rMedium) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::lang::WrappedTargetException); + +private: + std::auto_ptr<DocumentMetadataAccess_Impl> m_pImpl; +}; + +} // namespace sfx2 + +#endif // _SFX_DOCUMENTMETADATAACCESS_HXX_ + diff --git a/sfx2/inc/sfx2/Metadatable.hxx b/sfx2/inc/sfx2/Metadatable.hxx new file mode 100644 index 000000000000..c190abd0471b --- /dev/null +++ b/sfx2/inc/sfx2/Metadatable.hxx @@ -0,0 +1,190 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SwMetadatable.hxx,v $ + * $Revision: 1.1.2.6 $ + * + * 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. + * + ************************************************************************/ +#ifndef METADATABLE_HXX +#define METADATABLE_HXX + +#include <sal/config.h> + +#include <sfx2/dllapi.h> + +#include <cppuhelper/implbase1.hxx> +#include <com/sun/star/rdf/XMetadatable.hpp> + +#include <boost/utility.hpp> +#include <boost/shared_ptr.hpp> + + +namespace com { namespace sun { namespace star { + namespace frame { class XModel; } +} } } + +namespace sfx2 { + class IXmlIdRegistry; +} + +namespace sfx2 { + +class XmlIdRegistry; +class MetadatableUndo; + + +// XML ID handling --------------------------------------------------- + + +/// create a sfx2::XmlIdRegistryDocument or a sfx2::XmlIdRegistryClipboard +SFX2_DLLPUBLIC ::sfx2::IXmlIdRegistry * +createXmlIdRegistry(const bool i_DocIsClipboard); + + +/** base class for core objects that may have xml:id. + + <p>The interface of this class consists of 3 parts: + <ul><li>implementations that are used by the <type>MetadatableMixin</type> + below</li> + <li>hooks to be called by the sw core whenever actions that are + relevant to the uniqueness of xml:ids are taken (copying, + splitting, merging, deletion, undo, etc.)</li> + <li>abstract methods that are called by the implementation of the + previous hooks</li></ul> + </p> + */ +class SFX2_DLLPUBLIC Metadatable : private boost::noncopyable +{ + +public: + Metadatable() : m_pReg(0) {} + + // destructor calls RemoveMetadataReference + virtual ~Metadatable(); + + // for MetadatableMixin ---------------------------------------------- + + ::com::sun::star::beans::StringPair GetMetadataReference() const; + void SetMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference); + void EnsureMetadataReference(); + + // hooks ------------------------------------------------------------- + + // called from dtor! + void RemoveMetadataReference(); + + /** register this as a copy of i_rSource */ + void RegisterAsCopyOf(Metadatable const & i_rSource, + const bool i_bCopyPrecedesSource = false); + + /** create an Undo Metadatable, which remembers this' reference */ + ::boost::shared_ptr<MetadatableUndo> CreateUndo( + const bool i_isDelete = false); + + /** restore this from Undo Metadatable */ + void RestoreMetadata(::boost::shared_ptr<MetadatableUndo> const& i_pUndo); + + /** merge this and i_rOther into this */ + void JoinMetadatable(Metadatable const & i_rOther, + const bool i_isMergedEmpty, const bool i_isOtherEmpty); + + // abstract methods -------------------------------------------------- + + /** get the registry from the SwDoc */ + virtual ::sfx2::IXmlIdRegistry& GetRegistry() = 0; + + /** is this in a clipboard document? */ + virtual bool IsInClipboard() const = 0; + + /** is this in undo array? */ + virtual bool IsInUndo() const = 0; + + /** which stream is this in? true: content.xml; false: styles.xml */ + virtual bool IsInContent() const = 0; + + /** create XMetadatable from this. + note: if IsInUndo or IsInClipboard return true, + MakeUnoObject <em>must not</em> be called! + */ + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > MakeUnoObject() = 0; + +private: + friend class MetadatableClipboard; + friend class MetadatableUndo; + + // note that Reg may be a XmlIdRegistryDocument or a XmlIdRegistryClipboard + XmlIdRegistry* m_pReg; // null => no XmlId +}; + + +/** base class for UNO objects that implement <type>XMetadatable</type>. + + <p>An instance of this base class is associated with an instance of + <type>Metadatable</type>.</p> + */ +class SFX2_DLLPUBLIC MetadatableMixin : + public ::cppu::WeakImplHelper1< + ::com::sun::star::rdf::XMetadatable> +{ + +public: + MetadatableMixin() {}; + + virtual ~MetadatableMixin() {} + + // ::com::sun::star::rdf::XNode: + virtual ::rtl::OUString SAL_CALL getStringValue() + throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::rdf::XURI: + virtual ::rtl::OUString SAL_CALL getLocalName() + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getNamespace() + throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::rdf::XMetadatable: + virtual ::com::sun::star::beans::StringPair SAL_CALL getMetadataReference() + throw (::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException); + virtual void SAL_CALL ensureMetadataReference() + throw (::com::sun::star::uno::RuntimeException); + +protected: + /// get the core object corresponding to this UNO object. + virtual Metadatable * GetCoreObject() = 0; + /// get the <type>XModel</type> for the document + virtual ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel > + GetModel() = 0; + +}; + +} // namespace sfx2 + +#endif // METADATABLE_HXX diff --git a/sfx2/inc/sfx2/XmlIdRegistry.hxx b/sfx2/inc/sfx2/XmlIdRegistry.hxx new file mode 100644 index 000000000000..0ae6fbb75193 --- /dev/null +++ b/sfx2/inc/sfx2/XmlIdRegistry.hxx @@ -0,0 +1,101 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: XmlIdRegistry.hxx,v $ + * $Revision: 1.1.2.3 $ + * + * 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. + * + ************************************************************************/ + +#ifndef _SFX_XMLIDREGISTRY_HXX_ +#define _SFX_XMLIDREGISTRY_HXX_ + +#include <sal/config.h> + +#include <sfx2/dllapi.h> + +#include <com/sun/star/beans/StringPair.hpp> + + +namespace com { namespace sun { namespace star { namespace rdf { + class XMetadatable; +} } } } + +namespace sfx2 { + +// XML ID utilities -------------------------------------------------- + +/** is i_rIdref a valid NCName ? */ +bool SFX2_DLLPUBLIC isValidNCName(::rtl::OUString const & i_rIdref); + +extern inline bool +isValidXmlId(::rtl::OUString const & i_rStreamName, + ::rtl::OUString const & i_rIdref) +{ + return isValidNCName(i_rIdref) && + (i_rStreamName.equalsAscii("content.xml") || + i_rStreamName.equalsAscii("styles.xml")); +} + + +// XML ID handling --------------------------------------------------- + +/** interface for getElementByMetadataReference; + for use by sfx2::DocumentMetadataAccess + */ +class SFX2_DLLPUBLIC IXmlIdRegistry +{ + +public: + virtual ~IXmlIdRegistry() { } + + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > SAL_CALL + GetElementByMetadataReference( + const ::com::sun::star::beans::StringPair & i_rXmlId) const = 0; + +}; + +/** supplier interface for the registry. + + This indirection is unfortunately necessary, because the SwDocShell + is not always connected to a SwDoc, so we cannot guarantee that a + registry given to a SfxBaseModel/DocumentMetadataAccess remains valid; + it has to be retrieved from this supplier interface on access. + */ +class SFX2_DLLPUBLIC IXmlIdRegistrySupplier +{ + +public: + virtual ~IXmlIdRegistrySupplier() { } + + /** override this if you have a XmlIdRegistry. */ + virtual const IXmlIdRegistry* GetXmlIdRegistry() const { return 0; } + +}; + +} // namespace sfx2 + +#endif // _SFX_XMLIDREGISTRY_HXX_ + diff --git a/sfx2/inc/sfx2/app.hxx b/sfx2/inc/sfx2/app.hxx index ceac3c18ba5e..99deee0c97a3 100644 --- a/sfx2/inc/sfx2/app.hxx +++ b/sfx2/inc/sfx2/app.hxx @@ -262,6 +262,7 @@ public: BOOL bActivate, BOOL bForbidVisible = FALSE, const String* pPostStr = 0); + void ResetLastDir(); //#if 0 // _SOLAR__PRIVATE SAL_DLLPRIVATE static SfxApplication* Is_Impl() { return pApp;} diff --git a/sfx2/inc/sfx2/dinfdlg.hxx b/sfx2/inc/sfx2/dinfdlg.hxx index ae7439bcde44..1873c6e6c88e 100644 --- a/sfx2/inc/sfx2/dinfdlg.hxx +++ b/sfx2/inc/sfx2/dinfdlg.hxx @@ -50,9 +50,6 @@ #include "tabdlg.hxx" namespace com { namespace sun { namespace star { - namespace beans { - class XPropertyContainer; - } namespace document { class XDocumentProperties; } @@ -75,7 +72,7 @@ private: ::com::sun::star::util::DateTime m_CreationDate; ::rtl::OUString m_ModifiedBy; ::com::sun::star::util::DateTime m_ModificationDate; - String m_PrintedBy; + ::rtl::OUString m_PrintedBy; ::com::sun::star::util::DateTime m_PrintDate; sal_Int16 m_EditingCycles; sal_Int32 m_EditingDuration; @@ -83,11 +80,9 @@ private: ::rtl::OUString m_Keywords; ::rtl::OUString m_Subject; ::rtl::OUString m_Title; - ::rtl::OUString m_UserDefinedFieldTitles[4]; - ::rtl::OUString m_UserDefinedFieldValues[4]; - sal_Bool bHasTemplate; - sal_Bool bDeleteUserData; - sal_Bool bIsUseUserData; + sal_Bool m_bHasTemplate; + sal_Bool m_bDeleteUserData; + sal_Bool m_bUseUserData; std::vector< CustomProperty* > m_aCustomProperties; public: @@ -101,9 +96,10 @@ public: virtual ~SfxDocumentInfoItem(); /// update i_xDocProps with the data in this object - void updateDocumentInfo( + void UpdateDocumentInfo( const ::com::sun::star::uno::Reference< - ::com::sun::star::document::XDocumentProperties> & i_xDocProps) + ::com::sun::star::document::XDocumentProperties> & i_xDocProps, + bool i_bDoNotUpdateUserDefined = false) const; sal_Bool isAutoloadEnabled() const { return m_isAutoloadEnabled; } @@ -151,25 +147,21 @@ public: void setSubject(::rtl::OUString i_val) { m_Subject = i_val; } ::rtl::OUString getTitle() const { return m_Title; } void setTitle(::rtl::OUString i_val) { m_Title = i_val; } - ::rtl::OUString getUserDefinedFieldTitle(size_t i_ix) const; - void setUserDefinedFieldTitle(size_t i_ix, ::rtl::OUString i_val); - ::rtl::OUString getUserDefinedFieldValue(size_t i_ix) const; - void setUserDefinedFieldValue(size_t i_ix, ::rtl::OUString i_val); /// reset user-specific data (author, modified-by, ...) void resetUserData(const ::rtl::OUString & i_rAuthor); - void SetTemplate( BOOL b ) { bHasTemplate = b; } - FASTBOOL HasTemplate() const { return bHasTemplate; } - void SetDeleteUserData( BOOL bSet ); - void SetUseUserData( BOOL bSet ); - BOOL IsDeleteUserData() const; - BOOL IsUseUserData() const; + void SetTemplate( sal_Bool b ) { m_bHasTemplate = b; } + sal_Bool HasTemplate() const { return m_bHasTemplate; } + void SetDeleteUserData( sal_Bool bSet ); + void SetUseUserData( sal_Bool bSet ); + sal_Bool IsDeleteUserData() const; + sal_Bool IsUseUserData() const; std::vector< CustomProperty* > GetCustomProperties() const; - void ClearCustomProperties(); - void AddCustomProperty( const ::rtl::OUString& sName, - const com::sun::star::uno::Any& rValue ); + void ClearCustomProperties(); + void AddCustomProperty( const ::rtl::OUString& sName, + const com::sun::star::uno::Any& rValue ); virtual SfxPoolItem* Clone( SfxItemPool* pPool = NULL ) const; virtual int operator==( const SfxPoolItem& ) const; @@ -262,41 +254,6 @@ public: static SfxTabPage* Create( Window* pParent, const SfxItemSet& ); }; -// class SfxDocumentUserPage --------------------------------------------- - -class SfxDocumentUserPage : public SfxTabPage -{ -private: - BOOL bLabelModified; - - FixedText aInfo1Ft; - Edit aInfo1Ed; - FixedText aInfo2Ft; - Edit aInfo2Ed; - FixedText aInfo3Ft; - Edit aInfo3Ed; - FixedText aInfo4Ft; - Edit aInfo4Ed; - PushButton aEditLabelBtn; - SfxDocumentInfoItem* pInfoItem; - -#if _SOLAR__PRIVATE - DECL_LINK( EditLabelHdl, PushButton * ); - - String GetLabelText_Impl( FixedText* pLabel ); - void SetLabelText_Impl( FixedText* pLabel, const String& rNewLabel ); -#endif - -protected: - SfxDocumentUserPage( Window* pParent, const SfxItemSet& ); - - virtual BOOL FillItemSet( SfxItemSet& ); - virtual void Reset( const SfxItemSet& ); - -public: - static SfxTabPage* Create( Window* pParent, const SfxItemSet& ); -}; - // class SfxInternetPage ------------------------------------------------- class TargetList; diff --git a/sfx2/inc/sfx2/docfile.hxx b/sfx2/inc/sfx2/docfile.hxx index 9e82e6f011e5..bebcdc684d89 100644 --- a/sfx2/inc/sfx2/docfile.hxx +++ b/sfx2/inc/sfx2/docfile.hxx @@ -183,7 +183,8 @@ public: #endif void CheckFileDate( const ::com::sun::star::util::DateTime& aInitDate ); - ::com::sun::star::util::DateTime GetInitFileDate(); + sal_Bool DocNeedsFileDateCheck(); + ::com::sun::star::util::DateTime GetInitFileDate( sal_Bool bIgnoreOldValue ); ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContent > GetContent() const; const String& GetPhysicalName() const; diff --git a/sfx2/inc/sfx2/filedlghelper.hxx b/sfx2/inc/sfx2/filedlghelper.hxx index c93af303158c..f9377f9908ea 100644 --- a/sfx2/inc/sfx2/filedlghelper.hxx +++ b/sfx2/inc/sfx2/filedlghelper.hxx @@ -229,8 +229,16 @@ public: void SetTitle( const String& rNewTitle ); String GetPath() const; + /** @deprected: Don't use this method to retrieve the selected files + There are file picker which can provide multiple selected file which belong + to different folders. As this method always provides the root folder for all selected + files this cannot work. + */ ::com::sun::star::uno::Sequence< ::rtl::OUString > GetMPath() const; + /** Provides the selected files with full path information */ + ::com::sun::star::uno::Sequence< ::rtl::OUString > GetSelectedFiles() const; + void AddFilter( const String& rFilterName, const String& rExtension ); void SetCurrentFilter( const String& rFilter ); diff --git a/sfx2/inc/sfx2/msg.hxx b/sfx2/inc/sfx2/msg.hxx index 8147a9f67df1..66e8c07ba357 100644 --- a/sfx2/inc/sfx2/msg.hxx +++ b/sfx2/inc/sfx2/msg.hxx @@ -7,7 +7,7 @@ * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: msg.hxx,v $ - * $Revision: 1.4 $ + * $Revision: 1.4.82.2 $ * * This file is part of OpenOffice.org. * @@ -155,11 +155,17 @@ SFX_DECL_TYPE(5); SFX_DECL_TYPE(6); SFX_DECL_TYPE(7); SFX_DECL_TYPE(8); +SFX_DECL_TYPE(10); // for SfxDocInfoItem SFX_DECL_TYPE(11); +SFX_DECL_TYPE(13); // for SwAddPrinterItem, Sd... SFX_DECL_TYPE(14); -SFX_DECL_TYPE(17); // fuer SvxAddressItem, SvxSearchItem -SFX_DECL_TYPE(18); // fuer SfxDocInfoItem +SFX_DECL_TYPE(16); // for SwDocDisplayItem +SFX_DECL_TYPE(17); // for SvxAddressItem +SFX_DECL_TYPE(18); // for SvxSearchItem + +// all SfxTypes must be in this header +#undef SFX_DECL_TYPE #define SFX_SLOT_ARG( aShellClass, id, GroupId, ExecMethodPtr, StateMethodPtr, Flags, ItemClass, nArg0, nArgs, Name, Prop ) \ { id, GroupId, id, Flags | Prop, \ diff --git a/sfx2/inc/sfx2/objsh.hxx b/sfx2/inc/sfx2/objsh.hxx index 53b074aa8829..71f1729840c0 100644 --- a/sfx2/inc/sfx2/objsh.hxx +++ b/sfx2/inc/sfx2/objsh.hxx @@ -63,6 +63,7 @@ #include <sot/storage.hxx> #include <rsc/rscsfx.hxx> +#include <sfx2/XmlIdRegistry.hxx> #include <sfx2/shell.hxx> #include <comphelper/embeddedobjectcontainer.hxx> #include <com/sun/star/frame/XModel.hpp> @@ -207,11 +208,13 @@ enum SfxTitleQuery class SfxToolBoxConfig; struct TransferableObjectDescriptor; -class SFX2_DLLPUBLIC SfxObjectShell: public SfxShell, virtual public SotObject, public ::comphelper::IEmbeddedHelper +class SFX2_DLLPUBLIC SfxObjectShell : + public SfxShell, virtual public SotObject, + public ::comphelper::IEmbeddedHelper, public ::sfx2::IXmlIdRegistrySupplier { friend struct ModifyBlocker_Impl; -public: +private: struct SfxObjectShell_Impl* pImp; // interne Daten SfxMedium * pMedium; // Beschreibung der Datei bzw. des Storage, in dem sich das Objekt befindet @@ -524,6 +527,7 @@ public: //determine the position of the "Automatic" filter in the stylist void SetAutoStyleFilterIndex(sal_uInt16 nSet); + sal_uInt16 GetAutoStyleFilterIndex(); virtual sal_Bool HasBasic() const; BasicManager* GetBasicManager() const; com::sun::star::uno::Reference< com::sun::star::script::XLibraryContainer > diff --git a/sfx2/inc/sfx2/passwd.hxx b/sfx2/inc/sfx2/passwd.hxx index 4efde4dc4a73..bb4e1b8c1561 100644 --- a/sfx2/inc/sfx2/passwd.hxx +++ b/sfx2/inc/sfx2/passwd.hxx @@ -81,6 +81,7 @@ public: String GetConfirm() const { return maConfirmED.GetText(); } void SetMinLen( USHORT Len ); + void SetMaxLen( USHORT Len ); void SetEditHelpId( ULONG nId ) { maPasswordED.SetHelpId( nId ); } void ShowExtras( USHORT nExtras ) { mnExtras = nExtras; } diff --git a/sfx2/inc/sfx2/sfx.hrc b/sfx2/inc/sfx2/sfx.hrc index c29d0797bf81..fbc5e6f58d1c 100644 --- a/sfx2/inc/sfx2/sfx.hrc +++ b/sfx2/inc/sfx2/sfx.hrc @@ -367,14 +367,6 @@ #define MID_DOCINFO_KEYWORDS 0x17 #define MID_DOCINFO_SUBJECT 0x1b #define MID_DOCINFO_TITLE 0x1d -#define MID_DOCINFO_FIELD1TITLE 0x20 -#define MID_DOCINFO_FIELD2TITLE 0x21 -#define MID_DOCINFO_FIELD3TITLE 0x22 -#define MID_DOCINFO_FIELD4TITLE 0x23 -#define MID_DOCINFO_FIELD1 0x24 -#define MID_DOCINFO_FIELD2 0x25 -#define MID_DOCINFO_FIELD3 0x26 -#define MID_DOCINFO_FIELD4 0x27 #define MID_DOCINFO_AUTOLOADENABLED 0x2d #define MID_DOCINFO_AUTOLOADURL 0x2e #define MID_DOCINFO_AUTOLOADSECS 0x2f diff --git a/sfx2/inc/sfx2/sfxbasemodel.hxx b/sfx2/inc/sfx2/sfxbasemodel.hxx index 7cbd6e069d66..324080484c81 100644 --- a/sfx2/inc/sfx2/sfxbasemodel.hxx +++ b/sfx2/inc/sfx2/sfxbasemodel.hxx @@ -47,6 +47,9 @@ #include <com/sun/star/document/XDocumentInfo.hpp> #include <com/sun/star/document/XDocumentInfoSupplier.hpp> #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> + +#include <com/sun/star/rdf/XDocumentMetadataAccess.hpp> + #include <com/sun/star/document/XEventBroadcaster.hpp> #include <com/sun/star/document/XEventListener.hpp> #include <com/sun/star/document/XEventsSupplier.hpp> @@ -79,13 +82,12 @@ #include <com/sun/star/uno/Reference.hxx> #include <com/sun/star/uno/Any.hxx> #include <cppuhelper/weak.hxx> +#include <cppuhelper/basemutex.hxx> #include <cppuhelper/typeprovider.hxx> #include <com/sun/star/script/XStarBasicAccess.hpp> #include <osl/mutex.hxx> -#ifndef _LINK_HXX_ #include <tools/link.hxx> -#endif #include <com/sun/star/document/XViewDataSupplier.hpp> #include <com/sun/star/lang/XUnoTunnel.hpp> @@ -93,9 +95,9 @@ #include <com/sun/star/task/XInteractionHandler.hpp> //________________________________________________________________________________________________________ -#if ! defined(INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_28) -#define INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_28 -#define COMPHELPER_IMPLBASE_INTERFACE_NUMBER 28 +#if ! defined(INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_29) +#define INCLUDED_COMPHELPER_IMPLBASE_VAR_HXX_29 +#define COMPHELPER_IMPLBASE_INTERFACE_NUMBER 29 #include <comphelper/implbase_var.hxx> #endif @@ -204,11 +206,6 @@ struct IMPL_SfxBaseModel_DataContainer ; // impl. struct to hold member o // class declarations //________________________________________________________________________________________________________ -struct IMPL_SfxBaseModel_MutexContainer -{ - MUTEX m_aMutex ; -} ; - /**_______________________________________________________________________________________________________ @short - @@ -217,7 +214,8 @@ struct IMPL_SfxBaseModel_MutexContainer @implements XChild XComponent XDocumentInfoSupplier - XDocumentPropertiesSupplier + document::XDocumentPropertiesSupplier + rdf::XDocumentMetadataAccess XEventListener XModel XModifiable2 @@ -230,13 +228,14 @@ struct IMPL_SfxBaseModel_MutexContainer XCloseable XCloseBroadcaster - @base IMPL_MutexContainer + @base cppu::BaseMutex SfxListener */ -typedef ::comphelper::WeakImplHelper28 < XCHILD +typedef ::comphelper::WeakImplHelper29 < XCHILD , XDOCUMENTINFOSUPPLIER , ::com::sun::star::document::XDocumentPropertiesSupplier + , ::com::sun::star::rdf::XDocumentMetadataAccess , XEVENTBROADCASTER , XEVENTLISTENER , XEVENTSSUPPLIER @@ -264,8 +263,8 @@ typedef ::comphelper::WeakImplHelper28 < XCHILD , XUNTITLEDNUMBERS > SfxBaseModel_Base; -class SFX2_DLLPUBLIC SfxBaseModel : public SfxBaseModel_Base - , public IMPL_SfxBaseModel_MutexContainer +class SFX2_DLLPUBLIC SfxBaseModel : protected ::cppu::BaseMutex + , public SfxBaseModel_Base , public SfxListener { @@ -1290,6 +1289,114 @@ public: throw (css::uno::RuntimeException); //____________________________________________________________________________________________________ + + // ::com::sun::star::rdf::XNode: + virtual ::rtl::OUString SAL_CALL getStringValue() + throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::rdf::XURI: + virtual ::rtl::OUString SAL_CALL getNamespace() + throw (::com::sun::star::uno::RuntimeException); + virtual ::rtl::OUString SAL_CALL getLocalName() + throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::rdf::XRepositorySupplier: + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XRepository > SAL_CALL getRDFRepository() + throw (::com::sun::star::uno::RuntimeException); + + // ::com::sun::star::rdf::XDocumentMetadataAccess: + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > SAL_CALL + getElementByMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > SAL_CALL + getElementByURI(const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xURI) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException); + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > > SAL_CALL getMetadataGraphsWithType( + const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xType) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI> SAL_CALL + addMetadataFile(const ::rtl::OUString & i_rFileName, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< ::com::sun::star::rdf::XURI > + > & i_rTypes) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::ElementExistException); + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI> SAL_CALL + importMetadataFile(::sal_Int16 i_Format, + const ::com::sun::star::uno::Reference< + ::com::sun::star::io::XInputStream > & i_xInStream, + const ::rtl::OUString & i_rFileName, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xBaseURI, + const ::com::sun::star::uno::Sequence< + ::com::sun::star::uno::Reference< ::com::sun::star::rdf::XURI > + > & i_rTypes) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::datatransfer::UnsupportedFlavorException, + ::com::sun::star::container::ElementExistException, + ::com::sun::star::rdf::ParseException, + ::com::sun::star::io::IOException); + virtual void SAL_CALL removeMetadataFile( + const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xGraphName) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException); + virtual void SAL_CALL addContentOrStylesFile( + const ::rtl::OUString & i_rFileName) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::ElementExistException); + virtual void SAL_CALL removeContentOrStylesFile( + const ::rtl::OUString & i_rFileName) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::container::NoSuchElementException); + + virtual void SAL_CALL loadMetadataFromStorage( + const ::com::sun::star::uno::Reference< + ::com::sun::star::embed::XStorage > & i_xStorage, + const ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XURI > & i_xBaseURI, + const ::com::sun::star::uno::Reference< + ::com::sun::star::task::XInteractionHandler> & i_xHandler) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::lang::WrappedTargetException); + virtual void SAL_CALL storeMetadataToStorage( + const ::com::sun::star::uno::Reference< + ::com::sun::star::embed::XStorage > & i_xStorage) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::lang::WrappedTargetException); + virtual void SAL_CALL loadMetadataFromMedium( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue > & i_rMedium) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::lang::WrappedTargetException); + virtual void SAL_CALL storeMetadataToMedium( + const ::com::sun::star::uno::Sequence< + ::com::sun::star::beans::PropertyValue > & i_rMedium) + throw (::com::sun::star::uno::RuntimeException, + ::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::lang::WrappedTargetException); + + + //____________________________________________________________________________________________________ // SfxListener //____________________________________________________________________________________________________ @@ -1370,6 +1477,7 @@ public: /** returns true if someone added a XEventListener to this XEventBroadcaster */ sal_Bool hasEventListeners() const; + protected: /* returns a unique id for the model that is valid as long as the document diff --git a/sfx2/inc/sfx2/sfxsids.hrc b/sfx2/inc/sfx2/sfxsids.hrc index 5efa13713133..e600c812a373 100644 --- a/sfx2/inc/sfx2/sfxsids.hrc +++ b/sfx2/inc/sfx2/sfxsids.hrc @@ -143,6 +143,7 @@ #define SID_CURRENTTIME (SID_SFX_START + 311) #define SID_CURRENTDATE (SID_SFX_START + 312) #define SID_VERSION_VISIBLE (SID_SFX_START + 313) +#define SID_PASTE_UNFORMATTED (SID_SFX_START + 314) #define SID_PRINTER_NOTFOUND_WARN (SID_SFX_START + 320) #define SID_PRINTER_USETHREAD (SID_SFX_START + 321) #define SID_PRINTER_NAME (SID_SFX_START + 322) diff --git a/sfx2/prj/build.lst b/sfx2/prj/build.lst index fc6984c17ada..89e618e8fc12 100644 --- a/sfx2/prj/build.lst +++ b/sfx2/prj/build.lst @@ -1,4 +1,4 @@ -sf sfx2 : l10n idl basic xmlscript framework shell setup_native sax SYSTRAY_GTK:libegg NULL +sf sfx2 : l10n idl basic xmlscript framework shell setup_native sax SYSTRAY_GTK:libegg LIBXML2:libxml2 NULL sf sfx2 usr1 - all sf_mkout NULL sf sfx2\inc nmake - all sf_inc NULL sf sfx2\prj get - all sf_prj NULL diff --git a/sfx2/prj/d.lst b/sfx2/prj/d.lst index 03ae35e5c3d7..77acce9a7be9 100644 --- a/sfx2/prj/d.lst +++ b/sfx2/prj/d.lst @@ -128,3 +128,6 @@ mkdir: %_DEST%\inc%_EXT%\sfx2 ..\inc\sfx2\layout-tabdlg.hxx %_DEST%\inc%_EXT%\sfx2\layout-tabdlg.hxx ..\inc\sfx2\layout-post.hxx %_DEST%\inc%_EXT%\sfx2\layout-post.hxx ..\inc\sfx2\layout-pre.hxx %_DEST%\inc%_EXT%\sfx2\layout-pre.hxx +..\inc\sfx2\XmlIdRegistry.hxx %_DEST%\inc%_EXT%\sfx2\XmlIdRegistry.hxx +..\inc\sfx2\DocumentMetadataAccess.hxx %_DEST%\inc%_EXT%\sfx2\DocumentMetadataAccess.hxx +..\inc\sfx2\Metadatable.hxx %_DEST%\inc%_EXT%\sfx2\Metadatable.hxx diff --git a/sfx2/qa/complex/DocumentMetadataAccessTest.java b/sfx2/qa/complex/DocumentMetadataAccessTest.java new file mode 100644 index 000000000000..0983aec1bd37 --- /dev/null +++ b/sfx2/qa/complex/DocumentMetadataAccessTest.java @@ -0,0 +1,1270 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DocumentMetadataAccessTest.java,v $ + * + * $Revision: 1.1.2.9 $ + * + * 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. + ************************************************************************/ + +package complex.framework; + +import complexlib.ComplexTestCase; +import helper.StreamSimulator; + +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import com.sun.star.uno.Any; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XInitialization; +import com.sun.star.lang.XServiceInfo; +import com.sun.star.lang.IllegalArgumentException; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lang.WrappedTargetRuntimeException; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.PropertyValue; +import com.sun.star.beans.StringPair; +import com.sun.star.container.XEnumerationAccess; +import com.sun.star.container.XEnumeration; +import com.sun.star.container.ElementExistException; +import com.sun.star.container.NoSuchElementException; +import com.sun.star.io.XInputStream; +import com.sun.star.io.XOutputStream; +import com.sun.star.util.XCloseable; +import com.sun.star.frame.XStorable; +import com.sun.star.frame.XLoadable; +import com.sun.star.text.XTextDocument; +import com.sun.star.text.XTextRange; +import com.sun.star.text.XText; +import com.sun.star.rdf.*; + +/** + * Test case for interface com.sun.star.rdf.XDocumentMetadataAccess + * Currently, this service is implemented in + * sfx2/source/doc/DocumentMetadataAccess.cxx + * + * Actually, this is not a service, so we need to create a document and + * go from there... + * + * @author mst + */ +public class DocumentMetadataAccessTest extends ComplexTestCase +{ + XMultiServiceFactory xMSF; + XComponentContext xContext; + String tempDir; + + String nsRDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; + String nsRDFS = "http://www.w3.org/2000/01/rdf-schema#"; + String nsPkg="http://docs.oasis-open.org/opendocument/meta/package/common#"; + String nsODF ="http://docs.oasis-open.org/opendocument/meta/package/odf#"; + + XURI foo; + XURI bar; + XURI baz; + + static XURI rdf_type; + static XURI rdfs_label; + static XURI pkg_Document; + static XURI pkg_hasPart; + static XURI pkg_MetadataFile; + static XURI odf_ContentFile; + static XURI odf_StylesFile; + static XURI odf_Element; + static XBlankNode blank1; + static XBlankNode blank2; + static XBlankNode blank3; + static XBlankNode blank4; + static String manifestPath = "manifest.rdf"; + static String contentPath = "content.xml"; + static String stylesPath = "styles.xml"; + static String fooPath = "foo.rdf"; + static String fooBarPath = "meta/foo/bar.rdf"; + + XRepository xRep; + XRepositorySupplier xRS; + XDocumentMetadataAccess xDMA; + + public String[] getTestMethodNames () + { + return new String[] { "check", "checkRDFa" }; + } + + public void before() + { + try { + + xMSF = (XMultiServiceFactory) param.getMSF(); + assure("could not create MultiServiceFactory.", xMSF != null); + XPropertySet xPropertySet = (XPropertySet) + UnoRuntime.queryInterface(XPropertySet.class, xMSF); + Object defaultCtx = xPropertySet.getPropertyValue("DefaultContext"); + xContext = (XComponentContext) + UnoRuntime.queryInterface(XComponentContext.class, defaultCtx); + assure("could not get component context.", xContext != null); + + tempDir = util.utils.getOfficeTemp/*Dir*/(xMSF); + log.println("tempdir: " + tempDir); + + foo = URI.create(xContext, "uri:foo"); + assure("foo", null != foo); + bar = URI.create(xContext, "uri:bar"); + assure("bar", null != bar); + baz = URI.create(xContext, "uri:baz"); + assure("baz", null != baz); + + blank1 = BlankNode.create(xContext, "_:1"); + assure("blank1", null != blank1); + blank2 = BlankNode.create(xContext, "_:2"); + assure("blank2", null != blank2); + blank3 = BlankNode.create(xContext, "_:3"); + assure("blank3", null != blank3); + blank4 = BlankNode.create(xContext, "_:4"); + assure("blank4", null != blank4); + rdf_type = URI.createKnown(xContext, URIs.RDF_TYPE); + assure("rdf_type", null != rdf_type); + rdfs_label = URI.createKnown(xContext, URIs.RDFS_LABEL); + assure("rdfs_label", null != rdfs_label); + pkg_Document = URI.createKnown(xContext, URIs.PKG_DOCUMENT); + assure("pkg_Document", null != pkg_Document); + pkg_hasPart = URI.createKnown(xContext, URIs.PKG_HASPART); + assure("pkg_hasPart", null != pkg_hasPart); + pkg_MetadataFile = URI.createKnown(xContext, URIs.PKG_METADATAFILE); + assure("pkg_MetadataFile", null != pkg_MetadataFile); + odf_ContentFile = URI.createKnown(xContext, URIs.ODF_CONTENTFILE); + assure("odf_ContentFile", null != odf_ContentFile); + odf_StylesFile = URI.createKnown(xContext, URIs.ODF_STYLESFILE); + assure("odf_StylesFile", null != odf_StylesFile); + odf_Element = URI.createKnown(xContext, URIs.ODF_ELEMENT); + assure("odf_Element", null != odf_Element); + + } catch (Exception e) { + report(e); + } + } + + public void after() + { + xRep = null; + xRS = null; + xDMA = null; + } + + public void check() + { + XComponent xComp = null; + XComponent xComp2 = null; + try { + XEnumeration xStmtsEnum; + XNamedGraph xManifest; + + log.println("Creating document with Repository..."); + + // we cannot create a XDMA directly, we must create + // a document and get it from there :( + // create document + PropertyValue[] loadProps = new PropertyValue[1]; + loadProps[0] = new PropertyValue(); + loadProps[0].Name = "Hidden"; + loadProps[0].Value = new Boolean(true); + xComp = util.DesktopTools.openNewDoc(xMSF, "swriter", loadProps); + XTextDocument xText = (XTextDocument) UnoRuntime.queryInterface( + XTextDocument.class, xComp); + + XRepositorySupplier xRS = (XRepositorySupplier) + UnoRuntime.queryInterface(XRepositorySupplier.class, xComp); + assure("xRS null", null != xRS); + XDocumentMetadataAccess xDMA = (XDocumentMetadataAccess) + UnoRuntime.queryInterface(XDocumentMetadataAccess.class, xRS); + assure("xDMA null", null != xDMA); + xRep = xRS.getRDFRepository(); + assure("xRep null", null != xRep); + + log.println("...done"); + + log.println("Checking that new repository is initialized..."); + + XURI xBaseURI = (XURI) xDMA; + String baseURI = xBaseURI.getStringValue(); + assure("new: baseURI", + null != xBaseURI && !xBaseURI.getStringValue().equals("")); + + assure("new: # graphs", 1 == xRep.getGraphNames().length); + XURI manifest = URI.createNS(xContext, xBaseURI.getStringValue(), + manifestPath); + xManifest = xRep.getGraph(manifest); + assure("new: manifest graph", null != xManifest); + + Statement[] manifestStmts = getManifestStmts(xBaseURI); + xStmtsEnum = xRep.getStatements(null, null, null); + assure("new: manifest graph", eq(xStmtsEnum, manifestStmts)); + + log.println("...done"); + + log.println("Checking some invalid args..."); + + String content = "behold, for i am the content."; + XTextRange xTR = new TestRange(content); + XMetadatable xM = (XMetadatable) xTR; + + try { + xDMA.getElementByURI(null); + assure("getElementByURI: null allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.getMetadataGraphsWithType(null); + assure("getMetadataGraphsWithType: null URI allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("", new XURI[0]); + assure("addMetadataFile: empty filename allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("/foo", new XURI[0]); + assure("addMetadataFile: absolute filename allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("fo\"o", new XURI[0]); + assure("addMetadataFile: invalid filename allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("../foo", new XURI[0]); + assure("addMetadataFile: filename with .. allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("foo/../../bar", new XURI[0]); + assure("addMetadataFile: filename with nest .. allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("foo/././bar", new XURI[0]); + assure("addMetadataFile: filename with nest . allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("content.xml", new XURI[0]); + assure("addMetadataFile: content.xml allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("styles.xml", new XURI[0]); + assure("addMetadataFile: styles.xml allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("meta.xml", new XURI[0]); + assure("addMetadataFile: meta.xml allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addMetadataFile("settings.xml", new XURI[0]); + assure("addMetadataFile: settings.xml allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.importMetadataFile(FileFormat.RDF_XML, null, "foo", + foo, new XURI[0]); + assure("importMetadataFile: null stream allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + XInputStream xFooIn = + new StreamSimulator(tempDir + "empty.rdf", true, param); + xDMA.importMetadataFile(FileFormat.RDF_XML, xFooIn, "", + foo, new XURI[0]); + assure("importMetadataFile: empty filename allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + XInputStream xFooIn = + new StreamSimulator(tempDir + "empty.rdf", true, param); + xDMA.importMetadataFile(FileFormat.RDF_XML, xFooIn, "meta.xml", + foo, new XURI[0]); + assure("importMetadataFile: meta.xml filename allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + XInputStream xFooIn = + new StreamSimulator(tempDir + "empty.rdf", true, param); + xDMA.importMetadataFile(FileFormat.RDF_XML, + xFooIn, "foo", null, new XURI[0]); + assure("importMetadataFile: null base URI allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + XInputStream xFooIn = + new StreamSimulator(tempDir + "empty.rdf", true, param); + xDMA.importMetadataFile(FileFormat.RDF_XML, + xFooIn, "foo", rdf_type, new XURI[0]); + assure("importMetadataFile: non-absolute base URI allowed", + false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.removeMetadataFile(null); + assure("removeMetadataFile: null URI allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addContentOrStylesFile(""); + assure("addContentOrStylesFile: empty filename allowed", + false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addContentOrStylesFile("/content.xml"); + assure("addContentOrStylesFile: absolute filename allowed", + false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.addContentOrStylesFile("foo.rdf"); + assure("addContentOrStylesFile: invalid filename allowed", + false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.removeContentOrStylesFile(""); + assure("removeContentOrStylesFile: empty filename allowed", + false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.loadMetadataFromStorage(null, foo, null); + assure("loadMetadataFromStorage: null storage allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.storeMetadataToStorage(null/*, base*/); + assure("storeMetadataToStorage: null storage allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.loadMetadataFromMedium(new PropertyValue[0]); + assure("loadMetadataFromMedium: empty medium allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + try { + xDMA.storeMetadataToMedium(new PropertyValue[0]); + assure("storeMetadataToMedium: empty medium allowed", false); + } catch (IllegalArgumentException e) { + // ignore + } + + log.println("...done"); + + log.println("Checking file addition/removal..."); + + xDMA.removeContentOrStylesFile(contentPath); + xStmtsEnum = xManifest.getStatements(null, null, null); + assure("removeContentOrStylesFile (content)", + eq(xStmtsEnum, new Statement[] { + manifestStmts[0], manifestStmts[2], manifestStmts[4] + })); + + xDMA.addContentOrStylesFile(contentPath); + xStmtsEnum = xManifest.getStatements(null, null, null); + assure("addContentOrStylesFile (content)", + eq(xStmtsEnum, manifestStmts)); + + xDMA.removeContentOrStylesFile(stylesPath); + xStmtsEnum = xManifest.getStatements(null, null, null); + assure("removeContentOrStylesFile (styles)", + eq(xStmtsEnum, new Statement[] { + manifestStmts[0], manifestStmts[1], manifestStmts[3] + })); + + xDMA.addContentOrStylesFile(stylesPath); + xStmtsEnum = xManifest.getStatements(null, null, null); + assure("addContentOrStylesFile (styles)", + eq(xStmtsEnum, manifestStmts)); + + XURI xFoo = URI.createNS(xContext, xBaseURI.getStringValue(), + fooPath); + Statement xM_BaseHaspartFoo = + new Statement(xBaseURI, pkg_hasPart, xFoo, manifest); + Statement xM_FooTypeMetadata = + new Statement(xFoo, rdf_type, pkg_MetadataFile, manifest); + Statement xM_FooTypeBar = + new Statement(xFoo, rdf_type, bar, manifest); + xDMA.addMetadataFile(fooPath, new XURI[] { bar }); + xStmtsEnum = xManifest.getStatements(null, null, null); + assure("addMetadataFile", + eq(xStmtsEnum, merge(manifestStmts, new Statement[] { + xM_BaseHaspartFoo, xM_FooTypeMetadata, xM_FooTypeBar + }))); + + XURI[] graphsBar = xDMA.getMetadataGraphsWithType(bar); + assure("getMetadataGraphsWithType", + graphsBar.length == 1 && eq(graphsBar[0], xFoo)); + + + xDMA.removeMetadataFile(xFoo); + xStmtsEnum = xManifest.getStatements(null, null, null); + assure("removeMetadataFile", + eq(xStmtsEnum, manifestStmts)); + + log.println("...done"); + + log.println("Checking mapping..."); + + XEnumerationAccess xTextEnum = (XEnumerationAccess) + UnoRuntime.queryInterface(XEnumerationAccess.class, + xText.getText()); + Object o = xTextEnum.createEnumeration().nextElement(); + XMetadatable xMeta1 = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, o); + + XURI uri; + XMetadatable xMeta; + xMeta = xDMA.getElementByURI(xMeta1); + assure("getElementByURI: null", null != xMeta); + String XmlId = xMeta.getMetadataReference().Second; + String XmlId1 = xMeta1.getMetadataReference().Second; + assure("getElementByURI: no xml id", !XmlId.equals("")); + assure("getElementByURI: different xml id", XmlId.equals(XmlId1)); + + log.println("...done"); + + log.println("Checking storing and loading..."); + + XURI xFoobar = URI.createNS(xContext, xBaseURI.getStringValue(), + fooBarPath); + Statement[] metadataStmts = getMetadataFileStmts(xBaseURI, + fooBarPath); + xDMA.addMetadataFile(fooBarPath, new XURI[0]); + xStmtsEnum = xRep.getStatements(null, null, null); + assure("addMetadataFile", + eq(xStmtsEnum, merge(manifestStmts, metadataStmts ))); + + Statement xFoobar_FooBarFoo = + new Statement(foo, bar, foo, xFoobar); + xRep.getGraph(xFoobar).addStatement(foo, bar, foo); + xStmtsEnum = xRep.getStatements(null, null, null); + assure("addStatement", + eq(xStmtsEnum, merge(manifestStmts, merge(metadataStmts, + new Statement[] { xFoobar_FooBarFoo })))); + + PropertyValue noMDNoContentFile = new PropertyValue(); + noMDNoContentFile.Name = "URL"; + noMDNoContentFile.Value = util.utils.getFullTestURL("CUSTOM.odt"); + PropertyValue noMDFile = new PropertyValue(); + noMDFile.Name = "URL"; + noMDFile.Value = util.utils.getFullTestURL("TEST.odt"); + PropertyValue file = new PropertyValue(); + file.Name = "URL"; + file.Value = tempDir + "TESTDMA.odt"; + /* + PropertyValue baseURL = new PropertyValue(); + baseURL.Name = "DocumentBaseURL"; + baseURL.Value = tempDir + "TMP.odt"; + */ + PropertyValue mimetype = new PropertyValue(); + mimetype.Name = "MediaType"; + mimetype.Value = "application/vnd.oasis.opendocument.text"; + PropertyValue[] argsEmptyNoContent = { mimetype, noMDNoContentFile}; + PropertyValue[] argsEmpty = { mimetype, noMDFile }; + PropertyValue[] args = { mimetype, file }; + + xStmtsEnum = xRep.getStatements(null, null, null); + XURI[] graphs = xRep.getGraphNames(); + + xDMA.storeMetadataToMedium(args); + + // this should re-init + xDMA.loadMetadataFromMedium(argsEmptyNoContent); + xRep = xRS.getRDFRepository(); + assure("xRep null", null != xRep); + assure("baseURI still tdoc?", + !baseURI.equals(xDMA.getStringValue())); + Statement[] manifestStmts2 = getManifestStmts((XURI) xDMA); + xStmtsEnum = xRep.getStatements(null, null, null); + // there is no content or styles file in here, so we have just + // the package stmt + assure("loadMetadataFromMedium (no metadata, no content)", + eq(xStmtsEnum, new Statement[] { manifestStmts2[0] })); + + // this should re-init + xDMA.loadMetadataFromMedium(argsEmpty); + xRep = xRS.getRDFRepository(); + assure("xRep null", null != xRep); + assure("baseURI still tdoc?", + !baseURI.equals(xDMA.getStringValue())); + Statement[] manifestStmts3 = getManifestStmts((XURI) xDMA); + + xStmtsEnum = xRep.getStatements(null, null, null); + assure("loadMetadataFromMedium (no metadata)", + eq(xStmtsEnum, manifestStmts3)); + + xDMA.loadMetadataFromMedium(args); + xRep = xRS.getRDFRepository(); + assure("xRep null", null != xRep); + Statement[] manifestStmts4 = getManifestStmts((XURI) xDMA); + Statement[] metadataStmts4 = getMetadataFileStmts((XURI) xDMA, + fooBarPath); + + xStmtsEnum = xRep.getStatements(null, null, null); + assure("some graph(s) not reloaded", + graphs.length == xRep.getGraphNames().length); + + XURI xFoobar4 = URI.createNS(xContext, xDMA.getStringValue(), + fooBarPath); + Statement xFoobar_FooBarFoo4 = + new Statement(foo, bar, foo, xFoobar4); + assure("loadMetadataFromMedium (re-load)", + eq(xStmtsEnum, merge(manifestStmts4, merge(metadataStmts4, + new Statement[] { xFoobar_FooBarFoo4 })))); + + log.println("...done"); + + log.println("Checking storing and loading via model..."); + + String f = tempDir + "TESTPARA.odt"; + + XStorable xStor = (XStorable) UnoRuntime.queryInterface( + XStorable.class, xRS); + + xStor.storeToURL(f, new PropertyValue[0]); + + xComp2 = util.DesktopTools.loadDoc(xMSF, f, loadProps); + + XDocumentMetadataAccess xDMA2 = (XDocumentMetadataAccess) + UnoRuntime.queryInterface(XDocumentMetadataAccess.class, + xComp2); + assure("xDMA2 null", null != xDMA2); + + XRepositorySupplier xRS2 = (XRepositorySupplier) + UnoRuntime.queryInterface(XRepositorySupplier.class, xComp2); + assure("xRS2 null", null != xRS2); + + XRepository xRep2 = xRS2.getRDFRepository(); + assure("xRep2 null", null != xRep2); + + Statement[] manifestStmts5 = getManifestStmts((XURI) xDMA2); + Statement[] metadataStmts5 = getMetadataFileStmts((XURI) xDMA2, + fooBarPath); + XURI xFoobar5 = URI.createNS(xContext, xDMA2.getStringValue(), + fooBarPath); + Statement xFoobar_FooBarFoo5 = + new Statement(foo, bar, foo, xFoobar5); + xStmtsEnum = xRep.getStatements(null, null, null); + XEnumeration xStmtsEnum2 = xRep2.getStatements(null, null, null); + assure("load: repository differs", + eq(xStmtsEnum2, merge(manifestStmts5, merge(metadataStmts5, + new Statement[] { xFoobar_FooBarFoo5 })))); + + log.println("...done"); + + } catch (Exception e) { + report(e); + } finally { + close(xComp); + close(xComp2); + } + } + + public void checkRDFa() + { + XComponent xComp = null; + String file; + try { + file = util.utils.getFullTestURL("TESTRDFA.odt"); + xComp = loadRDFa(file); + if (xComp != null) + { + file = tempDir + "TESTRDFA.odt"; + storeRDFa(xComp, file); + close(xComp); + xComp = loadRDFa(file); + } + } finally { + close(xComp); + } + } + + public void storeRDFa(XComponent xComp, String file) + { + try { + + log.println("Storing test document..."); + + XStorable xStor = (XStorable) UnoRuntime.queryInterface( + XStorable.class, xComp); + + xStor.storeToURL(file, new PropertyValue[0]); + + log.println("...done"); + + } catch (Exception e) { + report(e); + } + } + + public XComponent loadRDFa(String file) + { + XComponent xComp = null; + try { + + log.println("Loading test document..."); + + PropertyValue[] loadProps = new PropertyValue[1]; + loadProps[0] = new PropertyValue(); + loadProps[0].Name = "Hidden"; + loadProps[0].Value = new Boolean(true); + + + + xComp = util.DesktopTools.loadDoc(xMSF, file, loadProps); + + XRepositorySupplier xRS = (XRepositorySupplier) + UnoRuntime.queryInterface(XRepositorySupplier.class, xComp); + assure("xRS null", null != xRS); + + XDocumentRepository xRep = (XDocumentRepository) + UnoRuntime.queryInterface(XDocumentRepository.class, + xRS.getRDFRepository()); + assure("xRep null", null != xRep); + + XTextDocument xTextDoc = (XTextDocument) + UnoRuntime.queryInterface(XTextDocument.class, xComp); + + XText xText = xTextDoc.getText(); + + XEnumerationAccess xEA = (XEnumerationAccess) + UnoRuntime.queryInterface(XEnumerationAccess.class, xText); + XEnumeration xEnum = xEA.createEnumeration(); + + log.println("...done"); + + log.println("Checking RDFa in loaded test document..."); + + XMetadatable xPara; + Statement[] stmts; + + Statement x_FooBarLit1 = new Statement(foo, bar, mkLit("1"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 1", + eq(stmts, new Statement[] { + x_FooBarLit1 + })); + + Statement x_FooBarLit2 = new Statement(foo, bar, mkLit("2"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 2", + eq(stmts, new Statement[] { + x_FooBarLit2 + })); + + Statement x_BlankBarLit3 = + new Statement(blank1, bar, mkLit("3"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 3", + eq(stmts, new Statement[] { + x_BlankBarLit3 + })); + XBlankNode b3 = (XBlankNode) UnoRuntime.queryInterface( + XBlankNode.class, stmts[0].Subject); + + Statement x_BlankBarLit4 = + new Statement(blank2, bar, mkLit("4"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 4", + eq(stmts, new Statement[] { + x_BlankBarLit4 + })); + XBlankNode b4 = (XBlankNode) UnoRuntime.queryInterface( + XBlankNode.class, stmts[0].Subject); + + Statement x_BlankBarLit5 = + new Statement(blank1, bar, mkLit("5"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 5", + eq(stmts, new Statement[] { + x_BlankBarLit5 + })); + XBlankNode b5 = (XBlankNode) UnoRuntime.queryInterface( + XBlankNode.class, stmts[0].Subject); + + assure("RDFa: 3 != 4", + !b3.getStringValue().equals(b4.getStringValue())); + assure("RDFa: 3 == 5", + b3.getStringValue().equals(b5.getStringValue())); + + Statement x_FooBarLit6 = new Statement(foo, bar, mkLit("6"), null); + Statement x_FooBazLit6 = new Statement(foo, baz, mkLit("6"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 6", + eq(stmts, new Statement[] { + x_FooBarLit6, x_FooBazLit6 + })); + + Statement x_FooBarLit7 = new Statement(foo, bar, mkLit("7"), null); + Statement x_FooBazLit7 = new Statement(foo, baz, mkLit("7"), null); + Statement x_FooFooLit7 = new Statement(foo, foo, mkLit("7"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 7", + eq(stmts, new Statement[] { + x_FooBarLit7, x_FooBazLit7, x_FooFooLit7 + })); + + XNode lit = mkLit("a fooish bar"); + XNode lit_type= mkLit("a fooish bar", bar); + Statement x_FooBarLit = new Statement(foo, bar, lit, null); + Statement x_FooBarLittype = new Statement(foo, bar, lit_type, null); + + Statement x_FooLabelLit8 = + new Statement(foo, rdfs_label, mkLit("8"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 8", + eq(stmts, new Statement[] { + x_FooBarLit, x_FooLabelLit8 + })); + + Statement x_FooLabelLit9 = + new Statement(foo, rdfs_label, mkLit("9"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 9", + eq(stmts, new Statement[] { + x_FooBarLit, x_FooLabelLit9 + })); + + Statement x_FooLabelLit10 = + new Statement(foo, rdfs_label, mkLit("10"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 10", + eq(stmts, new Statement[] { + x_FooBarLittype, x_FooLabelLit10 + })); + + Statement x_FooBarLit11 + = new Statement(foo, bar, mkLit("11", bar), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 11", + eq(stmts, new Statement[] { + x_FooBarLit11 + })); + + XURI xFile = URI.createNS(xContext, file, "/" + contentPath); + Statement x_FileBarLit12 = + new Statement(xFile, bar, mkLit("12"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 12", + eq(stmts, new Statement[] { + x_FileBarLit12 + })); + + Statement x_FooLabelLit13 = + new Statement(foo, rdfs_label, mkLit("13"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 13", + eq(stmts, new Statement[] { + x_FooBarLit, x_FooLabelLit13 + })); + + Statement x_FooLabelLit14 = + new Statement(foo, rdfs_label, mkLit("14"), null); + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 14", + eq(stmts, new Statement[] { + x_FooBarLit, x_FooLabelLit14 + })); + + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 15", eq(stmts, new Statement[] { } )); + + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 16", eq(stmts, new Statement[] { } )); + + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 17", eq(stmts, new Statement[] { } )); + + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 18", eq(stmts, new Statement[] { } )); + + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 19", eq(stmts, new Statement[] { } )); + + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 20", eq(stmts, new Statement[] { } )); + + xPara = (XMetadatable) UnoRuntime.queryInterface( + XMetadatable.class, xEnum.nextElement()); + stmts = xRep.getStatementRDFa(xPara); + assure("RDFa: 21", eq(stmts, new Statement[] { } )); + + log.println("...done"); + + } catch (Exception e) { + report(e); + close(xComp); + } + return xComp; + } + + +// utilities ------------------------------------------------------------- + + public void report2(Exception e) + { + if (e instanceof WrappedTargetException) + { + log.println("Cause:"); + Exception cause = (Exception) + (((WrappedTargetException)e).TargetException); + log.println(cause.toString()); + report2(cause); + } else if (e instanceof WrappedTargetRuntimeException) { + log.println("Cause:"); + Exception cause = (Exception) + (((WrappedTargetRuntimeException)e).TargetException); + log.println(cause.toString()); + report2(cause); + } + } + + public void report(Exception e) { + log.println("Exception occurred:"); + e.printStackTrace((java.io.PrintWriter) log); + report2(e); + failed(); + } + + static void close(XComponent i_comp) + { + try { + XCloseable xClos = (XCloseable) UnoRuntime.queryInterface( + XCloseable.class, i_comp); + if (xClos != null) xClos.close(true); + } catch (Exception e) { + } + } + + XLiteral mkLit(String i_content) + { + return Literal.create(xContext, i_content); + } + + XLiteral mkLit(String i_content, XURI i_uri) + { + return Literal.createWithType(xContext, i_content, i_uri); + } + + static Statement[] merge(Statement[] i_A1, Statement[] i_A2) + { + // bah, java sucks... + Statement[] ret = new Statement[i_A1.length + i_A2.length]; + for (int i = 0; i < i_A1.length; ++i) { + ret[i] = i_A1[i]; + } + for (int i = 0; i < i_A2.length; ++i) { + ret[i+i_A1.length] = i_A2[i]; + } + return ret; + } + + public static String toS(XNode n) { + if (null == n) return "< null >"; + return n.getStringValue(); + } + + static boolean isBlank(XNode i_node) + { + XBlankNode blank = (XBlankNode) UnoRuntime.queryInterface( + XBlankNode.class, i_node); + return blank != null; + } + +/* + static class Statement implements XStatement + { + XResource m_Subject; + XResource m_Predicate; + XNode m_Object; + XURI m_Graph; + + Statement(XResource i_Subject, XResource i_Predicate, XNode i_Object, + XURI i_Graph) + { + m_Subject = i_Subject; + m_Predicate = i_Predicate; + m_Object = i_Object; + m_Graph = i_Graph; + } + + public XResource getSubject() { return m_Subject; } + public XResource getPredicate() { return m_Predicate; } + public XNode getObject() { return m_Object; } + public XURI getGraph() { return m_Graph; } + } +*/ + + static Statement[] toSeq(XEnumeration i_Enum) throws Exception + { + java.util.Collection c = new java.util.Vector(); + while (i_Enum.hasMoreElements()) { + Statement s = (Statement) i_Enum.nextElement(); +//log.println("toSeq: " + s.getSubject().getStringValue() + " " + s.getPredicate().getStringValue() + " " + s.getObject().getStringValue() + "."); + c.add(s); + } +// return (Statement[]) c.toArray(); + // java sucks + Object[] arr = c.toArray(); + Statement[] ret = new Statement[arr.length]; + for (int i = 0; i < arr.length; ++i) { + ret[i] = (Statement) arr[i]; + } + return ret; + } + + static XNode[][] toSeqs(XEnumeration i_Enum) throws Exception + { + java.util.Collection c = new java.util.Vector(); + while (i_Enum.hasMoreElements()) { + XNode[] s = (XNode[]) i_Enum.nextElement(); + c.add(s); + } +// return (XNode[][]) c.toArray(); + Object[] arr = c.toArray(); + XNode[][] ret = new XNode[arr.length][]; + for (int i = 0; i < arr.length; ++i) { + ret[i] = (XNode[]) arr[i]; + } + return ret; + } + + static class BindingComp implements java.util.Comparator + { + public int compare(Object i_Left, Object i_Right) + { + XNode[] left = (XNode[]) i_Left; + XNode[] right = (XNode[]) i_Right; + if (left.length != right.length) throw new RuntimeException(); + for (int i = 0; i < left.length; ++i) { + int eq = (left[i].getStringValue().compareTo( + right[i].getStringValue())); + if (eq != 0) return eq; + } + return 0; + } + } + + static class StmtComp implements java.util.Comparator + { + public int compare(Object i_Left, Object i_Right) + { + int eq; + Statement left = (Statement) i_Left; + Statement right = (Statement) i_Right; + if ((eq = cmp(left.Graph, right.Graph )) != 0) return eq; + if ((eq = cmp(left.Subject, right.Subject )) != 0) return eq; + if ((eq = cmp(left.Predicate, right.Predicate)) != 0) return eq; + if ((eq = cmp(left.Object, right.Object )) != 0) return eq; + return 0; + } + + public int cmp(XNode i_Left, XNode i_Right) + { + if (isBlank(i_Left)) { + return isBlank(i_Right) ? 0 : 1; + } else { + if (isBlank(i_Right)) { + return -1; + } else { + return toS(i_Left).compareTo(toS(i_Right)); + } + } + } + } + + static boolean eq(Statement i_Left, Statement i_Right) + { + XURI lG = i_Left.Graph; + XURI rG = i_Right.Graph; + if (!eq(lG, rG)) { + log.println("Graphs differ: " + toS(lG) + " != " + toS(rG)); + return false; + } + if (!eq(i_Left.Subject, i_Right.Subject)) { + log.println("Subjects differ: " + + i_Left.Subject.getStringValue() + " != " + + i_Right.Subject.getStringValue()); + return false; + } + if (!eq(i_Left.Predicate, i_Right.Predicate)) { + log.println("Predicates differ: " + + i_Left.Predicate.getStringValue() + " != " + + i_Right.Predicate.getStringValue()); + return false; + } + if (!eq(i_Left.Object, i_Right.Object)) { + log.println("Objects differ: " + + i_Left.Object.getStringValue() + " != " + + i_Right.Object.getStringValue()); + return false; + } + return true; + } + + static boolean eq(Statement[] i_Result, Statement[] i_Expected) + { + if (i_Result.length != i_Expected.length) { + log.println("eq: different lengths: " + i_Result.length + " " + + i_Expected.length); + return false; + } + Statement[] expected = (Statement[]) + java.util.Arrays.asList(i_Expected).toArray(); + java.util.Arrays.sort(i_Result, new StmtComp()); + java.util.Arrays.sort(expected, new StmtComp()); + for (int i = 0; i < expected.length; ++i) { + if (!eq(i_Result[i], expected[i])) return false; + } + return true; + } + + static boolean eq(XEnumeration i_Enum, Statement[] i_Expected) + throws Exception + { + Statement[] current = toSeq(i_Enum); + return eq(current, i_Expected); + } + + static boolean eq(XNode i_Left, XNode i_Right) + { + if (i_Left == null) { + return (i_Right == null); + } else { + return (i_Right != null) && + (i_Left.getStringValue().equals(i_Right.getStringValue()) + // FIXME: hack: blank nodes considered equal + || (isBlank(i_Left) && isBlank(i_Right))); + } + } + + static boolean eq(XQuerySelectResult i_Result, + String[] i_Vars, XNode[][] i_Bindings) throws Exception + { + String[] vars = (String[]) i_Result.getBindingNames(); + XEnumeration iter = (XEnumeration) i_Result; + XNode[][] bindings = toSeqs(iter); + if (vars.length != i_Vars.length) { + log.println("var lengths differ"); + return false; + } + if (bindings.length != i_Bindings.length) { + log.println("binding lengths differ: " + i_Bindings.length + + " vs " + bindings.length ); + return false; + } + java.util.Arrays.sort(bindings, new BindingComp()); + java.util.Arrays.sort(i_Bindings, new BindingComp()); + for (int i = 0; i < i_Bindings.length; ++i) { + if (i_Bindings[i].length != i_Vars.length) { + log.println("TEST ERROR!"); + throw new Exception(); + } + if (bindings[i].length != i_Vars.length) { + log.println("binding length and var length differ"); + return false; + } + for (int j = 0; j < i_Vars.length; ++j) { + if (!eq(bindings[i][j], i_Bindings[i][j])) { + log.println("bindings differ: " + + toS(bindings[i][j]) + " != " + toS(i_Bindings[i][j])); + return false; + } + } + } + for (int i = 0; i < i_Vars.length; ++i) { + if (!vars[i].equals(i_Vars[i])) { + log.println("variable names differ: " + + vars[i] + " != " + i_Vars[i]); + return false; + } + } + return true; + } + + static boolean eq(StringPair i_Left, StringPair i_Right) + { + return ((i_Left.First).equals(i_Right.First)) && + ((i_Left.Second).equals(i_Right.Second)); + } + + static String mkNamespace(String i_prefix, String i_namespace) + { + return "PREFIX " + i_prefix + ": <" + i_namespace + ">\n"; + } + + static String mkNss() + { + String namespaces = mkNamespace("rdf", + "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + namespaces += mkNamespace("pkg", + "http://docs.oasis-open.org/opendocument/meta/package/common#"); + namespaces += mkNamespace("odf", + "http://docs.oasis-open.org/opendocument/meta/package/odf#"); + return namespaces; + } + + Statement[] getManifestStmts(XURI xBaseURI) throws Exception + { + XURI xManifest = URI.createNS(xContext, xBaseURI.getStringValue(), + manifestPath); + XURI xContent = URI.createNS(xContext, xBaseURI.getStringValue(), + contentPath); + XURI xStyles = URI.createNS(xContext, xBaseURI.getStringValue(), + stylesPath); + Statement xM_BaseTypeDoc = + new Statement(xBaseURI, rdf_type, pkg_Document, xManifest); + Statement xM_BaseHaspartContent = + new Statement(xBaseURI, pkg_hasPart, xContent, xManifest); + Statement xM_BaseHaspartStyles = + new Statement(xBaseURI, pkg_hasPart, xStyles, xManifest); + Statement xM_ContentTypeContent = + new Statement(xContent, rdf_type, odf_ContentFile, xManifest); + Statement xM_StylesTypeStyles = + new Statement(xStyles, rdf_type, odf_StylesFile, xManifest); + return new Statement[] { + xM_BaseTypeDoc, xM_BaseHaspartContent, xM_BaseHaspartStyles, + xM_ContentTypeContent, xM_StylesTypeStyles + }; + } + + Statement[] getMetadataFileStmts(XURI xBaseURI, String Path) + throws Exception + { + XURI xManifest = URI.createNS(xContext, xBaseURI.getStringValue(), + manifestPath); + XURI xGraph = URI.createNS(xContext, xBaseURI.getStringValue(), Path); + Statement xM_BaseHaspartGraph = + new Statement(xBaseURI, pkg_hasPart, xGraph, xManifest); + Statement xM_GraphTypeMetadata = + new Statement(xGraph, rdf_type, pkg_MetadataFile, xManifest); + return new Statement[] { xM_BaseHaspartGraph, xM_GraphTypeMetadata }; + } + + class TestRange implements XTextRange, XMetadatable, XServiceInfo + { + String m_Stream; + String m_XmlId; + String m_Text; + TestRange(String i_Str) { m_Text = i_Str; } + + public String getStringValue() { return ""; } + public String getNamespace() { return ""; } + public String getLocalName() { return ""; } + + public StringPair getMetadataReference() + { return new StringPair(m_Stream, m_XmlId); } + public void setMetadataReference(StringPair i_Ref) + throws IllegalArgumentException + { m_Stream = (String)i_Ref.First; m_XmlId = (String)i_Ref.Second; } + public void ensureMetadataReference() + { m_Stream = "content.xml"; m_XmlId = "42"; } + + public String getImplementationName() { return null; } + public String[] getSupportedServiceNames() { return null; } + public boolean supportsService(String i_Svc) + { return i_Svc.equals("com.sun.star.text.Paragraph"); } + + public XText getText() { return null; } + public XTextRange getStart() { return null; } + public XTextRange getEnd() { return null; } + public String getString() { return m_Text; } + public void setString(String i_Str) { m_Text = i_Str; } + } +} + diff --git a/sfx2/qa/complex/makefile.mk b/sfx2/qa/complex/makefile.mk index 102c641f2732..5c0006df9e04 100644 --- a/sfx2/qa/complex/makefile.mk +++ b/sfx2/qa/complex/makefile.mk @@ -42,7 +42,9 @@ PACKAGE = complex$/framework JARFILES = ridl.jar unoil.jar jurt.jar juh.jar java_uno.jar OOoRunner.jar JAVAFILES = CheckGlobalEventBroadcaster_writer1.java \ - DocumentMetaData.java + DocumentMetaData.java \ + DocumentMetadataAccessTest.java + JAVACLASSFILES = $(foreach,i,$(JAVAFILES) $(CLASSDIR)$/$(PACKAGE)$/$(i:b).class) SUBDIRS = DocHelper diff --git a/sfx2/qa/complex/testdocuments/TESTRDFA.odt b/sfx2/qa/complex/testdocuments/TESTRDFA.odt Binary files differnew file mode 100644 index 000000000000..d59739142df6 --- /dev/null +++ b/sfx2/qa/complex/testdocuments/TESTRDFA.odt diff --git a/sfx2/qa/complex/tests.sce b/sfx2/qa/complex/tests.sce index e95f6db8848d..c38852927ede 100644 --- a/sfx2/qa/complex/tests.sce +++ b/sfx2/qa/complex/tests.sce @@ -1,2 +1,3 @@ -o complex.framework.DocumentMetaData +-o complex.framework.DocumentMetadataAccessTest #-o complex.framework.CheckGlobalEventBroadcaster_writer1 diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi index b8597d853ddd..32db454b17e5 100644 --- a/sfx2/sdi/sfx.sdi +++ b/sfx2/sdi/sfx.sdi @@ -8777,3 +8777,29 @@ SfxBoolItem DockingWindow9 SID_DOCKWIN_9 ToolBoxConfig = FALSE, GroupId = GID_APPLICATION; ] + +//-------------------------------------------------------------------------- +SfxInt16Item PasteUnformatted SID_PASTE_UNFORMATTED +() +[ + /* flags: */ + AutoUpdate = FALSE, + Cachable = Volatile, + FastCall = TRUE, + HasCoreId = FALSE, + HasDialog = FALSE, + ReadOnlyDoc = FALSE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + Asynchron; + + /* config: */ + AccelConfig = TRUE, + MenuConfig = TRUE, + StatusBarConfig = FALSE, + ToolBoxConfig = FALSE, + GroupId = GID_EDIT; +] + diff --git a/sfx2/sdi/sfxslots.sdi b/sfx2/sdi/sfxslots.sdi index c7667f36c02e..27336865be73 100644 --- a/sfx2/sdi/sfxslots.sdi +++ b/sfx2/sdi/sfxslots.sdi @@ -88,14 +88,6 @@ TypeLibFile( "sfxslots.tlb" ) INT32 AutoReloadTime MID_DOCINFO_AUTOLOADSECS; String AutoReloadURL MID_DOCINFO_AUTOLOADURL; String AutoReloadFrame MID_DOCINFO_DEFAULTTARGET; - String Field1Title MID_DOCINFO_FIELD1TITLE; - String Field2Title MID_DOCINFO_FIELD2TITLE; - String Field3Title MID_DOCINFO_FIELD3TITLE; - String Field4Title MID_DOCINFO_FIELD4TITLE; - String Field1 MID_DOCINFO_FIELD1; - String Field2 MID_DOCINFO_FIELD2; - String Field3 MID_DOCINFO_FIELD3; - String Field4 MID_DOCINFO_FIELD4; }; item DocInfo SfxDocumentInfoItem; diff --git a/sfx2/source/appl/app.cxx b/sfx2/source/appl/app.cxx index d30ba1ab753d..ae16b2a306ed 100644 --- a/sfx2/source/appl/app.cxx +++ b/sfx2/source/appl/app.cxx @@ -460,6 +460,14 @@ void SfxApplication::SetLastDir_Impl //-------------------------------------------------------------------- +void SfxApplication::ResetLastDir() +{ + String aEmpty; + pAppData_Impl->aLastDir = aEmpty; +} + +//-------------------------------------------------------------------- + SfxDispatcher* SfxApplication::GetDispatcher_Impl() { return pAppData_Impl->pViewFrame? pAppData_Impl->pViewFrame->GetDispatcher(): pAppData_Impl->pAppDispat; diff --git a/sfx2/source/appl/childwin.cxx b/sfx2/source/appl/childwin.cxx index 89314944c18d..60beac537e53 100644 --- a/sfx2/source/appl/childwin.cxx +++ b/sfx2/source/appl/childwin.cxx @@ -807,6 +807,9 @@ sal_Bool SfxChildWindow::QueryClose() bAllow = xCtrl->suspend( sal_True ); } + if ( bAllow ) + bAllow = !GetWindow()->IsInModalMode(); + return bAllow; } diff --git a/sfx2/source/appl/sfxhelp.cxx b/sfx2/source/appl/sfxhelp.cxx index f419bc3e3d55..8a6622636c14 100644 --- a/sfx2/source/appl/sfxhelp.cxx +++ b/sfx2/source/appl/sfxhelp.cxx @@ -193,7 +193,10 @@ sal_Bool GetHelpAnchor_Impl( const String& _rURL, String& _rAnchor ) sal_Bool bRet = sal_False; ::rtl::OUString sAnchor; - ULONG nSolarCount = Application::ReleaseSolarMutex(); + // --> OD 2009-07-01 #159496# + // do not release solar mutex due to crash regarding accessibility +// ULONG nSolarCount = Application::ReleaseSolarMutex(); + // <-- try { ::ucbhelper::Content aCnt( INetURLObject( _rURL ).GetMainURL( INetURLObject::NO_DECODE ), @@ -215,7 +218,9 @@ sal_Bool GetHelpAnchor_Impl( const String& _rURL, String& _rAnchor ) catch( ::com::sun::star::uno::Exception& ) { } - Application::AcquireSolarMutex( nSolarCount ); + // --> OD 2009-07-01 #159496# +// Application::AcquireSolarMutex( nSolarCount ); + // <-- return bRet; } diff --git a/sfx2/source/appl/shutdownicon.cxx b/sfx2/source/appl/shutdownicon.cxx index 3dddea833123..995b8250e072 100644 --- a/sfx2/source/appl/shutdownicon.cxx +++ b/sfx2/source/appl/shutdownicon.cxx @@ -495,8 +495,12 @@ IMPL_STATIC_LINK( ShutdownIcon, DialogClosedHdl_Impl, FileDialogHelper*, EMPTYAR } #ifdef WNT - LeaveModalMode(); + // #103346 Destroy dialog to prevent problems with custom controls + delete pThis->m_pFileDlg; + pThis->m_pFileDlg = NULL; #endif + + LeaveModalMode(); return 0; } diff --git a/sfx2/source/bastyp/progress.cxx b/sfx2/source/bastyp/progress.cxx index 22a3be63dc19..62bc5533e1a9 100644 --- a/sfx2/source/bastyp/progress.cxx +++ b/sfx2/source/bastyp/progress.cxx @@ -117,7 +117,7 @@ struct SfxProgress_Impl : public SfxCancellable #define aTypeLibInfo aProgressTypeLibImpl //======================================================================== -#if (_MSC_VER < 1300) +#if defined(_MSC_VER) && (_MSC_VER < 1300) inline ULONG Get10ThSec() { #if defined (MSC) && defined (WIN) diff --git a/sfx2/source/control/unoctitm.cxx b/sfx2/source/control/unoctitm.cxx index 64aa1a7d9d26..190cc47dc2f6 100644 --- a/sfx2/source/control/unoctitm.cxx +++ b/sfx2/source/control/unoctitm.cxx @@ -765,6 +765,8 @@ void SAL_CALL SfxDispatchController_Impl::dispatch( const ::com::sun::star::util sal_Bool bFailure = sal_False; const SfxPoolItem* pItem = NULL; SfxShell* pShell( 0 ); + // #i102619# Retrieve metric from shell before execution - the shell could be destroyed after execution + SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM ); if ( pDispatcher->GetBindings() ) { if ( !pDispatcher->IsLocked( GetId() ) ) @@ -783,6 +785,7 @@ void SAL_CALL SfxDispatchController_Impl::dispatch( const ::com::sun::star::util lNewArgs[nIndex].Value = makeAny( SfxDispatchController_Impl::getSlaveCommand( aDispatchURL )); } + eMapUnit = GetCoreMetric( pShell->GetPool(), GetId() ); SfxAllItemSet aSet( pShell->GetPool() ); TransformParameters( GetId(), lNewArgs, aSet, pSlot ); if ( aSet.Count() ) @@ -811,6 +814,7 @@ void SAL_CALL SfxDispatchController_Impl::dispatch( const ::com::sun::star::util } else { + eMapUnit = GetCoreMetric( SFX_APP()->GetPool(), GetId() ); // AppDispatcher SfxAllItemSet aSet( SFX_APP()->GetPool() ); TransformParameters( GetId(), lNewArgs, aSet ); @@ -850,13 +854,6 @@ void SAL_CALL SfxDispatchController_Impl::dispatch( const ::com::sun::star::util aEvent.Source = (::com::sun::star::frame::XDispatch*) pDispatch; if ( bSuccess && pItem && !pItem->ISA(SfxVoidItem) ) { - // Retrieve metric from pool to have correct sub ID when calling QueryValue - SfxMapUnit eMapUnit( SFX_MAPUNIT_100TH_MM ); - if ( pShell ) - eMapUnit = GetCoreMetric( pShell->GetPool(), GetId() ); - else - eMapUnit = GetCoreMetric( SFX_APP()->GetPool(), GetId() ); - USHORT nSubId( 0 ); if ( eMapUnit == SFX_MAPUNIT_TWIP ) nSubId |= CONVERT_TWIPS; diff --git a/sfx2/source/dialog/dinfdlg.cxx b/sfx2/source/dialog/dinfdlg.cxx index cb442caa6f1f..6de52384a90c 100644 --- a/sfx2/source/dialog/dinfdlg.cxx +++ b/sfx2/source/dialog/dinfdlg.cxx @@ -223,9 +223,9 @@ SfxDocumentInfoItem::SfxDocumentInfoItem() , m_Keywords() , m_Subject() , m_Title() - , bHasTemplate( sal_True ) - , bDeleteUserData( sal_False ) - , bIsUseUserData( sal_True ) + , m_bHasTemplate( sal_True ) + , m_bDeleteUserData( sal_False ) + , m_bUseUserData( sal_True ) { } @@ -253,9 +253,9 @@ SfxDocumentInfoItem::SfxDocumentInfoItem( const String& rFile, i_xDocProps->getKeywords()) ) , m_Subject( i_xDocProps->getSubject() ) , m_Title( i_xDocProps->getTitle() ) - , bHasTemplate( TRUE ) - , bDeleteUserData( sal_False ) - , bIsUseUserData( bIs ) + , m_bHasTemplate( sal_True ) + , m_bDeleteUserData( sal_False ) + , m_bUseUserData( bIs ) { try { @@ -302,15 +302,10 @@ SfxDocumentInfoItem::SfxDocumentInfoItem( const SfxDocumentInfoItem& rItem ) , m_Keywords( rItem.getKeywords() ) , m_Subject( rItem.getSubject() ) , m_Title( rItem.getTitle() ) - , bHasTemplate( rItem.bHasTemplate ) - , bDeleteUserData( rItem.bDeleteUserData ) - , bIsUseUserData( rItem.bIsUseUserData ) + , m_bHasTemplate( rItem.m_bHasTemplate ) + , m_bDeleteUserData( rItem.m_bDeleteUserData ) + , m_bUseUserData( rItem.m_bUseUserData ) { - for (size_t i = 0; i < 4; ++i) { - m_UserDefinedFieldTitles[i] = rItem.getUserDefinedFieldTitle(i); - m_UserDefinedFieldValues[i] = rItem.getUserDefinedFieldValue(i); - } - for ( sal_uInt32 i = 0; i < rItem.m_aCustomProperties.size(); i++ ) { CustomProperty* pProp = new CustomProperty( rItem.m_aCustomProperties[i]->m_sName, @@ -384,8 +379,9 @@ void SfxDocumentInfoItem::resetUserData(const ::rtl::OUString & i_rAuthor) //------------------------------------------------------------------------ -void SfxDocumentInfoItem::updateDocumentInfo( - const uno::Reference<document::XDocumentProperties>& i_xDocProps) const +void SfxDocumentInfoItem::UpdateDocumentInfo( + const uno::Reference<document::XDocumentProperties>& i_xDocProps, + bool i_bDoNotUpdateUserDefined) const { if (isAutoloadEnabled()) { i_xDocProps->setAutoloadSecs(getAutoloadDelay()); @@ -410,6 +406,15 @@ void SfxDocumentInfoItem::updateDocumentInfo( i_xDocProps->setSubject(getSubject()); i_xDocProps->setTitle(getTitle()); + // this is necessary in case of replaying a recorded macro: + // in this case, the macro may contain the 4 old user-defined DocumentInfo + // fields, but not any of the DocumentInfo properties; + // as a consequence, most of the UserDefined properties of the + // DocumentProperties would be summarily deleted here, which does not + // seem like a good idea. + if (i_bDoNotUpdateUserDefined) + return; + try { Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties(); @@ -442,24 +447,24 @@ void SfxDocumentInfoItem::updateDocumentInfo( //------------------------------------------------------------------------ -BOOL SfxDocumentInfoItem::IsDeleteUserData() const +sal_Bool SfxDocumentInfoItem::IsDeleteUserData() const { - return bDeleteUserData; + return m_bDeleteUserData; } -void SfxDocumentInfoItem::SetDeleteUserData( BOOL bSet ) +void SfxDocumentInfoItem::SetDeleteUserData( sal_Bool bSet ) { - bDeleteUserData = bSet; + m_bDeleteUserData = bSet; } -BOOL SfxDocumentInfoItem::IsUseUserData() const +sal_Bool SfxDocumentInfoItem::IsUseUserData() const { - return bIsUseUserData; + return m_bUseUserData; } -void SfxDocumentInfoItem::SetUseUserData( BOOL bSet ) +void SfxDocumentInfoItem::SetUseUserData( sal_Bool bSet ) { - bIsUseUserData = bSet; + m_bUseUserData = bSet; } std::vector< CustomProperty* > SfxDocumentInfoItem::GetCustomProperties() const @@ -488,38 +493,11 @@ void SfxDocumentInfoItem::AddCustomProperty( const ::rtl::OUString& sName, const m_aCustomProperties.push_back( pProp ); } -::rtl::OUString SfxDocumentInfoItem::getUserDefinedFieldTitle(size_t i_ix) const -{ - DBG_ASSERT(i_ix < 4, "SfxDocumentInfoItem: invalid index"); - return m_UserDefinedFieldTitles[i_ix]; -} - -::rtl::OUString SfxDocumentInfoItem::getUserDefinedFieldValue(size_t i_ix) const -{ - DBG_ASSERT(i_ix < 4, "SfxDocumentInfoItem: invalid index"); - return m_UserDefinedFieldValues[i_ix]; -} - -void SfxDocumentInfoItem::setUserDefinedFieldTitle(size_t i_ix, - ::rtl::OUString i_val) -{ - DBG_ASSERT(i_ix < 4, "SfxDocumentInfoItem: invalid index"); - m_UserDefinedFieldTitles[i_ix] = i_val; -} - -void SfxDocumentInfoItem::setUserDefinedFieldValue(size_t i_ix, - ::rtl::OUString i_val) -{ - DBG_ASSERT(i_ix < 4, "SfxDocumentInfoItem: invalid index"); - m_UserDefinedFieldValues[i_ix] = i_val; -} - sal_Bool SfxDocumentInfoItem::QueryValue( Any& rVal, BYTE nMemberId ) const { String aValue; sal_Int32 nValue = 0; sal_Bool bValue = sal_False; - BOOL bField = FALSE; BOOL bIsInt = FALSE; BOOL bIsString = FALSE; nMemberId &= ~CONVERT_TWIPS; @@ -562,43 +540,6 @@ sal_Bool SfxDocumentInfoItem::QueryValue( Any& rVal, BYTE nMemberId ) const bIsString = TRUE; aValue = getTitle(); break; - case MID_DOCINFO_FIELD1: - case MID_DOCINFO_FIELD2: - case MID_DOCINFO_FIELD3: - case MID_DOCINFO_FIELD4: - bField = TRUE; - // no break here - case MID_DOCINFO_FIELD1TITLE: - case MID_DOCINFO_FIELD2TITLE: - case MID_DOCINFO_FIELD3TITLE: - case MID_DOCINFO_FIELD4TITLE: - { - bIsString = TRUE; - USHORT nSub = MID_DOCINFO_FIELD1TITLE; - if ( bField ) - { - nSub = MID_DOCINFO_FIELD1; - } - if ( bField ) - { - DBG_ASSERT( nMemberId == MID_DOCINFO_FIELD1 || - nMemberId == MID_DOCINFO_FIELD2 || - nMemberId == MID_DOCINFO_FIELD3 || - nMemberId == MID_DOCINFO_FIELD4, - "SfxDocumentInfoItem:Anpassungsfehler" ); - aValue = getUserDefinedFieldValue( nMemberId - nSub ); - } - else - { - DBG_ASSERT( nMemberId == MID_DOCINFO_FIELD1TITLE || - nMemberId == MID_DOCINFO_FIELD2TITLE || - nMemberId == MID_DOCINFO_FIELD3TITLE || - nMemberId == MID_DOCINFO_FIELD4TITLE, - "SfxDocumentInfoItem:Anpassungsfehler" ); - aValue = getUserDefinedFieldTitle( nMemberId - nSub ); - } - break; - } default: DBG_ERROR("Wrong MemberId!"); return sal_False; @@ -673,28 +614,6 @@ sal_Bool SfxDocumentInfoItem::PutValue( const Any& rVal, BYTE nMemberId ) if ( bRet ) setTitle(aValue); break; - case MID_DOCINFO_FIELD1TITLE: - case MID_DOCINFO_FIELD2TITLE: - case MID_DOCINFO_FIELD3TITLE: - case MID_DOCINFO_FIELD4TITLE: - { - bRet = (rVal >>= aValue); - if ( bRet ) - setUserDefinedFieldTitle( - nMemberId - MID_DOCINFO_FIELD1TITLE, String(aValue)); - break; - } - case MID_DOCINFO_FIELD1: - case MID_DOCINFO_FIELD2: - case MID_DOCINFO_FIELD3: - case MID_DOCINFO_FIELD4: - { - bRet = (rVal >>= aValue); - if ( bRet ) - setUserDefinedFieldValue( - nMemberId - MID_DOCINFO_FIELD1, String(aValue)); - break; - } default: DBG_ERROR("Wrong MemberId!"); return sal_False; @@ -1178,7 +1097,7 @@ void SfxDocumentPage::Reset( const SfxItemSet& rSet ) aFileValFt.SetText( aURL.GetPartBeforeLastName() ); // handle access data - BOOL bIsUseUserData = pInfoItem->IsUseUserData(); + sal_Bool m_bUseUserData = pInfoItem->IsUseUserData(); LocaleDataWrapper aLocaleWrapper( ::comphelper::getProcessServiceFactory(), Application::GetSettings().GetLocale() ); aCreateValFt.SetText( ConvertDateTime_Impl( pInfoItem->getAuthor(), pInfoItem->getCreationDate(), aLocaleWrapper ) ); @@ -1193,7 +1112,7 @@ void SfxDocumentPage::Reset( const SfxItemSet& rSet ) aPrintValFt.SetText( ConvertDateTime_Impl( pInfoItem->getPrintedBy(), aTime, aLocaleWrapper ) ); const long nTime = pInfoItem->getEditingDuration(); - if( bIsUseUserData ) + if ( m_bUseUserData ) { const Time aT( nTime/3600, (nTime%3600)/60, nTime%60 ); aTimeLogValFt.SetText( aLocaleWrapper.getDuration( aT ) ); @@ -1201,7 +1120,7 @@ void SfxDocumentPage::Reset( const SfxItemSet& rSet ) pInfoItem->getEditingCycles() ) ); } - TriState eState = (TriState)bIsUseUserData; + TriState eState = (TriState)m_bUseUserData; if ( STATE_DONTKNOW == eState ) aUseUserDataCB.EnableTriState( TRUE ); @@ -1558,192 +1477,6 @@ int SfxInternetPage::DeactivatePage( SfxItemSet* /*pSet*/ ) //------------------------------------------------------------------------ -SfxDocumentUserPage::SfxDocumentUserPage( Window* pParent, - const SfxItemSet& rItemSet ) : - - SfxTabPage( pParent, SfxResId( TP_DOCINFOUSER ), rItemSet ), - - bLabelModified ( FALSE ), - aInfo1Ft ( this, SfxResId( FT_INFO1 ) ), - aInfo1Ed ( this, SfxResId( ED_INFO1 ) ), - aInfo2Ft ( this, SfxResId( FT_INFO2 ) ), - aInfo2Ed ( this, SfxResId( ED_INFO2 ) ), - aInfo3Ft ( this, SfxResId( FT_INFO3 ) ), - aInfo3Ed ( this, SfxResId( ED_INFO3 ) ), - aInfo4Ft ( this, SfxResId( FT_INFO4 ) ), - aInfo4Ed ( this, SfxResId( ED_INFO4 ) ), - aEditLabelBtn ( this, SfxResId( BTN_EDITLABEL ) ), - - pInfoItem ( NULL ) - -{ - FreeResource(); - //increase button width in case of long labels - Size aButtonSize = aEditLabelBtn.GetOutputSizePixel(); - sal_Int32 nTextWidth = aEditLabelBtn.GetTextWidth(aEditLabelBtn.GetText()); - //add some additional space - sal_Int32 nDiff = nTextWidth + 4 - aButtonSize.Width(); - if( nDiff > 0) - { - Point aPos(aEditLabelBtn.GetPosPixel()); - aPos.X() -= nDiff; - aButtonSize.Width() += nDiff; - aEditLabelBtn.SetPosSizePixel(aPos, aButtonSize); - } - - aEditLabelBtn.SetClickHdl( LINK( this, SfxDocumentUserPage, EditLabelHdl ) ); -} - -//------------------------------------------------------------------------ - -IMPL_LINK( SfxDocumentUserPage, EditLabelHdl, PushButton *, pPushButton ) -{ - (void)pPushButton; //unused - SfxDocInfoEditDlg* pDlg = new SfxDocInfoEditDlg( this ); - pDlg->SetText1( GetLabelText_Impl( &aInfo1Ft ) ); - pDlg->SetText2( GetLabelText_Impl( &aInfo2Ft ) ); - pDlg->SetText3( GetLabelText_Impl( &aInfo3Ft ) ); - pDlg->SetText4( GetLabelText_Impl( &aInfo4Ft ) ); - - if ( RET_OK == pDlg->Execute() ) - { - SetLabelText_Impl( &aInfo1Ft, pDlg->GetText1() ); - SetLabelText_Impl( &aInfo2Ft, pDlg->GetText2() ); - SetLabelText_Impl( &aInfo3Ft, pDlg->GetText3() ); - SetLabelText_Impl( &aInfo4Ft, pDlg->GetText4() ); - bLabelModified = TRUE; - } - delete pDlg; - return 0; -} - -//------------------------------------------------------------------------ - -String SfxDocumentUserPage::GetLabelText_Impl( FixedText* pLabel ) -{ - DBG_ASSERT( pLabel, "SfxDocumentUserPage::SetLabelText_Impl(): invalid label" ); - String aLabel = pLabel->GetText(); - aLabel.Erase( 0, aLabel.Search( ' ' ) + 1 ); - return aLabel; -} - -//------------------------------------------------------------------------ - -void SfxDocumentUserPage::SetLabelText_Impl( FixedText* pLabel, const String& rNewLabel ) -{ - String aLabel( '~' ); - sal_Int32 nNumber = 0; - if ( &aInfo1Ft == pLabel ) - nNumber = 1; - else if ( &aInfo2Ft == pLabel ) - nNumber = 2; - else if ( &aInfo3Ft == pLabel ) - nNumber = 3; - else if ( &aInfo4Ft == pLabel ) - nNumber = 4; - DBG_ASSERT( nNumber > 0, "SfxDocumentUserPage::SetLabelText_Impl(): wrong label" ); - aLabel += String::CreateFromInt32( nNumber ); - aLabel += String( DEFINE_CONST_UNICODE(": ") ); - aLabel += rNewLabel; - DBG_ASSERT( pLabel, "SfxDocumentUserPage::SetLabelText_Impl(): invalid label" ); - pLabel->SetText( aLabel ); -} - -//------------------------------------------------------------------------ - -SfxTabPage* SfxDocumentUserPage::Create( Window* pParent, const SfxItemSet& rItemSet ) -{ - return new SfxDocumentUserPage(pParent, rItemSet); -} - -//------------------------------------------------------------------------ - -BOOL SfxDocumentUserPage::FillItemSet( SfxItemSet& rSet ) -{ - const BOOL bMod = bLabelModified || - aInfo1Ed.IsModified() || aInfo2Ed.IsModified() || - aInfo3Ed.IsModified() || aInfo4Ed.IsModified(); - if ( !bMod ) - return FALSE; - - const SfxPoolItem* pItem = NULL; - SfxDocumentInfoItem* pInfo = NULL; - SfxTabDialog* pDlg = GetTabDialog(); - const SfxItemSet* pExSet = NULL; - - if ( pDlg ) - pExSet = pDlg->GetExampleSet(); - - if ( pExSet && SFX_ITEM_SET != pExSet->GetItemState( SID_DOCINFO, TRUE, &pItem ) ) - pInfo = pInfoItem; - else if ( pItem ) - pInfo = new SfxDocumentInfoItem( *(const SfxDocumentInfoItem*)pItem ); - - if ( !pInfo ) - { - DBG_ERRORFILE( "SfxDocumentUserPage::FillItemSet(): no item found" ); - return FALSE; - } - - if ( bLabelModified || aInfo1Ed.IsModified() ) - { - XubString aTitle = GetLabelText_Impl( &aInfo1Ft ); - pInfo->setUserDefinedFieldTitle( 0, aTitle ); - pInfo->setUserDefinedFieldValue( 0, aInfo1Ed.GetText() ); - } - if ( bLabelModified || aInfo2Ed.IsModified() ) - { - XubString aTitle = GetLabelText_Impl( &aInfo2Ft ); - pInfo->setUserDefinedFieldTitle( 1, aTitle ); - pInfo->setUserDefinedFieldValue( 1, aInfo2Ed.GetText() ); - } - if ( bLabelModified || aInfo3Ed.IsModified() ) - { - XubString aTitle = GetLabelText_Impl( &aInfo3Ft ); - pInfo->setUserDefinedFieldTitle( 2, aTitle ); - pInfo->setUserDefinedFieldValue( 2, aInfo3Ed.GetText() ); - } - if ( bLabelModified || aInfo4Ed.IsModified() ) - { - XubString aTitle = GetLabelText_Impl( &aInfo4Ft ); - pInfo->setUserDefinedFieldTitle( 3, aTitle ); - pInfo->setUserDefinedFieldValue( 3, aInfo4Ed.GetText() ); - } - rSet.Put( *pInfo ); - if ( pInfo != pInfoItem ) - delete pInfo; - return bMod; -} - -//------------------------------------------------------------------------ - -void SfxDocumentUserPage::Reset(const SfxItemSet &rSet) -{ - pInfoItem = &(SfxDocumentInfoItem&)rSet.Get( SID_DOCINFO ); - - SetLabelText_Impl( &aInfo1Ft, pInfoItem->getUserDefinedFieldTitle(0) ); - aInfo1Ed.SetText( pInfoItem->getUserDefinedFieldValue(0) ); - SetLabelText_Impl( &aInfo2Ft, pInfoItem->getUserDefinedFieldTitle(1) ); - aInfo2Ed.SetText( pInfoItem->getUserDefinedFieldValue(1) ); - SetLabelText_Impl( &aInfo3Ft, pInfoItem->getUserDefinedFieldTitle(2) ); - aInfo3Ed.SetText( pInfoItem->getUserDefinedFieldValue(2) ); - SetLabelText_Impl( &aInfo4Ft, pInfoItem->getUserDefinedFieldTitle(3) ); - aInfo4Ed.SetText( pInfoItem->getUserDefinedFieldValue(3) ); - bLabelModified = FALSE; - - SFX_ITEMSET_ARG( &rSet, pROItem, SfxBoolItem, SID_DOC_READONLY, FALSE ); - if ( pROItem && pROItem->GetValue() ) - { - aInfo1Ed.SetReadOnly( TRUE ); - aInfo2Ed.SetReadOnly( TRUE ); - aInfo3Ed.SetReadOnly( TRUE ); - aInfo4Ed.SetReadOnly( TRUE ); - aEditLabelBtn.Disable(); - } -} - -//------------------------------------------------------------------------ - SfxDocumentInfoDialog::SfxDocumentInfoDialog( Window* pParent, const SfxItemSet& rItemSet ) : diff --git a/sfx2/source/dialog/dockwin.cxx b/sfx2/source/dialog/dockwin.cxx index afcf2aeef353..f31ed1724907 100644 --- a/sfx2/source/dialog/dockwin.cxx +++ b/sfx2/source/dialog/dockwin.cxx @@ -236,6 +236,7 @@ SfxDockingWrapper::SfxDockingWrapper( Window* pParentWnd , } Window* pContentWindow = VCLUnoHelper::GetWindow(xWindow); + pContentWindow->SetStyle( pContentWindow->GetStyle() | WB_DIALOGCONTROL | WB_CHILDDLGCTRL ); pTitleDockWindow->SetWrappedWindow(pContentWindow); } diff --git a/sfx2/source/dialog/filedlghelper.cxx b/sfx2/source/dialog/filedlghelper.cxx index de74d88ab631..33359a45ec96 100644 --- a/sfx2/source/dialog/filedlghelper.cxx +++ b/sfx2/source/dialog/filedlghelper.cxx @@ -87,6 +87,7 @@ #endif #include <svtools/pickerhelper.hxx> #include <svtools/docpasswdrequest.hxx> +#include <svtools/docmspasswdrequest.hxx> #include <ucbhelper/content.hxx> #include <ucbhelper/commandenvironment.hxx> #include <comphelper/storagehelper.hxx> @@ -556,13 +557,34 @@ void FileDialogHelper_Impl::updateSelectionBox() } // ------------------------------------------------------------------------ +struct CheckMSPasswordCapability +{ + sal_Bool operator() ( const String rFilterName ) + { + return rFilterName.EqualsAscii("MS Word 97"); + } +}; + +// ------------------------------------------------------------------------ struct CheckPasswordCapability { sal_Bool operator() ( const SfxFilter* _pFilter ) { - return _pFilter && _pFilter->IsOwnFormat() - && _pFilter->UsesStorage() - && ( SOFFICE_FILEFORMAT_60 <= _pFilter->GetVersion() ); + if (!_pFilter) + return false; + +#if 0 // to be enabled in the future + if (_pFilter->GetFilterName().EqualsAscii("MS Excel 97")) + // For now, we eanble password protection for Excel 97 as a + // special case. If we start having more filters supporting + // export encryption with password, we should probably switch to + // using a filter flag instead. + return true; +#endif + + return ( _pFilter->IsOwnFormat() && _pFilter->UsesStorage() + && ( SOFFICE_FILEFORMAT_60 <= _pFilter->GetVersion() ) ) + || CheckMSPasswordCapability()( _pFilter->GetFilterName() ); } }; @@ -1347,6 +1369,7 @@ sal_Int16 FileDialogHelper_Impl::implDoExecute() //On MacOSX the native file picker has to run in the primordial thread because of drawing issues //On Linux the native gtk file picker, when backed by gnome-vfs2, needs to be run in the same //primordial thread as the ucb gnome-vfs2 provider was initialized in. +/* #ifdef WNT if ( mbSystemPicker ) { @@ -1360,9 +1383,18 @@ sal_Int16 FileDialogHelper_Impl::implDoExecute() } else #endif +*/ { try { +#ifdef WNT + if ( mbSystemPicker ) + { + OReleaseSolarMutex aSolarMutex; + nRet = mxFileDlg->execute(); + } + else +#endif nRet = mxFileDlg->execute(); } catch( const Exception& ) @@ -1633,20 +1665,36 @@ ErrCode FileDialogHelper_Impl::execute( SvStringsDtor*& rpURLList, sal_Bool bPassWord = sal_False; if ( ( aValue >>= bPassWord ) && bPassWord ) { - // ask for the password + // ask for a password uno::Reference < ::com::sun::star::task::XInteractionHandler > xInteractionHandler( ::comphelper::getProcessServiceFactory()->createInstance(::rtl::OUString::createFromAscii("com.sun.star.comp.uui.UUIInteractionHandler")), UNO_QUERY ); if( xInteractionHandler.is() ) { - RequestDocumentPassword* pPasswordRequest = new RequestDocumentPassword( - ::com::sun::star::task::PasswordRequestMode_PASSWORD_CREATE, *(rpURLList->GetObject(0)) ); - - uno::Reference< com::sun::star::task::XInteractionRequest > rRequest( pPasswordRequest ); - xInteractionHandler->handle( rRequest ); - if ( pPasswordRequest->isPassword() ) - rpSet->Put( SfxStringItem( SID_PASSWORD, pPasswordRequest->getPassword() ) ); + // TODO: find out a way to set the 1-15 char limits on MS Excel 97 filter. + if ( CheckMSPasswordCapability()( rFilter ) ) + { + RequestMSDocumentPassword* pMSPasswordRequest = new RequestMSDocumentPassword( + ::com::sun::star::task::PasswordRequestMode_PASSWORD_CREATE, *(rpURLList->GetObject(0)) ); + + uno::Reference< com::sun::star::task::XInteractionRequest > rRequest( pMSPasswordRequest ); + xInteractionHandler->handle( rRequest ); + if ( pMSPasswordRequest->isPassword() ) + rpSet->Put( SfxStringItem( SID_PASSWORD, pMSPasswordRequest->getPassword() ) ); + else + return ERRCODE_ABORT; + } else - return ERRCODE_ABORT; + { + RequestDocumentPassword* pPasswordRequest = new RequestDocumentPassword( + ::com::sun::star::task::PasswordRequestMode_PASSWORD_CREATE, *(rpURLList->GetObject(0)) ); + + uno::Reference< com::sun::star::task::XInteractionRequest > rRequest( pPasswordRequest ); + xInteractionHandler->handle( rRequest ); + if ( pPasswordRequest->isPassword() ) + rpSet->Put( SfxStringItem( SID_PASSWORD, pPasswordRequest->getPassword() ) ); + else + return ERRCODE_ABORT; + } } } } @@ -2570,6 +2618,46 @@ Sequence < OUString > FileDialogHelper::GetMPath() const } // ------------------------------------------------------------------------ +Sequence< ::rtl::OUString > FileDialogHelper::GetSelectedFiles() const +{ + // a) the new way (optional!) + uno::Sequence< ::rtl::OUString > aResultSeq; + uno::Reference< XFilePicker2 > xPickNew(mpImp->mxFileDlg, UNO_QUERY); + if (xPickNew.is()) + { + aResultSeq = xPickNew->getSelectedFiles(); + } + // b) the olde way ... non optional. + else + { + uno::Reference< XFilePicker > xPickOld(mpImp->mxFileDlg, UNO_QUERY_THROW); + Sequence< OUString > lFiles = xPickOld->getFiles(); + ::sal_Int32 nFiles = lFiles.getLength(); + if ( nFiles > 1 ) + { + aResultSeq = Sequence< ::rtl::OUString >( nFiles-1 ); + + INetURLObject aPath( lFiles[0] ); + aPath.setFinalSlash(); + + for (::sal_Int32 i = 1; i < nFiles; i++) + { + if (i == 1) + aPath.Append( lFiles[i] ); + else + aPath.setName( lFiles[i] ); + + aResultSeq[i-1] = ::rtl::OUString(aPath.GetMainURL( INetURLObject::NO_DECODE )); + } + } + else + aResultSeq = lFiles; + } + + return aResultSeq; +} + +// ------------------------------------------------------------------------ String FileDialogHelper::GetDisplayDirectory() const { return mpImp->getPath(); diff --git a/sfx2/source/dialog/passwd.cxx b/sfx2/source/dialog/passwd.cxx index b4d0e49d92c5..cbe47d39b704 100644 --- a/sfx2/source/dialog/passwd.cxx +++ b/sfx2/source/dialog/passwd.cxx @@ -112,6 +112,15 @@ void SfxPasswordDialog::SetMinLen( USHORT nLen ) // ----------------------------------------------------------------------- +void SfxPasswordDialog::SetMaxLen( USHORT nLen ) +{ + maPasswordED.SetMaxTextLen( nLen ); + maConfirmED.SetMaxTextLen( nLen ); + EditModifyHdl( NULL ); +} + +// ----------------------------------------------------------------------- + short SfxPasswordDialog::Execute() { if ( mnExtras < SHOWEXTRAS_ALL ) diff --git a/sfx2/source/dialog/templdlg.cxx b/sfx2/source/dialog/templdlg.cxx index c0ee288eb882..706739cd0571 100644 --- a/sfx2/source/dialog/templdlg.cxx +++ b/sfx2/source/dialog/templdlg.cxx @@ -79,7 +79,6 @@ #include "imgmgr.hxx" #include "helpid.hrc" #include "appdata.hxx" -#include "objshimp.hxx" #include <sfx2/viewfrm.hxx> #include <comphelper/configurationhelper.hxx> @@ -103,8 +102,8 @@ using namespace ::com::sun::star::uno; static USHORT nLastItemId = USHRT_MAX; -// filter box has maximum 7 entries visible -#define MAX_FILTER_ENTRIES 7 +// filter box has maximum 12 entries visible +#define MAX_FILTER_ENTRIES 12 //========================================================================= @@ -883,7 +882,7 @@ void SfxCommonTemplateDialog_Impl::ReadResource() nActFilter = pCurObjShell ? static_cast< USHORT >( LoadFactoryStyleFilter( pCurObjShell ) ) : 0xFFFF; if ( pCurObjShell && 0xFFFF == nActFilter ) - nActFilter = pCurObjShell->pImp->nStyleFilter; + nActFilter = pCurObjShell->GetAutoStyleFilterIndex(); // Einfuegen in die Toolbox // umgekehrte Reihenfolge, da immer vorne eingefuegt wird. @@ -1300,7 +1299,7 @@ void SfxCommonTemplateDialog_Impl::UpdateStyles_Impl(USHORT nFlags) // Flags if(pTreeBox) aFilterLb.SelectEntry(String(SfxResId(STR_STYLE_FILTER_HIERARCHICAL))); - // show maximum seven entries + // show maximum 12 entries aFilterLb.SetDropDownLineCount( MAX_FILTER_ENTRIES ); aFilterLb.SetUpdateMode(TRUE); } @@ -1504,7 +1503,7 @@ void SfxCommonTemplateDialog_Impl::Update_Impl() CheckItem( nActFamily, TRUE ); nActFilter = static_cast< USHORT >( LoadFactoryStyleFilter( pDocShell ) ); if ( 0xFFFF == nActFilter ) - nActFilter = pDocShell->pImp->nStyleFilter; + nActFilter = pDocShell->GetAutoStyleFilterIndex(); nAppFilter = pItem->GetValue(); if(!pTreeBox) @@ -1674,7 +1673,7 @@ void SfxCommonTemplateDialog_Impl::FilterSelect( SfxObjectShell *pDocShell = pViewFrame->GetObjectShell(); if (pDocShell) { - pDocShell->Get_Impl()->nStyleFilter = nActFilter; + pDocShell->SetAutoStyleFilterIndex(nActFilter); SaveFactoryStyleFilter( pDocShell, nActFilter ); } @@ -1885,8 +1884,8 @@ void SfxCommonTemplateDialog_Impl::ActionSelect(USHORT nEntry) pStyleSheetPool->SetSearchMask( eFam, SFXSTYLEBIT_USERDEF ); SfxNewStyleDlg *pDlg = - // FloatingWindow must not be parent of a modal dialog - new SfxNewStyleDlg(SFX_APP()->GetTopWindow(), *pStyleSheetPool); + // why? : FloatingWindow must not be parent of a modal dialog + new SfxNewStyleDlg(pWindow, *pStyleSheetPool); if(RET_OK == pDlg->Execute()) { pStyleSheetPool->SetSearchMask(eFam, nFilter); diff --git a/sfx2/source/doc/DocumentMetadataAccess.cxx b/sfx2/source/doc/DocumentMetadataAccess.cxx new file mode 100644 index 000000000000..112183a4efbe --- /dev/null +++ b/sfx2/source/doc/DocumentMetadataAccess.cxx @@ -0,0 +1,1414 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: DocumentMetadataAccess.cxx,v $ + * $Revision: 1.1.2.9 $ + * + * 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 <sfx2/DocumentMetadataAccess.hxx> + +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/task/ErrorCodeIOException.hpp> +#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/rdf/FileFormat.hpp> +#include <com/sun/star/rdf/URIs.hpp> +#include <com/sun/star/rdf/Statement.hpp> +#include <com/sun/star/rdf/Literal.hpp> +#include <com/sun/star/rdf/URI.hpp> +#include <com/sun/star/rdf/Repository.hpp> + +#include <rtl/uuid.h> +#include <rtl/ustrbuf.hxx> + +#include <comphelper/interaction.hxx> +#include <comphelper/makesequence.hxx> +#include <comphelper/mediadescriptor.hxx> +#include <comphelper/sequenceasvector.hxx> +#include <comphelper/storagehelper.hxx> + +#include <sfx2/docfile.hxx> +#include <sfx2/XmlIdRegistry.hxx> + +#include <libxml/tree.h> // for xmlValidateNCName + +#include <boost/bind.hpp> +#include <boost/shared_array.hpp> +#include <boost/tuple/tuple.hpp> + +#include <vector> +#include <set> +#include <map> +#include <functional> +#include <algorithm> + +#include <unotools/ucbhelper.hxx> +#include <com/sun/star/uri/XUriReference.hpp> +#include <com/sun/star/uri/XUriReferenceFactory.hpp> +#include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp> + + +/* + Note: in the context of this implementation, all rdf.QueryExceptions and + rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such. + + This implementation assumes that it is only used with ODF documents, not mere + ODF packages. In other words, we enforce that metadata files must not be + called reserved names. + */ + +using namespace ::com::sun::star; + +namespace sfx2 { + + +bool isValidNCName(::rtl::OUString const & i_rIdref) +{ + const ::rtl::OString id( + ::rtl::OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8) ); + return !(xmlValidateNCName( + reinterpret_cast<const unsigned char*>(id.getStr()), 0)); +} + +//////////////////////////////////////////////////////////////////////////// + +static const char s_content [] = "content.xml"; +static const char s_styles [] = "styles.xml"; +static const char s_meta [] = "meta.xml"; +static const char s_settings[] = "settings.xml"; +static const char s_manifest[] = "manifest.rdf"; +static const char s_rdfxml [] = "application/rdf+xml"; +static const char s_odfmime [] = "application/vnd.oasis.opendocument."; + +//////////////////////////////////////////////////////////////////////////// + +static bool isContentFile(::rtl::OUString const & i_rPath) +{ + return i_rPath.equalsAscii(s_content); +} + +static bool isStylesFile (::rtl::OUString const & i_rPath) +{ + return i_rPath.equalsAscii(s_styles); +} + +static bool isReservedFile(::rtl::OUString const & i_rPath) +{ + return isContentFile(i_rPath) + || isStylesFile(i_rPath) + || i_rPath.equalsAscii(s_meta) + || i_rPath.equalsAscii(s_settings); +} + +//////////////////////////////////////////////////////////////////////////// + +uno::Reference<rdf::XURI> createBaseURI( + uno::Reference<uno::XComponentContext> const & i_xContext, + uno::Reference<embed::XStorage> const & i_xStorage, + ::rtl::OUString const & i_rPkgURI, ::rtl::OUString const & i_rSubDocument) +{ + if (!i_xContext.is() || !i_xStorage.is() || !i_rPkgURI.getLength()) { + throw uno::RuntimeException(); + } + + const uno::Reference<lang::XMultiComponentFactory> xServiceFactory( + i_xContext->getServiceManager(), uno::UNO_SET_THROW); + const uno::Reference<uri::XUriReferenceFactory> xUriFactory( + xServiceFactory->createInstanceWithContext( + ::rtl::OUString::createFromAscii( + "com.sun.star.uri.UriReferenceFactory"), i_xContext), + uno::UNO_QUERY_THROW); + uno::Reference< uri::XUriReference > xBaseURI; + + const uno::Reference< uri::XUriReference > xPkgURI( + xUriFactory->parse(i_rPkgURI), uno::UNO_SET_THROW ); + xPkgURI->clearFragment(); + // need to know whether the storage is a FileSystemStorage + // XServiceInfo would be better, but it is not implemented +// if ( i_rPkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(i_rPkgURI) ) + if (true) { + xBaseURI.set( xPkgURI, uno::UNO_SET_THROW ); +#if 0 + } else { + const uno::Reference<uri::XVndSunStarPkgUrlReferenceFactory> + xPkgUriFactory( xServiceFactory->createInstanceWithContext( + ::rtl::OUString::createFromAscii( + "com.sun.star.uri.VndSunStarPkgUrlReferenceFactory"), + i_xContext), + uno::UNO_QUERY_THROW); + xBaseURI.set( xPkgUriFactory->createVndSunStarPkgUrlReference(xPkgURI), + uno::UNO_SET_THROW ); +#endif + } + ::rtl::OUStringBuffer buf; + if (!xBaseURI->getUriReference().endsWithAsciiL("/", 1)) + { + const sal_Int32 count( xBaseURI->getPathSegmentCount() ); + if (count > 0) + { + const ::rtl::OUString last( xBaseURI->getPathSegment(count - 1) ); + buf.append(last); + } + buf.append(static_cast<sal_Unicode>('/')); + } + if (i_rSubDocument.getLength()) + { + buf.append(i_rSubDocument); + buf.append(static_cast<sal_Unicode>('/')); + } + const ::rtl::OUString Path(buf.makeStringAndClear()); + if (Path.getLength()) + { + const uno::Reference< uri::XUriReference > xPathURI( + xUriFactory->parse(Path), uno::UNO_SET_THROW ); + xBaseURI.set( + xUriFactory->makeAbsolute(xBaseURI, xPathURI, + true, uri::RelativeUriExcessParentSegments_ERROR), + uno::UNO_SET_THROW); + } + + return rdf::URI::create(i_xContext, xBaseURI->getUriReference()); +} + +//////////////////////////////////////////////////////////////////////////// + +struct DocumentMetadataAccess_Impl +{ + // note: these are all initialized in constructor, and loadFromStorage + const uno::Reference<uno::XComponentContext> m_xContext; + const IXmlIdRegistrySupplier & m_rXmlIdRegistrySupplier; + uno::Reference<rdf::XURI> m_xBaseURI; + uno::Reference<rdf::XRepository> m_xRepository; + uno::Reference<rdf::XNamedGraph> m_xManifest; + DocumentMetadataAccess_Impl( + uno::Reference<uno::XComponentContext> const& i_xContext, + IXmlIdRegistrySupplier const & i_rRegistrySupplier) + : m_xContext(i_xContext) + , m_rXmlIdRegistrySupplier(i_rRegistrySupplier) + , m_xBaseURI() + , m_xRepository() + , m_xManifest() + { + OSL_ENSURE(m_xContext.is(), "context null"); + } +}; + +// this is... a hack. +template<sal_Int16 Constant> +/*static*/ uno::Reference<rdf::XURI> +getURI(uno::Reference< uno::XComponentContext > const & i_xContext) +{ + static uno::Reference< rdf::XURI > xURI( + rdf::URI::createKnown(i_xContext, Constant), uno::UNO_QUERY_THROW); + return xURI; +} + + +/** would storing the file to a XStorage succeed? */ +static bool isFileNameValid(const ::rtl::OUString & i_rFileName) +{ + if (i_rFileName.getLength() <= 0) return false; + if (i_rFileName[0] == '/') return false; // no absolute paths! + sal_Int32 idx(0); + do { + const ::rtl::OUString segment( + i_rFileName.getToken(0, static_cast<sal_Unicode> ('/'), idx) ); + if (!segment.getLength() || // no empty segments + segment.equalsAscii(".") || // no . segments + segment.equalsAscii("..") || // no .. segments + !::comphelper::OStorageHelper::IsValidZipEntryFileName( + segment, sal_False)) // no invalid characters + return false; + } while (idx >= 0); + return true; +} + +/** split a uri hierarchy into first segment and rest */ +static bool +splitPath(::rtl::OUString const & i_rPath, + ::rtl::OUString & o_rDir, ::rtl::OUString& o_rRest) +{ + const sal_Int32 idx(i_rPath.indexOf(static_cast<sal_Unicode>('/'))); + if (idx < 0 || idx >= i_rPath.getLength()) { + o_rDir = ::rtl::OUString(); + o_rRest = i_rPath; + return true; + } else if (idx == 0 || idx == i_rPath.getLength() - 1) { + // input must not start or end with '/' + return false; + } else { + o_rDir = (i_rPath.copy(0, idx)); + o_rRest = (i_rPath.copy(idx+1)); + return true; + } +} + +static bool +splitXmlId(::rtl::OUString const & i_XmlId, + ::rtl::OUString & o_StreamName, ::rtl::OUString& o_Idref ) +{ + const sal_Int32 idx(i_XmlId.indexOf(static_cast<sal_Unicode>('#'))); + if ((idx <= 0) || (idx >= i_XmlId.getLength() - 1)) { + return false; + } else { + o_StreamName = (i_XmlId.copy(0, idx)); + o_Idref = (i_XmlId.copy(idx+1)); + return isValidXmlId(o_StreamName, o_Idref); + } +} + +//////////////////////////////////////////////////////////////////////////// + +static uno::Reference<rdf::XURI> +getURIForStream(struct DocumentMetadataAccess_Impl& i_rImpl, + ::rtl::OUString const& i_rPath) +{ + const uno::Reference<rdf::XURI> xURI( + rdf::URI::createNS( i_rImpl.m_xContext, + i_rImpl.m_xBaseURI->getStringValue(), i_rPath), + uno::UNO_SET_THROW); + return xURI; +} + +/** add statements declaring i_xResource to be a file of type i_xType with + path i_rPath to manifest, with optional additional types i_pTypes */ +static void +addFile(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference<rdf::XURI> const& i_xType, + ::rtl::OUString const & i_rPath, + const uno::Sequence < uno::Reference< rdf::XURI > > * i_pTypes = 0) +{ + try { + const uno::Reference<rdf::XURI> xURI( getURIForStream( + i_rImpl, i_rPath) ); + + i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), + xURI.get()); + i_rImpl.m_xManifest->addStatement(xURI.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + i_xType.get()); + if (i_pTypes) { + for (sal_Int32 i = 0; i < i_pTypes->getLength(); ++i) { + i_rImpl.m_xManifest->addStatement(xURI.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + (*i_pTypes)[i].get()); + } + } + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "addFile: exception"), /*this*/0, uno::makeAny(e)); + } +} + +/** add content.xml or styles.xml to manifest */ +static bool +addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl & i_rImpl, + const ::rtl::OUString & i_rPath) +{ + uno::Reference<rdf::XURI> xType; + if (isContentFile(i_rPath)) { + xType.set(getURI<rdf::URIs::ODF_CONTENTFILE>(i_rImpl.m_xContext)); + } else if (isStylesFile(i_rPath)) { + xType.set(getURI<rdf::URIs::ODF_STYLESFILE>(i_rImpl.m_xContext)); + } else { + return false; + } + addFile(i_rImpl, xType.get(), i_rPath); + return true; +} + +/** add metadata file to manifest */ +static void +addMetadataFileImpl(struct DocumentMetadataAccess_Impl & i_rImpl, + const ::rtl::OUString & i_rPath, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +{ + addFile(i_rImpl, + getURI<rdf::URIs::PKG_METADATAFILE>(i_rImpl.m_xContext), + i_rPath, &i_rTypes); +} + +/** remove a file from the manifest */ +static void +removeFile(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference<rdf::XURI> const& i_xPart) +{ + if (!i_xPart.is()) throw uno::RuntimeException(); + try { + i_rImpl.m_xManifest->removeStatements(i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), + i_xPart.get()); + i_rImpl.m_xManifest->removeStatements(i_xPart.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), 0); + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("removeFile: exception"), + 0, uno::makeAny(e)); + } +} + +static ::std::vector< uno::Reference< rdf::XURI > > +getAllParts(struct DocumentMetadataAccess_Impl & i_rImpl) +{ + ::std::vector< uno::Reference< rdf::XURI > > ret; + try { + const uno::Reference<container::XEnumeration> xEnum( + i_rImpl.m_xManifest->getStatements( i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext), 0), + uno::UNO_SET_THROW); + while (xEnum->hasMoreElements()) { + rdf::Statement stmt; + if (!(xEnum->nextElement() >>= stmt)) { + throw uno::RuntimeException(); + } + const uno::Reference<rdf::XURI> xPart(stmt.Object, + uno::UNO_QUERY); + if (!xPart.is()) continue; + ret.push_back(xPart); + } + return ret; + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("getAllParts: exception"), + 0, uno::makeAny(e)); + } +} + +static bool +isPartOfType(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference<rdf::XURI> const & i_xPart, + uno::Reference<rdf::XURI> const & i_xType) +{ + if (!i_xPart.is() || !i_xType.is()) throw uno::RuntimeException(); + try { + const uno::Reference<container::XEnumeration> xEnum( + i_rImpl.m_xManifest->getStatements(i_xPart.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + i_xType.get()), + uno::UNO_SET_THROW); + return (xEnum->hasMoreElements()); + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("isPartOfType: exception"), + 0, uno::makeAny(e)); + } +} + +//////////////////////////////////////////////////////////////////////////// + +static ucb::InteractiveAugmentedIOException +mkException( ::rtl::OUString const & i_rMessage, + ucb::IOErrorCode const i_ErrorCode, + ::rtl::OUString const & i_rUri, ::rtl::OUString const & i_rResource) +{ + ucb::InteractiveAugmentedIOException iaioe; + iaioe.Message = i_rMessage; + iaioe.Classification = task::InteractionClassification_ERROR; + iaioe.Code = i_ErrorCode; + + const beans::PropertyValue uriProp(::rtl::OUString::createFromAscii("Uri"), + -1, uno::makeAny(i_rUri), static_cast<beans::PropertyState>(0)); + const beans::PropertyValue rnProp( + ::rtl::OUString::createFromAscii("ResourceName"), + -1, uno::makeAny(i_rResource), static_cast<beans::PropertyState>(0)); + iaioe.Arguments = ::comphelper::makeSequence( + uno::makeAny(uriProp), uno::makeAny(rnProp)); + return iaioe; +} + +/** error handling policy. + <p>If a handler is given, ask it how to proceed: + <ul><li>(default:) cancel import, raise exception</li> + <li>ignore the error and continue</li> + <li>retry the action that led to the error</li></ul></p> + N.B.: must not be called before DMA is fully initalized! + @returns true iff caller should retry + */ +static bool +handleError( ucb::InteractiveAugmentedIOException const & i_rException, + const uno::Reference<task::XInteractionHandler> & i_xHandler) +{ + if (!i_xHandler.is()) { + throw lang::WrappedTargetException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: exception"), + /* *this*/ 0, uno::makeAny(i_rException)); + } + + ::rtl::Reference< ::comphelper::OInteractionRequest > pRequest( + new ::comphelper::OInteractionRequest(uno::makeAny(i_rException)) ); + ::rtl::Reference< ::comphelper::OInteractionRetry > pRetry( + new ::comphelper::OInteractionRetry ); + ::rtl::Reference< ::comphelper::OInteractionApprove > pApprove( + new ::comphelper::OInteractionApprove ); + ::rtl::Reference< ::comphelper::OInteractionAbort > pAbort( + new ::comphelper::OInteractionAbort ); + /* this does not seem to work + if (i_rException.Code != ucb::IOErrorCode_WRONG_FORMAT) { + pRequest->addContinuation( pRetry.get() ); + } + */ + pRequest->addContinuation( pApprove.get() ); + pRequest->addContinuation( pAbort.get() ); + // actually call the handler + i_xHandler->handle( pRequest.get() ); + if (pRetry->wasSelected()) { + return true; + } else if (pApprove->wasSelected()) { + return false; + } else { + OSL_ENSURE(pAbort->wasSelected(), "no continuation selected?"); + throw lang::WrappedTargetException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: exception"), + /* *this*/ 0, uno::makeAny(i_rException)); + } +} + +/** check if storage has content.xml/styles.xml; + e.g. ODB files seem to only have content.xml */ +static void +collectFilesFromStorage(uno::Reference<embed::XStorage> const& i_xStorage, + ::rtl::OUString i_Path, + std::set< ::rtl::OUString > & o_rFiles) +{ + static ::rtl::OUString content(::rtl::OUString::createFromAscii(s_content)); + static ::rtl::OUString styles (::rtl::OUString::createFromAscii(s_styles )); + try { + if (i_xStorage->hasByName(content) && + i_xStorage->isStreamElement(content)) + { + o_rFiles.insert(i_Path + content); + } + if (i_xStorage->hasByName(styles) && + i_xStorage->isStreamElement(styles)) + { + o_rFiles.insert(i_Path + styles); + } + } catch (uno::Exception &) { + OSL_TRACE("collectFilesFromStorage: exception?"); + } +} + +/** import a metadata file into repository */ +static void +readStream(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference< embed::XStorage > const & i_xStorage, + ::rtl::OUString const & i_rPath, + ::rtl::OUString const & i_rBaseURI) +{ + ::rtl::OUString dir; + ::rtl::OUString rest; + try { + if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException(); + if (dir.equalsAscii("")) { + if (i_xStorage->isStreamElement(i_rPath)) { + const uno::Reference<io::XStream> xStream( + i_xStorage->openStreamElement(i_rPath, + embed::ElementModes::READ), uno::UNO_SET_THROW); + const uno::Reference<io::XInputStream> xInStream( + xStream->getInputStream(), uno::UNO_SET_THROW ); + const uno::Reference<rdf::XURI> xBaseURI( + rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI)); + const uno::Reference<rdf::XURI> xURI( + rdf::URI::createNS(i_rImpl.m_xContext, + i_rBaseURI, i_rPath)); + i_rImpl.m_xRepository->importGraph(rdf::FileFormat::RDF_XML, + xInStream, xURI, xBaseURI); + } else { + throw mkException(::rtl::OUString::createFromAscii( + "readStream: is not a stream"), + ucb::IOErrorCode_NO_FILE, i_rBaseURI + i_rPath, i_rPath); + } + } else { + if (i_xStorage->isStorageElement(dir)) { + const uno::Reference<embed::XStorage> xDir( + i_xStorage->openStorageElement(dir, + embed::ElementModes::READ)); + const uno::Reference< beans::XPropertySet > xDirProps(xDir, + uno::UNO_QUERY_THROW); + try { + ::rtl::OUString mimeType; + xDirProps->getPropertyValue( + ::comphelper::MediaDescriptor::PROP_MEDIATYPE() ) + >>= mimeType; + if (mimeType.matchAsciiL(s_odfmime, sizeof(s_odfmime) - 1)) + { + OSL_TRACE("readStream: " + "refusing to recurse into embedded document"); + return; + } + } catch (uno::Exception &) { } + ::rtl::OUStringBuffer buf(i_rBaseURI); + buf.append(dir).append(static_cast<sal_Unicode>('/')); + readStream(i_rImpl, xDir, rest, buf.makeStringAndClear() ); + } else { + throw mkException(::rtl::OUString::createFromAscii( + "readStream: is not a directory"), + ucb::IOErrorCode_NO_DIRECTORY, i_rBaseURI + dir, dir); + } + } + } catch (container::NoSuchElementException & e) { + throw mkException(e.Message, ucb::IOErrorCode_NOT_EXISTING_PATH, + i_rBaseURI + i_rPath, i_rPath); + } catch (io::IOException & e) { + throw mkException(e.Message, ucb::IOErrorCode_CANT_READ, + i_rBaseURI + i_rPath, i_rPath); + } catch (rdf::ParseException & e) { + throw mkException(e.Message, ucb::IOErrorCode_WRONG_FORMAT, + i_rBaseURI + i_rPath, i_rPath); + } +} + +/** import a metadata file into repository */ +static void +importFile(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference<embed::XStorage> const & i_xStorage, + ::rtl::OUString const & i_rBaseURI, + uno::Reference<task::XInteractionHandler> const & i_xHandler, + ::rtl::OUString i_rPath) +{ +retry: + try { + readStream(i_rImpl, i_xStorage, i_rPath, i_rBaseURI); + } catch (ucb::InteractiveAugmentedIOException & e) { + if (handleError(e, i_xHandler)) goto retry; + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("importFile: exception"), + 0, uno::makeAny(e)); + } +} + +/** actually write a metadata file to the storage */ +static void +exportStream(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference< embed::XStorage > const & i_xStorage, + uno::Reference<rdf::XURI> const & i_xGraphName, + ::rtl::OUString const & i_rFileName, + ::rtl::OUString const & i_rBaseURI) +{ + const uno::Reference<io::XStream> xStream( + i_xStorage->openStreamElement(i_rFileName, + embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE), + uno::UNO_SET_THROW); + const uno::Reference< beans::XPropertySet > xStreamProps(xStream, + uno::UNO_QUERY); + if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage + xStreamProps->setPropertyValue( + ::rtl::OUString::createFromAscii("MediaType"), + uno::makeAny(::rtl::OUString::createFromAscii(s_rdfxml))); + } + const uno::Reference<io::XOutputStream> xOutStream( + xStream->getOutputStream(), uno::UNO_SET_THROW ); + const uno::Reference<rdf::XURI> xBaseURI( + rdf::URI::create(i_rImpl.m_xContext, i_rBaseURI)); + i_rImpl.m_xRepository->exportGraph(rdf::FileFormat::RDF_XML, + xOutStream, i_xGraphName, xBaseURI); +} + +/** write a metadata file to the storage */ +static void +writeStream(struct DocumentMetadataAccess_Impl & i_rImpl, + uno::Reference< embed::XStorage > const & i_xStorage, + uno::Reference<rdf::XURI> const & i_xGraphName, + ::rtl::OUString const & i_rPath, + ::rtl::OUString const & i_rBaseURI) +{ + ::rtl::OUString dir; + ::rtl::OUString rest; + if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException(); + try { + if (dir.equalsAscii("")) { + exportStream(i_rImpl, i_xStorage, i_xGraphName, i_rPath, + i_rBaseURI); + } else { + const uno::Reference<embed::XStorage> xDir( + i_xStorage->openStorageElement(dir, + embed::ElementModes::WRITE)); + const uno::Reference< beans::XPropertySet > xDirProps(xDir, + uno::UNO_QUERY_THROW); + try { + ::rtl::OUString mimeType; + xDirProps->getPropertyValue( + ::comphelper::MediaDescriptor::PROP_MEDIATYPE() ) + >>= mimeType; + if (mimeType.matchAsciiL(s_odfmime, sizeof(s_odfmime) - 1)) { + OSL_TRACE("writeStream: " + "refusing to recurse into embedded document"); + return; + } + } catch (uno::Exception &) { } + ::rtl::OUStringBuffer buf(i_rBaseURI); + buf.append(dir).append(static_cast<sal_Unicode>('/')); + writeStream(i_rImpl, xDir, i_xGraphName, rest, + buf.makeStringAndClear()); + } + const uno::Reference<embed::XTransactedObject> xTransaction( + i_xStorage, uno::UNO_QUERY); + if (xTransaction.is()) { + xTransaction->commit(); + } + } catch (uno::RuntimeException &) { + throw; + } catch (io::IOException &) { + throw; + } +} + +static void +initLoading(struct DocumentMetadataAccess_Impl & i_rImpl, + const uno::Reference< embed::XStorage > & i_xStorage, + const uno::Reference<rdf::XURI> & i_xBaseURI, + const uno::Reference<task::XInteractionHandler> & i_xHandler) +{ +retry: + // clear old data + i_rImpl.m_xManifest.clear(); + // init BaseURI + i_rImpl.m_xBaseURI = i_xBaseURI; + + // create repository + i_rImpl.m_xRepository.clear(); + i_rImpl.m_xRepository.set(rdf::Repository::create(i_rImpl.m_xContext), + uno::UNO_SET_THROW); + + const ::rtl::OUString manifest ( + ::rtl::OUString::createFromAscii(s_manifest)); + const ::rtl::OUString baseURI( i_xBaseURI->getStringValue() ); + // try to delay raising errors until after initialization is done + uno::Any rterr; + ucb::InteractiveAugmentedIOException iaioe; + bool err(false); + + const uno::Reference <rdf::XURI> xManifest( + getURIForStream(i_rImpl, manifest)); + try { + readStream(i_rImpl, i_xStorage, manifest, baseURI); + } catch (ucb::InteractiveAugmentedIOException & e) { + // no manifest.rdf: this is not an error in ODF < 1.2 + if (!(ucb::IOErrorCode_NOT_EXISTING_PATH == e.Code)) { + iaioe = e; + err = true; + } + } catch (uno::Exception & e) { + rterr <<= e; + } + + // init manifest graph + const uno::Reference<rdf::XNamedGraph> xManifestGraph( + i_rImpl.m_xRepository->getGraph(xManifest)); + i_rImpl.m_xManifest.set(xManifestGraph.is() ? xManifestGraph : + i_rImpl.m_xRepository->createGraph(xManifest), uno::UNO_SET_THROW); + const uno::Reference<container::XEnumeration> xEnum( + i_rImpl.m_xManifest->getStatements(0, + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext).get())); + + // document statement + i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext).get()); + + OSL_ENSURE(i_rImpl.m_xBaseURI.is(), "base URI is null"); + OSL_ENSURE(i_rImpl.m_xRepository.is(), "repository is null"); + OSL_ENSURE(i_rImpl.m_xManifest.is(), "manifest is null"); + + if (rterr.hasValue()) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "exception"), 0, rterr); + } + + if (err) { + if (handleError(iaioe, i_xHandler)) goto retry; + } +} + +/** init Impl struct */ +static void init(struct DocumentMetadataAccess_Impl & i_rImpl) +{ + try { + + i_rImpl.m_xManifest.set(i_rImpl.m_xRepository->createGraph( + getURIForStream(i_rImpl, + ::rtl::OUString::createFromAscii(s_manifest))), + uno::UNO_SET_THROW); + + // insert the document statement + i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(), + getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), + getURI<rdf::URIs::PKG_DOCUMENT>(i_rImpl.m_xContext).get()); + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii("init: unexpected exception"), 0, + uno::makeAny(e)); + } + + // add top-level content files + if (!addContentOrStylesFileImpl(i_rImpl, + ::rtl::OUString::createFromAscii(s_content))) { + throw uno::RuntimeException(); + } + if (!addContentOrStylesFileImpl(i_rImpl, + ::rtl::OUString::createFromAscii(s_styles))) { + throw uno::RuntimeException(); + } +} + + +//////////////////////////////////////////////////////////////////////////// + +DocumentMetadataAccess::DocumentMetadataAccess( + uno::Reference< uno::XComponentContext > const & i_xContext, + const IXmlIdRegistrySupplier & i_rRegistrySupplier) + : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier)) +{ + // no initalization: must call loadFrom... +} + +DocumentMetadataAccess::DocumentMetadataAccess( + uno::Reference< uno::XComponentContext > const & i_xContext, + const IXmlIdRegistrySupplier & i_rRegistrySupplier, + ::rtl::OUString const & i_rURI) + : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext, i_rRegistrySupplier)) +{ + OSL_ENSURE(i_rURI.getLength(), "DMA::DMA: no URI given!"); + OSL_ENSURE(i_rURI.endsWithAsciiL("/", 1), "DMA::DMA: URI without / given!"); + if (!i_rURI.endsWithAsciiL("/", 1)) throw uno::RuntimeException(); + m_pImpl->m_xBaseURI.set(rdf::URI::create(m_pImpl->m_xContext, i_rURI)); + m_pImpl->m_xRepository.set(rdf::Repository::create(m_pImpl->m_xContext), + uno::UNO_SET_THROW); + + // init repository + init(*m_pImpl); + + OSL_ENSURE(m_pImpl->m_xBaseURI.is(), "base URI is null"); + OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository is null"); + OSL_ENSURE(m_pImpl->m_xManifest.is(), "manifest is null"); +} + +DocumentMetadataAccess::~DocumentMetadataAccess() +{ +} + + +// ::com::sun::star::rdf::XRepositorySupplier: +uno::Reference< rdf::XRepository > SAL_CALL +DocumentMetadataAccess::getRDFRepository() throw (uno::RuntimeException) +{ + OSL_ENSURE(m_pImpl->m_xRepository.is(), "repository not initialized"); + return m_pImpl->m_xRepository; +} + +// ::com::sun::star::rdf::XNode: +::rtl::OUString SAL_CALL +DocumentMetadataAccess::getStringValue() throw (uno::RuntimeException) +{ + return m_pImpl->m_xBaseURI->getStringValue(); +} + +// ::com::sun::star::rdf::XURI: +::rtl::OUString SAL_CALL +DocumentMetadataAccess::getNamespace() throw (uno::RuntimeException) +{ + return m_pImpl->m_xBaseURI->getNamespace(); +} + +::rtl::OUString SAL_CALL +DocumentMetadataAccess::getLocalName() throw (uno::RuntimeException) +{ + return m_pImpl->m_xBaseURI->getLocalName(); +} + +// ::com::sun::star::rdf::XDocumentMetadataAccess: +uno::Reference< rdf::XMetadatable > SAL_CALL +DocumentMetadataAccess::getElementByMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) +throw (uno::RuntimeException) +{ + const IXmlIdRegistry * pReg( + m_pImpl->m_rXmlIdRegistrySupplier.GetXmlIdRegistry() ); + if (!pReg) { + throw uno::RuntimeException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::getElementByXmlId: no registry"), *this); + } + return pReg->GetElementByMetadataReference(i_rReference); +} + +uno::Reference< rdf::XMetadatable > SAL_CALL +DocumentMetadataAccess::getElementByURI( + const uno::Reference< rdf::XURI > & i_xURI ) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + if (!i_xURI.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::getElementByURI: URI is null"), *this, 0); + } + + const ::rtl::OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() ); + const ::rtl::OUString name( i_xURI->getStringValue() ); + if (!name.match(baseURI)) { + return 0; + } + const ::rtl::OUString relName( name.copy(baseURI.getLength()) ); + ::rtl::OUString path; + ::rtl::OUString idref; + if (!splitXmlId(relName, path, idref)) { + return 0; + } + + return getElementByMetadataReference( beans::StringPair(path, idref) ); +} + + +uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL +DocumentMetadataAccess::getMetadataGraphsWithType( + const uno::Reference<rdf::XURI> & i_xType) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + if (!i_xType.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::getMetadataGraphsWithType: " + "type is null"), *this, 0); + } + + ::comphelper::SequenceAsVector< uno::Reference< rdf::XURI > > ret; + const ::std::vector< uno::Reference< rdf::XURI > > parts( + getAllParts(*m_pImpl) ); + ::std::remove_copy_if(parts.begin(), parts.end(), + ::std::back_inserter(ret), + ::boost::bind( + ::std::logical_not<bool>(), + ::boost::bind(&isPartOfType, ::boost::ref(*m_pImpl), _1, i_xType) )); + return ret.getAsConstList(); +} + +uno::Reference<rdf::XURI> SAL_CALL +DocumentMetadataAccess::addMetadataFile(const ::rtl::OUString & i_rFileName, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::ElementExistException) +{ + if (!isFileNameValid(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addMetadataFile: invalid FileName"), + *this, 0); + } + if (isReservedFile(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addMetadataFile:" + "invalid FileName: reserved"), *this, 0); + } + for (sal_Int32 i = 0; i < i_rTypes.getLength(); ++i) { + if (!i_rTypes[i].is()) { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addMetadataFile: " + "null type"), *this, 2); + } + } + + const uno::Reference<rdf::XURI> xGraphName( + getURIForStream(*m_pImpl, i_rFileName) ); + + try { + m_pImpl->m_xRepository->createGraph(xGraphName); + } catch (rdf::RepositoryException & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addMetadataFile: exception"), + *this, uno::makeAny(e)); + // note: all other exceptions are propagated + } + + addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes); + return xGraphName; +} + +uno::Reference<rdf::XURI> SAL_CALL +DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format, + const uno::Reference< io::XInputStream > & i_xInStream, + const ::rtl::OUString & i_rFileName, + const uno::Reference< rdf::XURI > & i_xBaseURI, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +throw (uno::RuntimeException, lang::IllegalArgumentException, + datatransfer::UnsupportedFlavorException, + container::ElementExistException, rdf::ParseException, io::IOException) +{ + if (!isFileNameValid(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::importMetadataFile: invalid FileName"), + *this, 0); + } + if (isReservedFile(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::importMetadataFile:" + "invalid FileName: reserved"), *this, 0); + } + for (sal_Int32 i = 0; i < i_rTypes.getLength(); ++i) { + if (!i_rTypes[i].is()) { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::importMetadataFile: null type"), + *this, 5); + } + } + + const uno::Reference<rdf::XURI> xGraphName( + getURIForStream(*m_pImpl, i_rFileName) ); + + try { + m_pImpl->m_xRepository->importGraph( + i_Format, i_xInStream, xGraphName, i_xBaseURI); + } catch (rdf::RepositoryException & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::importMetadataFile: " + "RepositoryException"), *this, uno::makeAny(e)); + // note: all other exceptions are propagated + } + + // add to manifest + addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes); + return xGraphName; +} + +void SAL_CALL +DocumentMetadataAccess::removeMetadataFile( + const uno::Reference< rdf::XURI > & i_xGraphName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::NoSuchElementException) +{ + try { + m_pImpl->m_xRepository->destroyGraph(i_xGraphName); + } catch (rdf::RepositoryException & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::removeMetadataFile: " + "RepositoryException"), *this, uno::makeAny(e)); + // note: all other exceptions are propagated + } + + // remove file from manifest + removeFile(*m_pImpl, i_xGraphName.get()); +} + +void SAL_CALL +DocumentMetadataAccess::addContentOrStylesFile( + const ::rtl::OUString & i_rFileName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::ElementExistException) +{ + if (!isFileNameValid(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addContentOrStylesFile: " + "invalid FileName"), *this, 0); + } + + if (!addContentOrStylesFileImpl(*m_pImpl, i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::addContentOrStylesFile: " + "invalid FileName: must end with content.xml or styles.xml"), + *this, 0); + } +} + +void SAL_CALL +DocumentMetadataAccess::removeContentOrStylesFile( + const ::rtl::OUString & i_rFileName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::NoSuchElementException) +{ + if (!isFileNameValid(i_rFileName)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::removeContentOrStylesFile: " + "invalid FileName"), *this, 0); + } + + try { + const uno::Reference<rdf::XURI> xPart( + getURIForStream(*m_pImpl, i_rFileName) ); + const uno::Reference<container::XEnumeration> xEnum( + m_pImpl->m_xManifest->getStatements( m_pImpl->m_xBaseURI.get(), + getURI<rdf::URIs::PKG_HASPART>(m_pImpl->m_xContext), + xPart.get()), + uno::UNO_SET_THROW); + if (!xEnum->hasMoreElements()) { + throw container::NoSuchElementException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::removeContentOrStylesFile: " + "cannot find stream in manifest graph: ") + i_rFileName, + *this); + } + + // remove file from manifest + removeFile(*m_pImpl, xPart); + + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::removeContentOrStylesFile: exception"), + *this, uno::makeAny(e)); + } +} + +void SAL_CALL DocumentMetadataAccess::loadMetadataFromStorage( + const uno::Reference< embed::XStorage > & i_xStorage, + const uno::Reference<rdf::XURI> & i_xBaseURI, + const uno::Reference<task::XInteractionHandler> & i_xHandler) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + if (!i_xStorage.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "storage is null"), *this, 0); + } + if (!i_xBaseURI.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "base URI is null"), *this, 1); + } + const ::rtl::OUString baseURI( i_xBaseURI->getStringValue()); + if (baseURI.indexOf('#') >= 0) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "base URI not absolute"), *this, 1); + } + if (!baseURI.getLength() || !baseURI.endsWithAsciiL("/", 1)) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "base URI does not end with slash"), *this, 1); + } + + initLoading(*m_pImpl, i_xStorage, i_xBaseURI, i_xHandler); + + std::set< ::rtl::OUString > StgFiles; + collectFilesFromStorage(i_xStorage, + ::rtl::OUString::createFromAscii(""), StgFiles); + + std::vector< ::rtl::OUString > MfstMetadataFiles; + + try { + const ::std::vector< uno::Reference< rdf::XURI > > parts( + getAllParts(*m_pImpl) ); + const uno::Reference<rdf::XURI> xContentFile( + getURI<rdf::URIs::ODF_CONTENTFILE>(m_pImpl->m_xContext)); + const uno::Reference<rdf::XURI> xStylesFile( + getURI<rdf::URIs::ODF_STYLESFILE>(m_pImpl->m_xContext)); + const uno::Reference<rdf::XURI> xMetadataFile( + getURI<rdf::URIs::PKG_METADATAFILE>(m_pImpl->m_xContext)); + const sal_Int32 len( baseURI.getLength() ); + const ::rtl::OUString manifest ( + ::rtl::OUString::createFromAscii(s_manifest)); + for (::std::vector< uno::Reference< rdf::XURI > >::const_iterator it + = parts.begin(); + it != parts.end(); ++it) { + const ::rtl::OUString name((*it)->getStringValue()); + if (!name.match(baseURI)) { + OSL_TRACE("loadMetadataFromStorage: graph not in document: %s", + ::rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8) + .getStr()); + continue; + } + const ::rtl::OUString relName( name.copy(len) ); + if (relName == manifest) { + OSL_TRACE("loadMetadataFromStorage: " + "found ourselves a recursive manifest!"); + continue; + } + // remove found items from StgFiles + StgFiles.erase(relName); + if (isContentFile(relName)) { + if (!isPartOfType(*m_pImpl, *it, xContentFile)) { + const uno::Reference <rdf::XURI> xName( + getURIForStream(*m_pImpl, relName) ); + // add missing type statement + m_pImpl->m_xManifest->addStatement(xName.get(), + getURI<rdf::URIs::RDF_TYPE>(m_pImpl->m_xContext), + xContentFile.get()); + } + } else if (isStylesFile(relName)) { + if (!isPartOfType(*m_pImpl, *it, xStylesFile)) { + const uno::Reference <rdf::XURI> xName( + getURIForStream(*m_pImpl, relName) ); + // add missing type statement + m_pImpl->m_xManifest->addStatement(xName.get(), + getURI<rdf::URIs::RDF_TYPE>(m_pImpl->m_xContext), + xStylesFile.get()); + } + } else if (isReservedFile(relName)) { + OSL_TRACE("loadMetadataFromStorage: " + "reserved file name in manifest"); + } else { + if (isPartOfType(*m_pImpl, *it, xMetadataFile)) { + MfstMetadataFiles.push_back(relName); + } + // do not add statement for MetadataFile; it could be + // something else! just ignore it... + } + } + } catch (uno::RuntimeException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromStorage: " + "exception"), *this, uno::makeAny(e)); + } + + std::for_each(StgFiles.begin(), StgFiles.end(), + boost::bind(addContentOrStylesFileImpl, boost::ref(*m_pImpl), _1)); + + std::for_each(MfstMetadataFiles.begin(), MfstMetadataFiles.end(), + boost::bind(importFile, boost::ref(*m_pImpl), + i_xStorage, baseURI, i_xHandler, _1)); +} + +void SAL_CALL DocumentMetadataAccess::storeMetadataToStorage( + const uno::Reference< embed::XStorage > & i_xStorage) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + if (!i_xStorage.is()) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::storeMetadataToStorage: " + "storage is null"), *this, 0); + } + + // export manifest + const ::rtl::OUString manifest ( + ::rtl::OUString::createFromAscii(s_manifest)); + const uno::Reference <rdf::XURI> xManifest( + getURIForStream(*m_pImpl, manifest) ); + const ::rtl::OUString baseURI( m_pImpl->m_xBaseURI->getStringValue() ); + try { + writeStream(*m_pImpl, i_xStorage, xManifest, manifest, baseURI); + } catch (uno::RuntimeException &) { + throw; + } catch (io::IOException & e) { + throw lang::WrappedTargetException( ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: IO exception"), *this, uno::makeAny(e)); + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: exception"), *this, uno::makeAny(e)); + } + + // export metadata streams + try { + const uno::Sequence<uno::Reference<rdf::XURI> > graphs( + m_pImpl->m_xRepository->getGraphNames()); + const sal_Int32 len( baseURI.getLength() ); + for (sal_Int32 i = 0; i < graphs.getLength(); ++i) { + const uno::Reference<rdf::XURI> xName(graphs[i]); + const ::rtl::OUString name(xName->getStringValue()); + if (!name.match(baseURI)) { + OSL_TRACE("storeMetadataToStorage: graph not in document: %s", + ::rtl::OUStringToOString(name, RTL_TEXTENCODING_UTF8) + .getStr()); + continue; + } + const ::rtl::OUString relName( name.copy(len) ); + if (relName == manifest) { + continue; + } + if (!isFileNameValid(relName) || isReservedFile(relName)) { + OSL_TRACE("storeMetadataToStorage: invalid file name: %s", + ::rtl::OUStringToOString(relName, RTL_TEXTENCODING_UTF8) + .getStr()); + continue; + } + try { + writeStream(*m_pImpl, i_xStorage, xName, relName, baseURI); + } catch (uno::RuntimeException &) { + throw; + } catch (io::IOException & e) { + throw lang::WrappedTargetException( + ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: IO exception"), + *this, uno::makeAny(e)); + } catch (uno::Exception & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: exception"), + *this, uno::makeAny(e)); + } + } + } catch (rdf::RepositoryException & e) { + throw lang::WrappedTargetRuntimeException( + ::rtl::OUString::createFromAscii( + "storeMetadataToStorage: exception"), *this, uno::makeAny(e)); + } +} + +void SAL_CALL +DocumentMetadataAccess::loadMetadataFromMedium( + const uno::Sequence< beans::PropertyValue > & i_rMedium) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + uno::Reference<io::XInputStream> xIn; + ::comphelper::MediaDescriptor md(i_rMedium); + ::rtl::OUString URL; + md[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL; + ::rtl::OUString BaseURL; + md[ ::comphelper::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= BaseURL; + if (md.addInputStream()) { + md[ ::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn; + } + if (!xIn.is() && URL.equalsAscii("")) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromMedium: " + "inalid medium: no URL, no input stream"), *this, 0); + } + uno::Reference<embed::XStorage> xStorage; + try { + const uno::Reference<lang::XMultiServiceFactory> xMsf ( + m_pImpl->m_xContext->getServiceManager(), uno::UNO_QUERY_THROW); + if (xIn.is()) { + xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream( + xIn, xMsf); + } else { // fallback to url + xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2( + URL, embed::ElementModes::READ, xMsf); + } + } catch (uno::RuntimeException &) { + throw; + } catch (io::IOException &) { + throw; + } catch (uno::Exception & e) { + throw lang::WrappedTargetException( + ::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromMedium: " + "exception"), *this, uno::makeAny(e)); + } + if (!xStorage.is()) { + throw uno::RuntimeException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::loadMetadataFromMedium: " + "cannot get Storage"), *this); + } + uno::Reference<rdf::XURI> xBaseURI; + try { + xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, BaseURL); + } catch (uno::Exception &) { + // fall back to URL + try { + xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, URL); + } catch (uno::Exception &) { + OSL_ENSURE(false, "cannot create base URI"); + } + } + uno::Reference<task::XInteractionHandler> xIH; + md[ ::comphelper::MediaDescriptor::PROP_INTERACTIONHANDLER() ] >>= xIH; + loadMetadataFromStorage(xStorage, xBaseURI, xIH); +} + +void SAL_CALL +DocumentMetadataAccess::storeMetadataToMedium( + const uno::Sequence< beans::PropertyValue > & i_rMedium) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + ::comphelper::MediaDescriptor md(i_rMedium); + ::rtl::OUString URL; + md[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL; + if (URL.equalsAscii("")) { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::storeMetadataToMedium: " + "invalid medium: no URL"), *this, 0); + } + + SfxMedium aMedium(i_rMedium); + uno::Reference<embed::XStorage> xStorage(aMedium.GetOutputStorage()); + + bool sfx(false); + if (xStorage.is()) { + sfx = true; + } else { + const uno::Reference<lang::XMultiServiceFactory> xMsf ( + m_pImpl->m_xContext->getServiceManager(), uno::UNO_QUERY_THROW); + xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2( + URL, embed::ElementModes::WRITE, xMsf); + } + + if (!xStorage.is()) { + throw uno::RuntimeException(::rtl::OUString::createFromAscii( + "DocumentMetadataAccess::storeMetadataToMedium: " + "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()) { + uno::Reference< beans::XPropertySet > xProps(xStorage, + uno::UNO_QUERY_THROW); + try { + // this is NOT supported in FileSystemStorage + xProps->setPropertyValue( + ::comphelper::MediaDescriptor::PROP_MEDIATYPE(), + iter->second); + } catch (uno::Exception &) { } + } + storeMetadataToStorage(xStorage); + + if (sfx) { + const sal_Bool bOk = aMedium.Commit(); + aMedium.Close(); + if ( !bOk ) { + sal_uInt32 nError = aMedium.GetError(); + if ( nError == ERRCODE_NONE ) { + nError = ERRCODE_IO_GENERAL; + } + task::ErrorCodeIOException ex( ::rtl::OUString(), + uno::Reference< uno::XInterface >(), nError); + throw lang::WrappedTargetException(::rtl::OUString(), *this, + uno::makeAny(ex)); + } + } +} + +} // namespace sfx2 + diff --git a/sfx2/source/doc/Metadatable.cxx b/sfx2/source/doc/Metadatable.cxx new file mode 100644 index 000000000000..2ad27856c7cc --- /dev/null +++ b/sfx2/source/doc/Metadatable.cxx @@ -0,0 +1,1860 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: SwMetadatable.cxx,v $ + * $Revision: 1.1.2.8 $ + * + * 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 <sfx2/Metadatable.hxx> +#include <sfx2/XmlIdRegistry.hxx> + +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> // solarmutex + +#include <boost/bind.hpp> + +#include <memory> +#include <hash_map> +#include <list> +#include <algorithm> +#if OSL_DEBUG_LEVEL > 0 +#include <typeinfo> +#endif + + +/** XML ID handling. + + There is an abstract base class <type>XmlIdRegistry</type>, with + 2 subclasses <type>XmlIdRegistryDocument</type> for "normal" documents, + and <type>XmlIdRegistryClipboard</type> for clipboard documents. + These classes are responsible for managing XML IDs for all elements + of the model. Only the implementation of the <type>Metadatable</type> + base class needs to know the registries, so they are not in the header. + + The handling of XML IDs differs between clipboard and non-clipboard + documents in several aspects. Most importantly, non-clipboard documents + can have several elements associated with one XML ID. + This is necessary because of the weird undo implementation: + deleting a text node moves the deleted node to the undo array, but + executing undo will then create a <em>copy</em> of that node in the + document array. These 2 nodes must have the same XML ID, because + we cannot know whether the user will do a redo next, or something else. + + Because we need to have a mechanism for several objects per XML ID anyway, + we use that also to enable some usability features: + The document registry has a list of Metadatables per XML ID. + This list is sorted by priority, i.e., the first element has highest + priority. When inserting copies, care must be taken that they are inserted + at the right position: either before or after the source. + This is done by <method>Metadatable::RegisterAsCopyOf</method>. + When a text node is split, then both resulting text nodes are inserted + into the list. If the user then deletes one text node, the other one + will have the XML ID. + Also, when a Metadatable is copied to the clipboard and then pasted, + the copy is inserted into the list. If the user then deletes the source, + the XML ID is not lost. + The goal is that it should be hard to lose an XML ID by accident, which + is especially important as long as we do not have an UI that displays them. + + There are two subclasses of <type>Metadatable</type>: + <ul><li><type>MetadatableClipboard</type>: for copies in the clipboard</li> + <li><type>MetadatableUndo</type>: for undo, because a Metadatable + may be destroyed on delete and a new one created on undo.</li></ul> + These serve only to track the position in an XML ID list in a document + registry, so that future actions can insert objects at the right position. + Unfortunately, inserting dummy objects seems to be necessary: + <ul><li>it is not sufficent to just remember the saved id, because then + the relative priorities might change when executing the undo</li> + <li>it is not sufficient to record the position as an integer, because + if we delete a text node and then undo, the node will be copied(!), + and we will have one more node in the list.<li> + <li>it is not sufficient to record the pointer of the previous/next + Metadatable, because if we delete a text node, undo, and then + do something to clear the redo array, the original text node is + destroyed, and is replaced by the copy created by undo</li></ul> + + If content from a non-clipboard document is copied into a clipboard + document, a dummy <type>MetadatableClipboard</type> is inserted into the + non-clipboard document registry in order to track the position of the + source element. When the clipboard content is pasted back into the source + document, this dummy object is used to associate the pasted element with + that same XML ID. + + If a <type>Metadatable</type> is deleted or merged, + <method>Metadatable::CreateUndo</method> is called, and returns a + <type>MetadatableUndo<type> instance, which can be used to undo the action + by passing it to <method>Metadatable::RestoreMetadata</method>. + + @author mst + */ + + +using namespace ::com::sun::star; + +using ::sfx2::isValidXmlId; + + +namespace sfx2 { + +static const char s_content [] = "content.xml"; +static const char s_styles [] = "styles.xml"; +static const char s_prefix [] = "id"; // prefix for generated xml:id + +static bool isContentFile(::rtl::OUString const & i_rPath) +{ + return i_rPath.equalsAscii(s_content); +} + +static bool isStylesFile (::rtl::OUString const & i_rPath) +{ + return i_rPath.equalsAscii(s_styles); +} + + +//============================================================================= +// XML ID handling --------------------------------------------------- + +/** handles registration of XMetadatable. + + This class is responsible for guaranteeing that XMetadatable objects + always have XML IDs that are unique within a stream. + + This is an abstract base class; see subclasses XmlIdRegistryDocument and + XmlIdRegistryClipboard. + + @see SwDoc::GetXmlIdRegistry + @see SwDocShell::GetXmlIdRegistry + */ +class XmlIdRegistry : public sfx2::IXmlIdRegistry +{ + +public: + XmlIdRegistry(); + + virtual ~XmlIdRegistry(); + + /** get the ODF element with the given metadata reference. */ + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > SAL_CALL + GetElementByMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) const; + + /** register an ODF element at a newly generated, unique metadata reference. + + <p> + Find a fresh XML ID, and register it for the element. + The generated ID does not occur in any stream of the document. + </p> + */ + virtual void RegisterMetadatableAndCreateID(Metadatable& i_xObject) = 0; + + /** try to register an ODF element at a given XML ID, or update its + registation to a different XML ID. + + <p> + If the given new metadata reference is not already occupied in the + document, unregister the element at its old metadata reference if + it has one, and register the new metadata reference for the element. + Note that this method only ensures that XML IDs are unique per stream, + so using the same XML ID in both content.xml and styles.xml is allowed. + </p> + + @returns + true iff the element has successfully been registered + */ + virtual bool TryRegisterMetadatable(Metadatable& i_xObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref) + = 0; + + /** unregister an ODF element. + + <p> + Unregister the element at its metadata reference. + Does not remove the metadata reference from the element. + </p> + + @see RemoveXmlIdForElement + */ + virtual void UnregisterMetadatable(Metadatable const&) = 0; + + /** get the metadata reference for the given element. */ + ::com::sun::star::beans::StringPair + GetXmlIdForElement(Metadatable const&) const; + + /** remove the metadata reference for the given element. */ + virtual void RemoveXmlIdForElement(Metadatable const&) = 0; + +protected: + + virtual bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const = 0; + + virtual Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const = 0; +}; + +// XmlIdRegistryDocument --------------------------------------------- + +/** non-clipboard documents */ +class XmlIdRegistryDocument : public XmlIdRegistry +{ + +public: + XmlIdRegistryDocument(); + + virtual ~XmlIdRegistryDocument(); + + virtual void RegisterMetadatableAndCreateID(Metadatable& i_xObject); + + virtual bool TryRegisterMetadatable(Metadatable& i_xObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref); + + virtual void UnregisterMetadatable(Metadatable const&); + + virtual void RemoveXmlIdForElement(Metadatable const&); + + /** register i_rCopy as a copy of i_rSource, + with precedence iff i_bCopyPrecedesSource is true */ + void RegisterCopy(Metadatable const& i_rSource, Metadatable & i_rCopy, + const bool i_bCopyPrecedesSource); + + /** create a Undo Metadatable for i_rObject. */ + ::boost::shared_ptr<MetadatableUndo> CreateUndo( + Metadatable const& i_rObject); + + /** merge i_rMerged and i_rOther into i_rMerged. */ + void JoinMetadatables(Metadatable & i_rMerged, Metadatable const& i_rOther); + + // unfortunately public, Metadatable::RegisterAsCopyOf needs this + virtual bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const; + +private: + + virtual Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + struct XmlIdRegistry_Impl; + ::std::auto_ptr<XmlIdRegistry_Impl> m_pImpl; +}; + +// MetadatableUndo --------------------------------------------------- + +/** the horrible Undo Metadatable: is inserted into lists to track position */ +class MetadatableUndo : public Metadatable +{ + /// as determined by the stream of the source in original document + const bool m_isInContent; +public: + MetadatableUndo(const bool i_isInContent) + : m_isInContent(i_isInContent) { } + virtual ::sfx2::XmlIdRegistry& GetRegistry() + { + // N.B. for Undo, m_pReg is initialized by registering this as copy in + // CreateUndo; it is never cleared + OSL_ENSURE(m_pReg, "no m_pReg in MetadatableUndo ?"); + return *m_pReg; + } + virtual bool IsInClipboard() const { return false; } + virtual bool IsInUndo() const { return true; } + virtual bool IsInContent() const { return m_isInContent; } + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > MakeUnoObject() + { OSL_ENSURE(false, "MetadatableUndo::MakeUnoObject"); throw; } +}; + +// MetadatableClipboard ---------------------------------------------- + +/** the horrible Clipboard Metadatable: inserted into lists to track position */ +class MetadatableClipboard : public Metadatable +{ + /// as determined by the stream of the source in original document + const bool m_isInContent; +public: + MetadatableClipboard(const bool i_isInContent) + : m_isInContent(i_isInContent) { } + virtual ::sfx2::XmlIdRegistry& GetRegistry() + { + // N.B. for Clipboard, m_pReg is initialized by registering this as copy in + // RegisterAsCopyOf; it is only cleared by OriginNoLongerInBusinessAnymore + OSL_ENSURE(m_pReg, "no m_pReg in MetadatableClipboard ?"); + return *m_pReg; + } + virtual bool IsInClipboard() const { return true; } + virtual bool IsInUndo() const { return false; } + virtual bool IsInContent() const { return m_isInContent; } + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > MakeUnoObject() + { OSL_ENSURE(false, "MetadatableClipboard::MakeUnoObject"); throw; } + void OriginNoLongerInBusinessAnymore() { m_pReg = 0; } +}; + +// XmlIdRegistryClipboard -------------------------------------------- + +class XmlIdRegistryClipboard : public XmlIdRegistry +{ + +public: + XmlIdRegistryClipboard(); + virtual ~XmlIdRegistryClipboard(); + + virtual void RegisterMetadatableAndCreateID(Metadatable& i_xObject); + + virtual bool TryRegisterMetadatable(Metadatable& i_xObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref); + + virtual void UnregisterMetadatable(Metadatable const&); + + virtual void RemoveXmlIdForElement(Metadatable const&); + + /** register i_rCopy as a copy of i_rSource */ + MetadatableClipboard & RegisterCopyClipboard(Metadatable & i_rCopy, + beans::StringPair const & i_rReference, + const bool i_isLatent); + + /** get the Metadatable that links i_rObject to its origin registry */ + MetadatableClipboard const* SourceLink(Metadatable const& i_rObject); + +private: + virtual bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const; + + virtual Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + /** create a Clipboard Metadatable for i_rObject. */ + ::boost::shared_ptr<MetadatableClipboard> CreateClipboard( + const bool i_isInContent); + + struct XmlIdRegistry_Impl; + ::std::auto_ptr<XmlIdRegistry_Impl> m_pImpl; +}; + + +//============================================================================= +// XmlIdRegistry + +::sfx2::IXmlIdRegistry * createXmlIdRegistry(const bool i_DocIsClipboard) +{ + return i_DocIsClipboard + ? static_cast<XmlIdRegistry*>( new XmlIdRegistryClipboard ) + : static_cast<XmlIdRegistry*>( new XmlIdRegistryDocument ); +} + +XmlIdRegistry::XmlIdRegistry() +{ +} + +XmlIdRegistry::~XmlIdRegistry() +{ +} + +::com::sun::star::uno::Reference< ::com::sun::star::rdf::XMetadatable > SAL_CALL +XmlIdRegistry::GetElementByMetadataReference( + const beans::StringPair & i_rReference) const +{ + Metadatable* pObject( LookupElement(i_rReference.First, + i_rReference.Second) ); + return pObject ? pObject->MakeUnoObject() : 0; +} + +beans::StringPair +XmlIdRegistry::GetXmlIdForElement(const Metadatable& i_rObject) const +{ + ::rtl::OUString path; + ::rtl::OUString idref; + if (LookupXmlId(i_rObject, path, idref)) + { + if (LookupElement(path, idref) == &i_rObject) + { + return beans::StringPair(path, idref); + } + } + return beans::StringPair(); +} + + +/// generate unique xml:id +template< typename T > +/*static*/ ::rtl::OUString create_id(const + ::std::hash_map< ::rtl::OUString, T, ::rtl::OUStringHash > & i_rXmlIdMap) +{ + const ::rtl::OUString prefix( ::rtl::OUString::createFromAscii(s_prefix) ); + typename ::std::hash_map< ::rtl::OUString, T, ::rtl::OUStringHash > + ::const_iterator iter; + ::rtl::OUString id; + do + { + const int n( rand() ); + id = prefix + ::rtl::OUString::valueOf(static_cast<sal_Int64>(n)); + iter = i_rXmlIdMap.find(id); + } + while (iter != i_rXmlIdMap.end()); + return id; +} + +//============================================================================= +// Document XML ID Registry (_Impl) + +/// element list +typedef ::std::list< Metadatable* > XmlIdList_t; + +/// Idref -> (content.xml element list, styles.xml element list) +typedef ::std::hash_map< ::rtl::OUString, + ::std::pair< XmlIdList_t, XmlIdList_t >, ::rtl::OUStringHash > XmlIdMap_t; + +/// pointer hash template +template<typename T> struct PtrHash +{ + size_t operator() (T const * i_pT) const + { + return reinterpret_cast<size_t>(i_pT); + } +}; + +/// element -> (stream name, idref) +typedef ::std::hash_map< const Metadatable*, + ::std::pair< ::rtl::OUString, ::rtl::OUString>, PtrHash<Metadatable> > + XmlIdReverseMap_t; + +struct XmlIdRegistryDocument::XmlIdRegistry_Impl +{ + XmlIdRegistry_Impl() + : m_XmlIdMap(), m_XmlIdReverseMap() { } + + bool TryInsertMetadatable(Metadatable& i_xObject, + const ::rtl::OUString & i_rStream, const ::rtl::OUString & i_rIdref); + + bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const; + + Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + const XmlIdList_t * LookupElementList( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + XmlIdList_t * LookupElementList( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) + { + return const_cast<XmlIdList_t*>( + const_cast<const XmlIdRegistry_Impl*>(this) + ->LookupElementList(i_rStreamName, i_rIdref)); + } + + XmlIdMap_t m_XmlIdMap; + XmlIdReverseMap_t m_XmlIdReverseMap; +}; + +// ------------------------------------------------------------------- + +static void +rmIter(XmlIdMap_t & i_rXmlIdMap, XmlIdMap_t::iterator const& i_rIter, + ::rtl::OUString const & i_rStream, Metadatable const& i_rObject) +{ + if (i_rIter != i_rXmlIdMap.end()) + { + XmlIdList_t & rList( isContentFile(i_rStream) + ? i_rIter->second.first : i_rIter->second.second ); + rList.remove(&const_cast<Metadatable&>(i_rObject)); + if (i_rIter->second.first.empty() && i_rIter->second.second.empty()) + { + i_rXmlIdMap.erase(i_rIter); + } + } +} + +// ------------------------------------------------------------------- + +const XmlIdList_t * +XmlIdRegistryDocument::XmlIdRegistry_Impl::LookupElementList( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + const XmlIdMap_t::const_iterator iter( m_XmlIdMap.find(i_rIdref) ); + if (iter != m_XmlIdMap.end()) + { + OSL_ENSURE(!iter->second.first.empty() || !iter->second.second.empty(), + "null entry in m_XmlIdMap"); + return (isContentFile(i_rStreamName)) + ? &iter->second.first + : &iter->second.second; + } + else + { + return 0; + } +} + +Metadatable* +XmlIdRegistryDocument::XmlIdRegistry_Impl::LookupElement( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + if (!isValidXmlId(i_rStreamName, i_rIdref)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + + const XmlIdList_t * pList( LookupElementList(i_rStreamName, i_rIdref) ); + if (pList) + { + const XmlIdList_t::const_iterator iter( + ::std::find_if(pList->begin(), pList->end(), + ::boost::bind( + ::std::logical_not<bool>(), + ::boost::bind( + ::std::logical_or<bool>(), + ::boost::bind( &Metadatable::IsInUndo, _1 ), + ::boost::bind( &Metadatable::IsInClipboard, _1 ) + ) ) ) ); + if (iter != pList->end()) + { + return *iter; + } + } + return 0; +} + +bool +XmlIdRegistryDocument::XmlIdRegistry_Impl::LookupXmlId( + const Metadatable& i_rObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const +{ + const XmlIdReverseMap_t::const_iterator iter( + m_XmlIdReverseMap.find(&i_rObject) ); + if (iter != m_XmlIdReverseMap.end()) + { + OSL_ENSURE(!iter->second.first.equalsAscii(""), + "null stream in m_XmlIdReverseMap"); + OSL_ENSURE(!iter->second.second.equalsAscii(""), + "null id in m_XmlIdReverseMap"); + o_rStream = iter->second.first; + o_rIdref = iter->second.second; + return true; + } + else + { + return false; + } +} + +bool +XmlIdRegistryDocument::XmlIdRegistry_Impl::TryInsertMetadatable( + Metadatable & i_rObject, + const ::rtl::OUString & i_rStreamName, const ::rtl::OUString & i_rIdref) +{ + const bool bContent( isContentFile(i_rStreamName) ); + OSL_ENSURE(isContentFile(i_rStreamName) || isStylesFile(i_rStreamName), + "invalid stream"); + + XmlIdList_t * pList( LookupElementList(i_rStreamName, i_rIdref) ); + if (pList) + { + if (pList->empty()) + { + pList->push_back( &i_rObject ); + return true; + } + else + { + // this is only called from TryRegister now, so check + // if all elements in the list are deleted (in undo) or + // placeholders, then "steal" the id from them + if ( pList->end() == ::std::find_if(pList->begin(), pList->end(), + ::boost::bind( + ::std::logical_not<bool>(), + ::boost::bind( + ::std::logical_or<bool>(), + ::boost::bind( &Metadatable::IsInUndo, _1 ), + ::boost::bind( &Metadatable::IsInClipboard, _1 ) + ) ) ) ) + { +// ??? this is not undoable +// pList->clear(); +// pList->push_back( &i_rObject ); + pList->push_front( &i_rObject ); + return true; + } + else + { + return false; + } + } + } + else + { + m_XmlIdMap.insert(::std::make_pair(i_rIdref, bContent + ? ::std::make_pair( XmlIdList_t( 1, &i_rObject ), XmlIdList_t() ) + : ::std::make_pair( XmlIdList_t(), XmlIdList_t( 1, &i_rObject ) ))); + return true; + } +} + +//============================================================================= +// Document XML ID Registry + + +XmlIdRegistryDocument::XmlIdRegistryDocument() + : m_pImpl( new XmlIdRegistry_Impl ) +{ +} + +static void +removeLink(Metadatable* i_pObject) +{ + OSL_ENSURE(i_pObject, "null in list ???"); + if (!i_pObject) return; + if (i_pObject->IsInClipboard()) + { + MetadatableClipboard* pLink( + dynamic_cast<MetadatableClipboard*>( i_pObject ) ); + OSL_ENSURE(pLink, "IsInClipboard, but no MetadatableClipboard ?"); + if (pLink) + { + pLink->OriginNoLongerInBusinessAnymore(); + } + } +} + +XmlIdRegistryDocument::~XmlIdRegistryDocument() +{ + // notify all list elements that are actually in the clipboard + for (XmlIdMap_t::iterator iter(m_pImpl->m_XmlIdMap.begin()); + iter != m_pImpl->m_XmlIdMap.end(); ++iter) + { + ::std::for_each(iter->second.first.begin(), iter->second.first.end(), + removeLink); + ::std::for_each(iter->second.second.begin(), iter->second.second.end(), + removeLink); + } +} + +bool +XmlIdRegistryDocument::LookupXmlId( + const Metadatable& i_rObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const +{ + return m_pImpl->LookupXmlId(i_rObject, o_rStream, o_rIdref); +} + +Metadatable* +XmlIdRegistryDocument::LookupElement( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + return m_pImpl->LookupElement(i_rStreamName, i_rIdref); +} + +bool +XmlIdRegistryDocument::TryRegisterMetadatable(Metadatable & i_rObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref) +{ + OSL_TRACE("TryRegisterMetadatable: %p (%s#%s)\n", &i_rObject, + ::rtl::OUStringToOString(i_rStreamName, RTL_TEXTENCODING_UTF8).getStr(), + ::rtl::OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8).getStr()); + + OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), + "TryRegisterMetadatable called for MetadatableUndo?"); + OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), + "TryRegisterMetadatable called for MetadatableClipboard?"); + + if (!isValidXmlId(i_rStreamName, i_rIdref)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + if (i_rObject.IsInContent() + ? !isContentFile(i_rStreamName) + : !isStylesFile(i_rStreamName)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId: wrong stream"), 0, 0); + } + + ::rtl::OUString old_path; + ::rtl::OUString old_idref; + m_pImpl->LookupXmlId(i_rObject, old_path, old_idref); + if (old_path == i_rStreamName && old_idref == i_rIdref) + { + return (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject); + } + XmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() ); + if (!old_idref.equalsAscii("")) + { + old_id = m_pImpl->m_XmlIdMap.find(old_idref); + OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found"); + } + if (m_pImpl->TryInsertMetadatable(i_rObject, i_rStreamName, i_rIdref)) + { + rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject); + m_pImpl->m_XmlIdReverseMap[&i_rObject] = + ::std::make_pair(i_rStreamName, i_rIdref); + return true; + } + else + { + return false; + } +} + +void +XmlIdRegistryDocument::RegisterMetadatableAndCreateID(Metadatable & i_rObject) +{ + OSL_TRACE("RegisterMetadatableAndCreateID: %p\n", &i_rObject); + + OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), + "RegisterMetadatableAndCreateID called for MetadatableUndo?"); + OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), + "RegisterMetadatableAndCreateID called for MetadatableClipboard?"); + + const bool isInContent( i_rObject.IsInContent() ); + const ::rtl::OUString stream( ::rtl::OUString::createFromAscii( + isInContent ? s_content : s_styles ) ); + // check if we have a latent xmlid, and if yes, remove it + ::rtl::OUString old_path; + ::rtl::OUString old_idref; + m_pImpl->LookupXmlId(i_rObject, old_path, old_idref); + + XmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() ); + if (!old_idref.equalsAscii("")) + { + old_id = m_pImpl->m_XmlIdMap.find(old_idref); + OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found"); + if (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject) + { + return; + } + else + { + // remove latent xmlid + rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject); + } + } + + // create id + const ::rtl::OUString id( create_id(m_pImpl->m_XmlIdMap) ); + OSL_ENSURE(m_pImpl->m_XmlIdMap.find(id) == m_pImpl->m_XmlIdMap.end(), + "created id is in use"); + m_pImpl->m_XmlIdMap.insert(::std::make_pair(id, isInContent + ? ::std::make_pair( XmlIdList_t( 1, &i_rObject ), XmlIdList_t() ) + : ::std::make_pair( XmlIdList_t(), XmlIdList_t( 1, &i_rObject ) ))); + m_pImpl->m_XmlIdReverseMap[&i_rObject] = ::std::make_pair(stream, id); +} + +void XmlIdRegistryDocument::UnregisterMetadatable(const Metadatable& i_rObject) +{ + OSL_TRACE("UnregisterMetadatable: %p\n", &i_rObject); + + ::rtl::OUString path; + ::rtl::OUString idref; + if (!m_pImpl->LookupXmlId(i_rObject, path, idref)) + { + OSL_ENSURE(false, "unregister: no xml id?"); + return; + } + const XmlIdMap_t::iterator iter( m_pImpl->m_XmlIdMap.find(idref) ); + if (iter != m_pImpl->m_XmlIdMap.end()) + { + rmIter(m_pImpl->m_XmlIdMap, iter, path, i_rObject); + } +} + +void XmlIdRegistryDocument::RemoveXmlIdForElement(const Metadatable& i_rObject) +{ + OSL_TRACE("RemoveXmlIdForElement: %p\n", &i_rObject); + + const XmlIdReverseMap_t::iterator iter( + m_pImpl->m_XmlIdReverseMap.find(&i_rObject) ); + if (iter != m_pImpl->m_XmlIdReverseMap.end()) + { + OSL_ENSURE(!iter->second.second.equalsAscii(""), + "null id in m_XmlIdReverseMap"); + m_pImpl->m_XmlIdReverseMap.erase(iter); + } +} + +// ------------------------------------------------------------------- + +void XmlIdRegistryDocument::RegisterCopy(Metadatable const& i_rSource, + Metadatable & i_rCopy, const bool i_bCopyPrecedesSource) +{ + OSL_TRACE("RegisterCopy: %p -> %p (%d)\n", + &i_rSource, &i_rCopy, i_bCopyPrecedesSource); + + // potential sources: clipboard, undo array, splitNode + // assumption: stream change can only happen via clipboard, and is handled + // by Metadatable::RegisterAsCopyOf + OSL_ENSURE(i_rSource.IsInUndo() || i_rCopy.IsInUndo() || + (i_rSource.IsInContent() == i_rCopy.IsInContent()), + "RegisterCopy: not in same stream?"); + + ::rtl::OUString path; + ::rtl::OUString idref; + if (!m_pImpl->LookupXmlId( i_rSource, path, idref )) + { + OSL_ENSURE(false, "no xml id?"); + return; + } + XmlIdList_t * pList ( m_pImpl->LookupElementList(path, idref) ); + OSL_ENSURE( ::std::find( pList->begin(), pList->end(), &i_rCopy ) + == pList->end(), "copy already registered???"); + XmlIdList_t::iterator srcpos( + ::std::find( pList->begin(), pList->end(), &i_rSource ) ); + OSL_ENSURE(srcpos != pList->end(), "source not in list???"); + if (srcpos == pList->end()) + { + return; + } + if (i_bCopyPrecedesSource) + { + pList->insert( srcpos, &i_rCopy ); + } + else + { + // for undo push_back does not work! must insert right after source + pList->insert( ++srcpos, &i_rCopy ); + } + m_pImpl->m_XmlIdReverseMap.insert(::std::make_pair(&i_rCopy, + ::std::make_pair(path, idref))); +} + +::boost::shared_ptr<MetadatableUndo> +XmlIdRegistryDocument::CreateUndo(Metadatable const& i_rObject) +{ + OSL_TRACE("CreateUndo: %p\n", &i_rObject); + + return ::boost::shared_ptr<MetadatableUndo>( + new MetadatableUndo(i_rObject.IsInContent()) ); +} + +/* +i_rMerged is both a source and the target node of the merge +i_rOther is the other source, and will be deleted after the merge + +dimensions: none|latent|actual empty|nonempty +i_rMerged(1) i_rOther(2) result + *|empty *|empty => 1|2 (arbitrary) + *|empty *|nonempty => 2 + *|nonempty *|empty => 1 + none|nonempty none|nonempty => none + none|nonempty latent|nonempty => 2 +latent|nonempty none|nonempty => 1 +latent|nonempty latent|nonempty => 1|2 + *|nonempty actual|nonempty => 2 +actual|nonempty *|nonempty => 1 +actual|nonempty actual|nonempty => 1|2 +*/ +void +XmlIdRegistryDocument::JoinMetadatables( + Metadatable & i_rMerged, Metadatable const & i_rOther) +{ + OSL_TRACE("JoinMetadatables: %p <- %p\n", &i_rMerged, &i_rOther); + + bool mergedOwnsRef; + ::rtl::OUString path; + ::rtl::OUString idref; + if (m_pImpl->LookupXmlId(i_rMerged, path, idref)) + { + mergedOwnsRef = (m_pImpl->LookupElement(path, idref) == &i_rMerged); + } + else + { + OSL_ENSURE(false, "JoinMetadatables: no xmlid?"); + return; + } + if (!mergedOwnsRef) + { + i_rMerged.RemoveMetadataReference(); + i_rMerged.RegisterAsCopyOf(i_rOther, true); + return; + } + // other cases: merged has actual ref and is nonempty, + // other has latent/actual ref and is nonempty: other loses => nothing to do +} + + +//============================================================================= +// Clipboard XML ID Registry (_Impl) + +struct RMapEntry +{ + RMapEntry() : m_pLink() { } + RMapEntry(::rtl::OUString const& i_rStream, + ::rtl::OUString const& i_rXmlId, + ::boost::shared_ptr<MetadatableClipboard> const& i_pLink + = ::boost::shared_ptr<MetadatableClipboard>()) + : m_Stream(i_rStream), m_XmlId(i_rXmlId), m_pLink(i_pLink) + {} + ::rtl::OUString m_Stream; + ::rtl::OUString m_XmlId; + // this would have been an auto_ptr, if only that would have compiled... + ::boost::shared_ptr<MetadatableClipboard> m_pLink; +}; + +/// element -> (stream name, idref, source) +typedef ::std::hash_map< const Metadatable*, + struct RMapEntry, + PtrHash<Metadatable> > + ClipboardXmlIdReverseMap_t; + +/// Idref -> (content.xml element, styles.xml element) +typedef ::std::hash_map< ::rtl::OUString, + ::std::pair< Metadatable*, Metadatable* >, ::rtl::OUStringHash > + ClipboardXmlIdMap_t; + +struct XmlIdRegistryClipboard::XmlIdRegistry_Impl +{ + XmlIdRegistry_Impl() + : m_XmlIdMap(), m_XmlIdReverseMap() { } + + bool TryInsertMetadatable(Metadatable& i_xObject, + const ::rtl::OUString & i_rStream, const ::rtl::OUString & i_rIdref); + + bool LookupXmlId(const Metadatable& i_xObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref, + MetadatableClipboard const* &o_rpLink) const; + + Metadatable* LookupElement(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + Metadatable* const* LookupEntry(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const; + + Metadatable* * LookupEntry(const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) + { + return const_cast<Metadatable**>( + const_cast<const XmlIdRegistry_Impl*>(this) + ->LookupEntry(i_rStreamName, i_rIdref)); + } + + ClipboardXmlIdMap_t m_XmlIdMap; + ClipboardXmlIdReverseMap_t m_XmlIdReverseMap; +}; + +// ------------------------------------------------------------------- + +static void +rmIter(ClipboardXmlIdMap_t & i_rXmlIdMap, + ClipboardXmlIdMap_t::iterator const& i_rIter, + ::rtl::OUString const & i_rStream, Metadatable const& i_rObject) +{ + if (i_rIter != i_rXmlIdMap.end()) + { + Metadatable *& rMeta = isContentFile(i_rStream) + ? i_rIter->second.first : i_rIter->second.second; + if (rMeta == &i_rObject) + { + rMeta = 0; + } + if (!i_rIter->second.first && !i_rIter->second.second) + { + i_rXmlIdMap.erase(i_rIter); + } + } +} + +// ------------------------------------------------------------------- + +Metadatable* const* +XmlIdRegistryClipboard::XmlIdRegistry_Impl::LookupEntry( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + if (!isValidXmlId(i_rStreamName, i_rIdref)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + + const ClipboardXmlIdMap_t::const_iterator iter( m_XmlIdMap.find(i_rIdref) ); + if (iter != m_XmlIdMap.end()) + { + OSL_ENSURE(iter->second.first || iter->second.second, + "null entry in m_XmlIdMap"); + return (isContentFile(i_rStreamName)) + ? &iter->second.first + : &iter->second.second; + } + else + { + return 0; + } +} + +Metadatable* +XmlIdRegistryClipboard::XmlIdRegistry_Impl::LookupElement( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + Metadatable * const * ppEntry = LookupEntry(i_rStreamName, i_rIdref); + return ppEntry ? *ppEntry : 0; +} + +bool +XmlIdRegistryClipboard::XmlIdRegistry_Impl::LookupXmlId( + const Metadatable& i_rObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref, + MetadatableClipboard const* &o_rpLink) const +{ + const ClipboardXmlIdReverseMap_t::const_iterator iter( + m_XmlIdReverseMap.find(&i_rObject) ); + if (iter != m_XmlIdReverseMap.end()) + { + OSL_ENSURE(!iter->second.m_Stream.equalsAscii(""), + "null stream in m_XmlIdReverseMap"); + OSL_ENSURE(!iter->second.m_XmlId.equalsAscii(""), + "null id in m_XmlIdReverseMap"); + o_rStream = iter->second.m_Stream; + o_rIdref = iter->second.m_XmlId; + o_rpLink = iter->second.m_pLink.get(); + return true; + } + else + { + return false; + } +} + +bool +XmlIdRegistryClipboard::XmlIdRegistry_Impl::TryInsertMetadatable( + Metadatable & i_rObject, + const ::rtl::OUString & i_rStreamName, const ::rtl::OUString & i_rIdref) +{ + bool bContent( isContentFile(i_rStreamName) ); + OSL_ENSURE(isContentFile(i_rStreamName) || isStylesFile(i_rStreamName), + "invalid stream"); + + //wntmsci12 won't parse this: +// Metadatable ** ppEntry( LookupEntry(i_rStreamName, i_rIdref) ); + Metadatable ** ppEntry = LookupEntry(i_rStreamName, i_rIdref); + if (ppEntry) + { + if (*ppEntry) + { + return false; + } + else + { + *ppEntry = &i_rObject; + return true; + } + } + else + { + m_XmlIdMap.insert(::std::make_pair(i_rIdref, bContent + ? ::std::make_pair( &i_rObject, static_cast<Metadatable*>(0) ) + : ::std::make_pair( static_cast<Metadatable*>(0), &i_rObject ))); + return true; + } +} + +//============================================================================= +// Clipboard XML ID Registry + + +XmlIdRegistryClipboard::XmlIdRegistryClipboard() + : m_pImpl( new XmlIdRegistry_Impl ) +{ +} + +XmlIdRegistryClipboard::~XmlIdRegistryClipboard() +{ +} + +bool +XmlIdRegistryClipboard::LookupXmlId( + const Metadatable& i_rObject, + ::rtl::OUString & o_rStream, ::rtl::OUString & o_rIdref) const +{ + const MetadatableClipboard * pLink; + return m_pImpl->LookupXmlId(i_rObject, o_rStream, o_rIdref, pLink); +} + +Metadatable* +XmlIdRegistryClipboard::LookupElement( + const ::rtl::OUString & i_rStreamName, + const ::rtl::OUString & i_rIdref) const +{ + return m_pImpl->LookupElement(i_rStreamName, i_rIdref); +} + +bool +XmlIdRegistryClipboard::TryRegisterMetadatable(Metadatable & i_rObject, + ::rtl::OUString const& i_rStreamName, ::rtl::OUString const& i_rIdref) +{ + OSL_TRACE("TryRegisterMetadatable: %p (%s#%s)\n", &i_rObject, + ::rtl::OUStringToOString(i_rStreamName, RTL_TEXTENCODING_UTF8).getStr(), + ::rtl::OUStringToOString(i_rIdref, RTL_TEXTENCODING_UTF8).getStr()); + + OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), + "TryRegisterMetadatable called for MetadatableUndo?"); + OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), + "TryRegisterMetadatable called for MetadatableClipboard?"); + + if (!isValidXmlId(i_rStreamName, i_rIdref)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + if (i_rObject.IsInContent() + ? !isContentFile(i_rStreamName) + : !isStylesFile(i_rStreamName)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId: wrong stream"), 0, 0); + } + + ::rtl::OUString old_path; + ::rtl::OUString old_idref; + const MetadatableClipboard * pLink; + m_pImpl->LookupXmlId(i_rObject, old_path, old_idref, pLink); + if (old_path == i_rStreamName && old_idref == i_rIdref) + { + return (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject); + } + ClipboardXmlIdMap_t::iterator old_id( m_pImpl->m_XmlIdMap.end() ); + if (!old_idref.equalsAscii("")) + { + old_id = m_pImpl->m_XmlIdMap.find(old_idref); + OSL_ENSURE(old_id != m_pImpl->m_XmlIdMap.end(), "old id not found"); + } + if (m_pImpl->TryInsertMetadatable(i_rObject, i_rStreamName, i_rIdref)) + { + rmIter(m_pImpl->m_XmlIdMap, old_id, old_path, i_rObject); + m_pImpl->m_XmlIdReverseMap[&i_rObject] = + RMapEntry(i_rStreamName, i_rIdref); + return true; + } + else + { + return false; + } +} + +void +XmlIdRegistryClipboard::RegisterMetadatableAndCreateID(Metadatable & i_rObject) +{ + OSL_TRACE("RegisterMetadatableAndCreateID: %p\n", &i_rObject); + + OSL_ENSURE(!dynamic_cast<MetadatableUndo*>(&i_rObject), + "RegisterMetadatableAndCreateID called for MetadatableUndo?"); + OSL_ENSURE(!dynamic_cast<MetadatableClipboard*>(&i_rObject), + "RegisterMetadatableAndCreateID called for MetadatableClipboard?"); + + bool isInContent( i_rObject.IsInContent() ); + ::rtl::OUString stream( ::rtl::OUString::createFromAscii( + isInContent ? s_content : s_styles ) ); + + ::rtl::OUString old_path; + ::rtl::OUString old_idref; + LookupXmlId(i_rObject, old_path, old_idref); + if (!old_idref.equalsAscii("") && + (m_pImpl->LookupElement(old_path, old_idref) == &i_rObject)) + { + return; + } + + // create id + const ::rtl::OUString id( create_id(m_pImpl->m_XmlIdMap) ); + OSL_ENSURE(m_pImpl->m_XmlIdMap.find(id) == m_pImpl->m_XmlIdMap.end(), + "created id is in use"); + m_pImpl->m_XmlIdMap.insert(::std::make_pair(id, isInContent + ? ::std::make_pair( &i_rObject, static_cast<Metadatable*>(0) ) + : ::std::make_pair( static_cast<Metadatable*>(0), &i_rObject ))); + // N.B.: if i_rObject had a latent XmlId, then we implicitly delete the + // MetadatableClipboard and thus the latent XmlId here + m_pImpl->m_XmlIdReverseMap[&i_rObject] = RMapEntry(stream, id); +} + +void XmlIdRegistryClipboard::UnregisterMetadatable(const Metadatable& i_rObject) +{ + OSL_TRACE("UnregisterMetadatable: %p\n", &i_rObject); + + ::rtl::OUString path; + ::rtl::OUString idref; + const MetadatableClipboard * pLink; + if (!m_pImpl->LookupXmlId(i_rObject, path, idref, pLink)) + { + OSL_ENSURE(false, "unregister: no xml id?"); + return; + } + const ClipboardXmlIdMap_t::iterator iter( m_pImpl->m_XmlIdMap.find(idref) ); + if (iter != m_pImpl->m_XmlIdMap.end()) + { + rmIter(m_pImpl->m_XmlIdMap, iter, path, i_rObject); + } +} + + +void XmlIdRegistryClipboard::RemoveXmlIdForElement(const Metadatable& i_rObject) +{ + OSL_TRACE("RemoveXmlIdForElement: %p\n", &i_rObject); + + ClipboardXmlIdReverseMap_t::iterator iter( + m_pImpl->m_XmlIdReverseMap.find(&i_rObject) ); + if (iter != m_pImpl->m_XmlIdReverseMap.end()) + { + OSL_ENSURE(!iter->second.m_XmlId.equalsAscii(""), + "null id in m_XmlIdReverseMap"); + m_pImpl->m_XmlIdReverseMap.erase(iter); + } +} + +// ------------------------------------------------------------------- + +::boost::shared_ptr<MetadatableClipboard> +XmlIdRegistryClipboard::CreateClipboard(const bool i_isInContent) +{ + OSL_TRACE("CreateClipboard: \n"); + + return ::boost::shared_ptr<MetadatableClipboard>( + new MetadatableClipboard(i_isInContent) ); +} + +MetadatableClipboard & +XmlIdRegistryClipboard::RegisterCopyClipboard(Metadatable & i_rCopy, + beans::StringPair const & i_rReference, + const bool i_isLatent) +{ + OSL_TRACE("RegisterCopyClipboard: %p -> "/*"%p"*/"(%s#%s) (%d)\n", + /*&i_rSource,*/ &i_rCopy, + ::rtl::OUStringToOString(i_rReference.First, + RTL_TEXTENCODING_UTF8).getStr(), + ::rtl::OUStringToOString(i_rReference.Second, + RTL_TEXTENCODING_UTF8).getStr(), + i_isLatent); + + // N.B.: when copying to the clipboard, the selection is always inserted + // into the body, even if the source is a header/footer! + // so we do not check whether the stream is right in this function + + if (!isValidXmlId(i_rReference.First, i_rReference.Second)) + { + throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii( + "illegal XmlId"), 0, 0); + } + + if (!i_isLatent) + { + // this should succeed assuming clipboard has a single source document + const bool success( m_pImpl->TryInsertMetadatable(i_rCopy, + i_rReference.First, i_rReference.Second) ); + OSL_ENSURE(success, "RegisterCopyClipboard: TryInsert failed?"); + (void) success; + } + const ::boost::shared_ptr<MetadatableClipboard> pLink( + CreateClipboard( isContentFile(i_rReference.First)) ); + m_pImpl->m_XmlIdReverseMap.insert(::std::make_pair(&i_rCopy, + RMapEntry(i_rReference.First, i_rReference.Second, pLink))); + return *pLink.get(); +} + +MetadatableClipboard const* +XmlIdRegistryClipboard::SourceLink(Metadatable const& i_rObject) +{ + ::rtl::OUString path; + ::rtl::OUString idref; + const MetadatableClipboard * pLink( 0 ); + m_pImpl->LookupXmlId(i_rObject, path, idref, pLink); + return pLink; +} + + +//============================================================================= +// Metadatable mixin + + +Metadatable::~Metadatable() +{ + RemoveMetadataReference(); +} + +void Metadatable::RemoveMetadataReference() +{ + try + { + if (m_pReg) + { + m_pReg->UnregisterMetadatable( *this ); + m_pReg->RemoveXmlIdForElement( *this ); + m_pReg = 0; + } + } + catch (uno::Exception &) + { + OSL_ENSURE(false, "Metadatable::RemoveMetadataReference: exception"); + } +} + +// ::com::sun::star::rdf::XMetadatable: +beans::StringPair +Metadatable::GetMetadataReference() const +{ + if (m_pReg) + { + return m_pReg->GetXmlIdForElement(*this); + } + return beans::StringPair(); +} + +void +Metadatable::SetMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) +{ + if (i_rReference.Second.equalsAscii("")) + { + RemoveMetadataReference(); + } + else + { + ::rtl::OUString streamName( i_rReference.First ); + if (streamName.equalsAscii("")) + { + // handle empty stream name as auto-detect. + // necessary for importing flat file format. + streamName = ::rtl::OUString::createFromAscii( + IsInContent() ? s_content : s_styles ); + } + XmlIdRegistry & rReg( dynamic_cast<XmlIdRegistry&>( GetRegistry() ) ); + if (rReg.TryRegisterMetadatable(*this, streamName, i_rReference.Second)) + { + m_pReg = &rReg; + } + else + { + throw lang::IllegalArgumentException( + ::rtl::OUString::createFromAscii("Metadatable::" + "SetMetadataReference: argument is invalid"), /*this*/0, 0); + } + } +} + +void Metadatable::EnsureMetadataReference() +{ + XmlIdRegistry& rReg( + m_pReg ? *m_pReg : dynamic_cast<XmlIdRegistry&>( GetRegistry() ) ); + rReg.RegisterMetadatableAndCreateID( *this ); + m_pReg = &rReg; +} + +const ::sfx2::IXmlIdRegistry& GetRegistryConst(Metadatable const& i_rObject) +{ + return const_cast< Metadatable& >( i_rObject ).GetRegistry(); +} + +void +Metadatable::RegisterAsCopyOf(Metadatable const & i_rSource, + const bool i_bCopyPrecedesSource) +{ + OSL_ENSURE(typeid(*this) == typeid(i_rSource) + || typeid(i_rSource) == typeid(MetadatableUndo) + || typeid(*this) == typeid(MetadatableUndo) + || typeid(i_rSource) == typeid(MetadatableClipboard) + || typeid(*this) == typeid(MetadatableClipboard), + "RegisterAsCopyOf element with different class?"); + OSL_ENSURE(!this->m_pReg, "RegisterAsCopyOf called on element with XmlId?"); + + if (this->m_pReg) + { + RemoveMetadataReference(); + } + + try + { + if (i_rSource.m_pReg) + { + XmlIdRegistry & rReg( + dynamic_cast<XmlIdRegistry&>( GetRegistry() ) ); + if (i_rSource.m_pReg == &rReg) + { + OSL_ENSURE(!IsInClipboard(), + "RegisterAsCopy: both in clipboard?"); + if (!IsInClipboard()) + { + XmlIdRegistryDocument & rRegDoc( + dynamic_cast<XmlIdRegistryDocument&>( rReg ) ); + rRegDoc.RegisterCopy(i_rSource, *this, + i_bCopyPrecedesSource); + this->m_pReg = &rRegDoc; + } + return; + } + // source is in different document + XmlIdRegistryDocument * pRegDoc( + dynamic_cast<XmlIdRegistryDocument *>(&rReg) ); + XmlIdRegistryClipboard * pRegClp( + dynamic_cast<XmlIdRegistryClipboard*>(&rReg) ); + + if (pRegClp) + { + beans::StringPair SourceRef( + i_rSource.m_pReg->GetXmlIdForElement(i_rSource) ); + bool isLatent( SourceRef.Second.equalsAscii("") ); + XmlIdRegistryDocument * pSourceRegDoc( + dynamic_cast<XmlIdRegistryDocument*>(i_rSource.m_pReg) ); + OSL_ENSURE(pSourceRegDoc, "RegisterAsCopyOf: 2 clipboards?"); + if (!pSourceRegDoc) return; + // this is a copy _to_ the clipboard + if (isLatent) + { + pSourceRegDoc->LookupXmlId(i_rSource, + SourceRef.First, SourceRef.Second); + } + Metadatable & rLink( + pRegClp->RegisterCopyClipboard(*this, SourceRef, isLatent)); + this->m_pReg = pRegClp; + // register as copy in the non-clipboard registry + pSourceRegDoc->RegisterCopy(i_rSource, rLink, + false); // i_bCopyPrecedesSource); + rLink.m_pReg = pSourceRegDoc; + } + else if (pRegDoc) + { + XmlIdRegistryClipboard * pSourceRegClp( + dynamic_cast<XmlIdRegistryClipboard*>(i_rSource.m_pReg) ); + OSL_ENSURE(pSourceRegClp, + "RegisterAsCopyOf: 2 non-clipboards?"); + if (!pSourceRegClp) return; + const MetadatableClipboard * pLink( + pSourceRegClp->SourceLink(i_rSource) ); + // may happen if src got its id via UNO call + if (!pLink) return; + // only register copy if clipboard content is from this SwDoc! + if (pLink && (&GetRegistryConst(*pLink) == pRegDoc)) + { + // this is a copy _from_ the clipboard; check if the + // element is still in the same stream + // N.B.: we check the stream of pLink, not of i_rSource! + bool srcInContent( pLink->IsInContent() ); + bool tgtInContent( this->IsInContent() ); + if (srcInContent == tgtInContent) + { + pRegDoc->RegisterCopy(*pLink, *this, + true); // i_bCopyPrecedesSource); + this->m_pReg = pRegDoc; + } + // otherwise: stream change! do not register! + } + } + else + { + OSL_ENSURE(false, "neither RegDoc nor RegClp cannot happen"); + } +#if 0 + { + //FIXME: do we need this at all??? + XmlIdRegistryDocument & rRegDoc( + dynamic_cast<XmlIdRegistryDocument&>( rReg ) ); + { + if (rRegDoc.TryRegisterMetadatable(*this, SourceRef)) + { + this->m_pReg = &rRegDoc; + } + } + } +#endif + } + } + catch (uno::Exception &) + { + OSL_ENSURE(false, "Metadatable::RegisterAsCopyOf: exception"); + } +} + +::boost::shared_ptr<MetadatableUndo> Metadatable::CreateUndo( + const bool i_isDelete) +{ + OSL_ENSURE(!IsInUndo(), "CreateUndo called for object in undo?"); + OSL_ENSURE(!IsInClipboard(), "CreateUndo called for object in clipboard?"); + try + { + if (!IsInClipboard() && !IsInUndo() && m_pReg) + { + XmlIdRegistryDocument * pRegDoc( + dynamic_cast<XmlIdRegistryDocument*>( m_pReg ) ); + ::boost::shared_ptr<MetadatableUndo> pUndo( + pRegDoc->CreateUndo(*this) ); + pRegDoc->RegisterCopy(*this, *pUndo, false); + pUndo->m_pReg = pRegDoc; + + if (i_isDelete) + { + RemoveMetadataReference(); + } + return pUndo; + } + } + catch (uno::Exception &) + { + OSL_ENSURE(false, "Metadatable::CreateUndo: exception"); + } + return ::boost::shared_ptr<MetadatableUndo>(); +} + +void Metadatable::RestoreMetadata( + ::boost::shared_ptr<MetadatableUndo> const& i_pUndo) +{ + OSL_ENSURE(!IsInUndo(), "RestoreMetadata called for object in undo?"); + OSL_ENSURE(!IsInClipboard(), + "RestoreMetadata called for object in clipboard?"); + if (IsInClipboard() || IsInUndo()) return; + RemoveMetadataReference(); + if (i_pUndo) + { + this->RegisterAsCopyOf(*i_pUndo, true); + } +} + +void +Metadatable::JoinMetadatable(Metadatable const & i_rOther, + const bool i_isMergedEmpty, const bool i_isOtherEmpty) +{ + OSL_ENSURE(!IsInUndo(), "JoinMetadatables called for object in undo?"); + OSL_ENSURE(!IsInClipboard(), + "JoinMetadatables called for object in clipboard?"); + if (IsInClipboard() || IsInUndo()) return; + + if (i_isOtherEmpty && !i_isMergedEmpty) + { + // other is empty, thus loses => nothing to do + return; + } + if (i_isMergedEmpty && !i_isOtherEmpty) + { + this->RemoveMetadataReference(); + this->RegisterAsCopyOf(i_rOther, true); + return; + } + + if (!i_rOther.m_pReg) + { + // other doesn't have xmlid, thus loses => nothing to do + return; + } + if (!m_pReg) + { + this->RegisterAsCopyOf(i_rOther, true); + // assumption: i_rOther will be deleted, so don't unregister it here + return; + } + try + { + XmlIdRegistryDocument * pRegDoc( + dynamic_cast<XmlIdRegistryDocument*>( m_pReg ) ); + OSL_ENSURE(pRegDoc, "JoinMetadatable: no pRegDoc?"); + if (pRegDoc) + { + pRegDoc->JoinMetadatables(*this, i_rOther); + } + } + catch (uno::Exception &) + { + OSL_ENSURE(false, "Metadatable::JoinMetadatable: exception"); + } +} + + +//============================================================================= +// XMetadatable mixin + +// ::com::sun::star::rdf::XNode: +::rtl::OUString SAL_CALL MetadatableMixin::getStringValue() + throw (::com::sun::star::uno::RuntimeException) +{ + return getNamespace() + getLocalName(); +} + +// ::com::sun::star::rdf::XURI: +::rtl::OUString SAL_CALL MetadatableMixin::getLocalName() + throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + beans::StringPair mdref( getMetadataReference() ); + if (!mdref.Second.getLength()) + { + ensureMetadataReference(); // N.B.: side effect! + mdref = getMetadataReference(); + } + ::rtl::OUStringBuffer buf; + buf.append(mdref.First); + buf.append(static_cast<sal_Unicode>('#')); + buf.append(mdref.Second); + return buf.makeStringAndClear(); +} + +::rtl::OUString SAL_CALL MetadatableMixin::getNamespace() + throw (::com::sun::star::uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + const uno::Reference< frame::XModel > xModel( GetModel() ); + const uno::Reference< rdf::XURI > xDMA( xModel, uno::UNO_QUERY_THROW ); + return xDMA->getStringValue(); +} + +// ::com::sun::star::rdf::XMetadatable: +beans::StringPair SAL_CALL +MetadatableMixin::getMetadataReference() +throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + Metadatable* pObject( GetCoreObject() ); + if (pObject) + { + return pObject->GetMetadataReference(); + } + else + { + throw uno::RuntimeException(); + } +} + +void SAL_CALL +MetadatableMixin::setMetadataReference( + const beans::StringPair & i_rReference) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + Metadatable* pObject( GetCoreObject() ); + if (pObject) + { + return pObject->SetMetadataReference(i_rReference); + } + else + { + throw uno::RuntimeException(); + } +} + +void SAL_CALL MetadatableMixin::ensureMetadataReference() +throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + Metadatable* pObject( GetCoreObject() ); + if (pObject) + { + return pObject->EnsureMetadataReference(); + } + else + { + throw uno::RuntimeException(); + } +} + +} // namespace sfx2 + + +//============================================================================= + +#if OSL_DEBUG_LEVEL > 1 + +static ::sfx2::XmlIdRegistryDocument s_Reg; +static ::sfx2::XmlIdRegistryClipboard s_RegClip; + +class MockMetadatable : public ::sfx2::Metadatable +{ +public: + MockMetadatable(bool i_isInClip = false) : + m_bInClipboard(i_isInClip), m_bInUndo(false), m_bInContent(true) {} + bool m_bInClipboard; + bool m_bInUndo; + bool m_bInContent; + virtual bool IsInClipboard() const { return m_bInClipboard; } + virtual bool IsInUndo() const { return m_bInUndo; } + virtual bool IsInContent() const { return m_bInContent; } + virtual ::sfx2::XmlIdRegistry& GetRegistry() { return m_bInClipboard ? static_cast< ::sfx2::XmlIdRegistry&>(s_RegClip) : static_cast< ::sfx2::XmlIdRegistry&>(s_Reg); } + virtual ::com::sun::star::uno::Reference< + ::com::sun::star::rdf::XMetadatable > MakeUnoObject() { return 0; } +}; + +bool operator==(beans::StringPair p1, beans::StringPair p2) +{ + return p1.First == p2.First && p1.Second == p2.Second; +} + +void test() +{ + OSL_TRACE("SwMetadatable test(): start\n"); + MockMetadatable m1; + MockMetadatable m2; + MockMetadatable m3; + MockMetadatable m4; + MockMetadatable m5; + ::rtl::OUString empty; + ::rtl::OUString content( ::rtl::OUString::createFromAscii("content.xml") ); + ::rtl::OUString styles ( ::rtl::OUString::createFromAscii("styles.xml") ); + ::rtl::OUString sid1( ::rtl::OUString::createFromAscii("id1") ); + ::rtl::OUString sid2( ::rtl::OUString::createFromAscii("id2") ); + ::rtl::OUString sid3( ::rtl::OUString::createFromAscii("id3") ); + ::rtl::OUString sid4( ::rtl::OUString::createFromAscii("id4") ); + beans::StringPair id1(content, sid1); + beans::StringPair id2(content, sid2); + beans::StringPair id3(content, sid3); + beans::StringPair id4(styles, sid4); + beans::StringPair id3e(empty, sid3); + beans::StringPair id4e(empty, sid4); + m1.SetMetadataReference(id1); + OSL_ENSURE(m1.GetMetadataReference() == id1, "set failed"); + try { + m2.SetMetadataReference(id1); + OSL_ENSURE(false, "set duplicate succeeded"); + } catch (lang::IllegalArgumentException) { } + m1.SetMetadataReference(id1); + OSL_ENSURE(m1.GetMetadataReference() == id1, "set failed (existing)"); + m1.EnsureMetadataReference(); + OSL_ENSURE(m1.GetMetadataReference() == id1, "ensure failed (existing)"); + + m2.EnsureMetadataReference(); + beans::StringPair m2id(m2.GetMetadataReference()); + OSL_ENSURE(m2id.Second.getLength(), "ensure failed"); + m2.EnsureMetadataReference(); + OSL_ENSURE(m2.GetMetadataReference() == m2id, "ensure failed (idempotent)"); + + m1.m_bInUndo = true; + OSL_ENSURE(!m1.GetMetadataReference().Second.getLength(), "move to undo failed"); + + m1.m_bInUndo = false; + OSL_ENSURE(m1.GetMetadataReference() == id1, "move from undo failed"); + + m1.m_bInUndo = true; + try { + m2.SetMetadataReference(id1); // steal! + } catch (lang::IllegalArgumentException &) { + OSL_ENSURE(false, "set duplicate to undo failed"); + } + m1.m_bInUndo = false; + OSL_ENSURE(!m1.GetMetadataReference().Second.getLength(), "move from undo: duplicate"); + + m3.RegisterAsCopyOf(m2); + OSL_ENSURE(m2.GetMetadataReference() == id1, "copy: source"); + OSL_ENSURE(!m3.GetMetadataReference().Second.getLength(), "copy: duplicate"); + m4.RegisterAsCopyOf(m3); + OSL_ENSURE(m2.GetMetadataReference() == id1, "copy: source"); + OSL_ENSURE(!m3.GetMetadataReference().Second.getLength(), "copy: duplicate"); + OSL_ENSURE(!m4.GetMetadataReference().Second.getLength(), "copy: duplicate"); + m2.m_bInUndo = true; + OSL_ENSURE(m3.GetMetadataReference() == id1, "duplicate to undo"); + OSL_ENSURE(!m2.GetMetadataReference().Second.getLength(), "duplicate to undo"); + m2.m_bInUndo = false; + OSL_ENSURE(m2.GetMetadataReference() == id1, "duplicate from undo"); + OSL_ENSURE(!m3.GetMetadataReference().Second.getLength(), "duplicate from undo"); + + m4.EnsureMetadataReference(); // new! + beans::StringPair m4id(m4.GetMetadataReference()); + OSL_ENSURE(m4id.Second.getLength() && !(m4id == id1), "ensure on duplicate"); + + MockMetadatable mc1(true); // in clipboard + MockMetadatable mc2(true); + MockMetadatable mc3(true); + MockMetadatable mc4(true); + MockMetadatable m2p; + MockMetadatable m3p; + + mc1.SetMetadataReference(id2); + OSL_ENSURE(mc1.GetMetadataReference() == id2, "set failed"); + try { + mc2.SetMetadataReference(id2); + OSL_ENSURE(false, "set duplicate succeeded"); + } catch (lang::IllegalArgumentException) { } + mc1.SetMetadataReference(id2); + OSL_ENSURE(mc1.GetMetadataReference() == id2, "set failed (existing)"); + mc1.EnsureMetadataReference(); + OSL_ENSURE(mc1.GetMetadataReference() == id2, "ensure failed (existing)"); + mc2.EnsureMetadataReference(); + beans::StringPair mc2id(mc2.GetMetadataReference()); + OSL_ENSURE(mc2id.Second.getLength(), "ensure failed"); + mc2.EnsureMetadataReference(); + OSL_ENSURE(mc2.GetMetadataReference() == mc2id, "ensure failed (idempotent)"); + mc2.RemoveMetadataReference(); + OSL_ENSURE(!mc2.GetMetadataReference().Second.getLength(), "remove failed"); + + // set up mc2 as copy of m2 and mc3 as copy of m3 + mc3.RegisterAsCopyOf(m3); + OSL_ENSURE(!mc3.GetMetadataReference().Second.getLength() , "copy to clipboard (latent)"); + mc2.RegisterAsCopyOf(m2); + OSL_ENSURE(mc2.GetMetadataReference() == id1, "copy to clipboard (non-latent)"); + // paste mc2 to m2p and mc3 to m3p + m2p.RegisterAsCopyOf(mc2); + OSL_ENSURE(!m2p.GetMetadataReference().Second.getLength() , "paste from clipboard (non-latent)"); + m3p.RegisterAsCopyOf(mc3); + OSL_ENSURE(!m3p.GetMetadataReference().Second.getLength() , "paste from clipboard (latent)"); + // delete m2, m2p, m3 + m2.RemoveMetadataReference(); + OSL_ENSURE(!m2.GetMetadataReference().Second.getLength(), "remove failed"); + OSL_ENSURE(m2p.GetMetadataReference() == id1, "paste-remove (non-latent)"); + m2p.RemoveMetadataReference(); + OSL_ENSURE(!m2p.GetMetadataReference().Second.getLength(), "remove failed"); + OSL_ENSURE(m3.GetMetadataReference() == id1, "paste-remove2 (non-latent)"); + m3.RemoveMetadataReference(); + OSL_ENSURE(!m3.GetMetadataReference().Second.getLength(), "remove failed"); + OSL_ENSURE(m3p.GetMetadataReference() == id1, "paste-remove (latent)"); + // delete mc2 + mc2.SetMetadataReference(beans::StringPair()); + OSL_ENSURE(!mc3.GetMetadataReference().Second.getLength() , "in clipboard becomes non-latent"); + // paste mc2 + m2p.RegisterAsCopyOf(mc2); + OSL_ENSURE(!m2p.GetMetadataReference().Second.getLength(), "remove-paste"); + OSL_ENSURE(m3p.GetMetadataReference() == id1, "remove-paste (stolen)"); + + // auto-detect stream + m5.SetMetadataReference(id3e); + OSL_ENSURE(m5.GetMetadataReference() == id3, "auto-detect (content)"); + m5.m_bInContent = false; + m5.SetMetadataReference(id4e); + OSL_ENSURE(m5.GetMetadataReference() == id4, "auto-detect (styles)"); + + OSL_TRACE("sfx2::Metadatable test(): finished\n"); +} + +struct Test { Test() { test(); } }; +static Test s_test; + + +#include <stdio.h> + +static void dump(sfx2::XmlIdList_t * pList) +#ifdef GCC +__attribute__ ((unused)) +#endif +; +static void dump(sfx2::XmlIdList_t * pList) +{ + fprintf(stderr, "\nXmlIdList(%p): ", pList); + for (sfx2::XmlIdList_t::iterator i = pList->begin(); i != pList->end(); ++i) + { + fprintf(stderr, "%p ", *i); + } + fprintf(stderr, "\n"); +} + +#endif + diff --git a/sfx2/source/doc/docfile.cxx b/sfx2/source/doc/docfile.cxx index 79197b6e5f52..23093bfa066f 100644 --- a/sfx2/source/doc/docfile.cxx +++ b/sfx2/source/doc/docfile.cxx @@ -568,7 +568,7 @@ long SfxMedium::GetFileVersion() const //------------------------------------------------------------------ void SfxMedium::CheckFileDate( const util::DateTime& aInitDate ) { - GetInitFileDate(); + GetInitFileDate( sal_True ); if ( pImp->m_aDateTime.Seconds != aInitDate.Seconds || pImp->m_aDateTime.Minutes != aInitDate.Minutes || pImp->m_aDateTime.Hours != aInitDate.Hours @@ -576,40 +576,43 @@ void SfxMedium::CheckFileDate( const util::DateTime& aInitDate ) || pImp->m_aDateTime.Month != aInitDate.Month || pImp->m_aDateTime.Year != aInitDate.Year ) { - if ( !IsSystemFileLockingUsed() ) - { - uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler(); + uno::Reference< task::XInteractionHandler > xHandler = GetInteractionHandler(); - if ( xHandler.is() ) + if ( xHandler.is() ) + { + try { - try - { - ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny( - document::ChangedByOthersRequest() ) ); - uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 ); - aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() ); - aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() ); - xInteractionRequestImpl->setContinuations( aContinuations ); + ::rtl::Reference< ::ucbhelper::InteractionRequest > xInteractionRequestImpl = new ::ucbhelper::InteractionRequest( uno::makeAny( + document::ChangedByOthersRequest() ) ); + uno::Sequence< uno::Reference< task::XInteractionContinuation > > aContinuations( 3 ); + aContinuations[0] = new ::ucbhelper::InteractionAbort( xInteractionRequestImpl.get() ); + aContinuations[1] = new ::ucbhelper::InteractionApprove( xInteractionRequestImpl.get() ); + xInteractionRequestImpl->setContinuations( aContinuations ); - xHandler->handle( xInteractionRequestImpl.get() ); + xHandler->handle( xInteractionRequestImpl.get() ); - ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection(); - if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() ) - { - SetError( ERRCODE_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); - } + ::rtl::Reference< ::ucbhelper::InteractionContinuation > xSelected = xInteractionRequestImpl->getSelection(); + if ( uno::Reference< task::XInteractionAbort >( xSelected.get(), uno::UNO_QUERY ).is() ) + { + SetError( ERRCODE_ABORT, ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ) ); } - catch ( uno::Exception& ) - {} } + catch ( uno::Exception& ) + {} } } } //------------------------------------------------------------------ -util::DateTime SfxMedium::GetInitFileDate() +sal_Bool SfxMedium::DocNeedsFileDateCheck() +{ + return ( !IsReadOnly() && ::utl::LocalFileHelper::IsLocalFile( GetURLObject().GetMainURL( INetURLObject::NO_DECODE ) ) ); +} + +//------------------------------------------------------------------ +util::DateTime SfxMedium::GetInitFileDate( sal_Bool bIgnoreOldValue ) { - if ( !pImp->m_bGotDateTime && GetContent().is() ) + if ( ( bIgnoreOldValue || !pImp->m_bGotDateTime ) && GetContent().is() ) { try { @@ -866,11 +869,8 @@ sal_Bool SfxMedium::Commit() sal_Bool bResult = ( GetError() == SVSTREAM_OK ); - if ( bResult ) - { - pImp->m_bGotDateTime = sal_False; - GetInitFileDate(); - } + if ( bResult && DocNeedsFileDateCheck() ) + GetInitFileDate( sal_True ); // remove truncation mode from the flags nStorOpenMode &= (~STREAM_TRUNC); @@ -1400,6 +1400,10 @@ sal_Bool SfxMedium::LockOrigFileOnDemand( sal_Bool bLoading, sal_Bool bNoUI ) GetItemSet()->Put( SfxBoolItem( SID_DOC_READONLY, sal_True ) ); } + // when the file is locked, get the current file date + if ( bResult && DocNeedsFileDateCheck() ) + GetInitFileDate( sal_True ); + return bResult; } @@ -2662,8 +2666,6 @@ void SfxMedium::GetMedium_Impl() pInStream = utl::UcbStreamHelper::CreateStream( pImp->xInputStream ); } - GetInitFileDate(); - pImp->bDownloadDone = sal_True; pImp->aDoneLink.ClearPendingCall(); pImp->aDoneLink.Call( (void*) GetError() ); @@ -3305,6 +3307,7 @@ SfxMedium::SfxMedium( const ::com::sun::star::uno::Sequence< ::com::sun::star::b // that must be copied here SFX_ITEMSET_ARG( pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, FALSE ); + if (!pFileNameItem) throw uno::RuntimeException(); ::rtl::OUString aNewTempFileURL = SfxMedium::CreateTempCopyWithExt( pFileNameItem->GetValue() ); if ( aNewTempFileURL.getLength() ) { @@ -3326,6 +3329,7 @@ SfxMedium::SfxMedium( const ::com::sun::star::uno::Sequence< ::com::sun::star::b bReadOnly = TRUE; SFX_ITEMSET_ARG( pSet, pFileNameItem, SfxStringItem, SID_FILE_NAME, FALSE ); + if (!pFileNameItem) throw uno::RuntimeException(); aLogicName = pFileNameItem->GetValue(); nStorOpenMode = bReadOnly ? SFX_STREAM_READONLY : SFX_STREAM_READWRITE; bDirect = FALSE; diff --git a/sfx2/source/doc/docinsert.cxx b/sfx2/source/doc/docinsert.cxx index 8fae29a1847c..ecd9ae7aee42 100644 --- a/sfx2/source/doc/docinsert.cxx +++ b/sfx2/source/doc/docinsert.cxx @@ -177,33 +177,17 @@ void impl_FillURLList( sfx2::FileDialogHelper* _pFileDlg, SvStringsDtor*& _rpURL { DBG_ASSERT( _pFileDlg, "DocumentInserter::fillURLList(): invalid file dialog" ); DBG_ASSERT( !_rpURLList, "DocumentInserter::fillURLList(): URLList already exists" ); - Sequence < ::rtl::OUString > aPathSeq = _pFileDlg->GetMPath(); + Sequence < ::rtl::OUString > aPathSeq = _pFileDlg->GetSelectedFiles(); if ( aPathSeq.getLength() ) { _rpURLList = new SvStringsDtor; - if ( aPathSeq.getLength() == 1 ) + for ( USHORT i = 0; i < aPathSeq.getLength(); ++i ) { - ::rtl::OUString sFileURL( aPathSeq[0] ); - String* pURL = new String( sFileURL ); - _rpURLList->Insert( pURL, 0 ); - } - else - { - INetURLObject aPathObj( aPathSeq[0] ); - aPathObj.setFinalSlash(); - - for ( USHORT i = 1; i < aPathSeq.getLength(); ++i ) - { - if ( i == 1 ) - aPathObj.Append( aPathSeq[i] ); - else - aPathObj.setName( aPathSeq[i] ); - - String* pURL = new String( aPathObj.GetMainURL( INetURLObject::NO_DECODE ) ); - _rpURLList->Insert( pURL, _rpURLList->Count() ); - } + INetURLObject aPathObj( aPathSeq[i] ); + String* pURL = new String( aPathObj.GetMainURL( INetURLObject::NO_DECODE ) ); + _rpURLList->Insert( pURL, _rpURLList->Count() ); } } } diff --git a/sfx2/source/doc/doctemplates.cxx b/sfx2/source/doc/doctemplates.cxx index 731c04c1086d..7df93afaa63e 100644 --- a/sfx2/source/doc/doctemplates.cxx +++ b/sfx2/source/doc/doctemplates.cxx @@ -2064,7 +2064,7 @@ sal_Bool SfxDocTplService_Impl::addTemplate( const OUString& rGroupName, Content aResultContent; if ( Content::create( aNewTemplateTargetURL, xEnv, aResultContent ) ) { - ::rtl::OUString aPropertyName( RTL_CONSTASCII_USTRINGPARAM( "IsReadonly" ) ); + ::rtl::OUString aPropertyName( RTL_CONSTASCII_USTRINGPARAM( "IsReadOnly" ) ); uno::Any aProperty; sal_Bool bReadOnly = sal_False; if ( getProperty( aResultContent, aPropertyName, aProperty ) && ( aProperty >>= bReadOnly ) && bReadOnly ) diff --git a/sfx2/source/doc/makefile.mk b/sfx2/source/doc/makefile.mk index b46ee5aa30e8..4c893288ebb8 100644 --- a/sfx2/source/doc/makefile.mk +++ b/sfx2/source/doc/makefile.mk @@ -40,6 +40,10 @@ ENABLE_EXCEPTIONS=TRUE .INCLUDE : settings.mk .INCLUDE : $(PRJ)$/util$/makefile.pmk +.IF "$(SYSTEM_LIBXML)" == "YES" +CFLAGS+=-DSYSTEM_LIBXML $(LIBXML_CFLAGS) +.ENDIF + # --- Files -------------------------------------------------------- SRS1NAME=$(TARGET) @@ -80,10 +84,13 @@ SLOFILES = \ $(SLO)$/docinsert.obj \ $(SLO)$/docmacromode.obj \ $(SLO)$/SfxDocumentMetaData.obj \ + $(SLO)$/DocumentMetadataAccess.obj \ + $(SLO)$/Metadatable.obj \ $(SLO)$/sfxmodelfactory.obj \ $(SLO)$/docstoragemodifylistener.obj \ $(SLO)$/querytemplate.obj + # --- Tagets ------------------------------------------------------- .INCLUDE : target.mk diff --git a/sfx2/source/doc/objmisc.cxx b/sfx2/source/doc/objmisc.cxx index 8e1c618f65cd..a7910c463cf9 100644 --- a/sfx2/source/doc/objmisc.cxx +++ b/sfx2/source/doc/objmisc.cxx @@ -84,6 +84,7 @@ #include <comphelper/processfactory.hxx> #include <comphelper/componentcontext.hxx> +#include <comphelper/configurationhelper.hxx> #include <com/sun/star/security/XDocumentDigitalSignatures.hpp> #include <com/sun/star/frame/XModel.hpp> @@ -2251,6 +2252,33 @@ sal_Bool SfxObjectShell::UseInteractionToHandleError( return bResult; } +sal_Bool SfxObjectShell_Impl::NeedsOfficeUpdateDialog() +{ + // if the configuration is not available for any reason, the default behavior is to show the message + sal_Bool bResult = sal_True; + + try + { + uno::Reference< lang::XMultiServiceFactory > xServiceManager( ::comphelper::getProcessServiceFactory(), uno::UNO_SET_THROW ); + uno::Reference< uno::XInterface > xCommonConfig( + ::comphelper::ConfigurationHelper::openConfig( + xServiceManager, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common" ) ), + ::comphelper::ConfigurationHelper::E_STANDARD ), + uno::UNO_SET_THROW ); + + ::comphelper::ConfigurationHelper::readRelativeKey( + xCommonConfig, + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Load/" ) ), + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ShowOfficeUpdateDialog" ) ) ) >>= bResult; + } + catch( uno::Exception& ) + { + } + + return bResult; +} + sal_Int16 SfxObjectShell_Impl::getCurrentMacroExecMode() const { sal_Int16 nImposedExecMode( MacroExecMode::NEVER_EXECUTE ); diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx index 3571c4226ff7..a47fc1bf4747 100644 --- a/sfx2/source/doc/objserv.cxx +++ b/sfx2/source/doc/objserv.cxx @@ -415,7 +415,7 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq) if ( pDocInfItem ) { // parameter, e.g. from replayed macro - pDocInfItem->updateDocumentInfo(getDocProperties()); + pDocInfItem->UpdateDocumentInfo(getDocProperties(), true); SetUseUserData( pDocInfItem->IsUseUserData() ); } else @@ -478,7 +478,7 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq) if ( pDocInfoItem ) { // user has done some changes to DocumentInfo - pDocInfoItem->updateDocumentInfo(getDocProperties()); + pDocInfoItem->UpdateDocumentInfo(getDocProperties()); SetUseUserData( ((const SfxDocumentInfoItem *)pDocInfoItem)->IsUseUserData() ); // add data from dialog for possible recording purposes diff --git a/sfx2/source/doc/objstor.cxx b/sfx2/source/doc/objstor.cxx index 76e6bb59e189..89f2fe74e2f9 100644 --- a/sfx2/source/doc/objstor.cxx +++ b/sfx2/source/doc/objstor.cxx @@ -621,6 +621,7 @@ sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed ) else aBaseURL = pMed->GetBaseURL(); } + pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, aBaseURL ) ); pImp->nLoadedFlags = 0; pImp->bModelInitialized = sal_False; @@ -827,37 +828,28 @@ sal_Bool SfxObjectShell::DoLoad( SfxMedium *pMed ) } } - uno::Reference< XInteractionHandler > xHandler( pMedium->GetInteractionHandler() ); - if ( xHandler.is() && !SFX_APP()->Get_Impl()->bODFVersionWarningLater ) + if ( pMedium->HasStorage_Impl() ) { - // scan the generator string (within meta.xml) - uno::Reference<document::XDocumentPropertiesSupplier> xDPS( - GetModel(), uno::UNO_QUERY_THROW); - uno::Reference<document::XDocumentProperties> xDocProps - = xDPS->getDocumentProperties(); - if ( xDocProps.is() ) + uno::Reference< XInteractionHandler > xHandler( pMedium->GetInteractionHandler() ); + if ( xHandler.is() && !SFX_APP()->Get_Impl()->bODFVersionWarningLater ) { - uno::Reference<beans::XPropertySet> xUserDefinedProps( - xDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); - uno::Any aAny; + uno::Reference<beans::XPropertySet> xStorageProps( pMedium->GetStorage(), uno::UNO_QUERY_THROW ); + ::rtl::OUString sVersion; try { - aAny = xUserDefinedProps->getPropertyValue( - DEFINE_CONST_UNICODE("ODFVersion")); + xStorageProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ) ) >>= sVersion; } catch( const uno::Exception& ) { // Custom Property "ODFVersion" does not exist } - ::rtl::OUString sVersion; - if ( (aAny >>= sVersion) && sVersion.getLength() ) + if ( sVersion.getLength() ) { double nVersion = sVersion.toDouble(); - if ( nVersion > 1.20001 ) + if ( nVersion > 1.20001 && SfxObjectShell_Impl::NeedsOfficeUpdateDialog() ) // ODF version greater than 1.2 - added some decimal places to be safe against floating point conversion errors (hack) { - ::rtl::OUString sDocumentURL( pMedium->GetOrigURL() ); ::rtl::OUString aSystemFileURL; if ( osl::FileBase::getSystemPathFromFileURL( sDocumentURL, aSystemFileURL ) == osl::FileBase::E_None ) @@ -1138,7 +1130,12 @@ sal_Bool SfxObjectShell::SaveTo_Impl */ { - RTL_LOGFILE_CONTEXT( aLog, "sfx2 (mv76033) SfxObjectShell::SaveTo_Impl" ); + RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::SaveTo_Impl" ); + if( RTL_LOGFILE_HASLOGFILE() ) + { + ByteString aString( rMedium.GetName(), RTL_TEXTENCODING_ASCII_US ); + RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1( aLog, "saving \"%s\"", aString.GetBuffer() ); + } AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Begin" ) ) ); @@ -1227,7 +1224,8 @@ sal_Bool SfxObjectShell::SaveTo_Impl bStoreToSameLocation = sal_True; AddLog( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Save" ) ) ); - rMedium.CheckFileDate( pMedium->GetInitFileDate() ); + if ( pMedium->DocNeedsFileDateCheck() ) + rMedium.CheckFileDate( pMedium->GetInitFileDate( sal_False ) ); if ( bCopyTo && GetCreateMode() != SFX_CREATE_MODE_EMBEDDED ) { @@ -2083,10 +2081,17 @@ sal_Bool SfxObjectShell::DoSaveCompleted( SfxMedium* pNewMed ) InvalidateName(); SetModified(sal_False); // nur bei gesetztem Medium zur"ucksetzen Broadcast( SfxSimpleHint(SFX_HINT_MODECHANGED) ); + + // this is the end of the saving process, it is possible that the file was changed + // between medium commit and this step ( attributes change and so on ) + // so get the file date again + if ( pNewMed->DocNeedsFileDateCheck() ) + pNewMed->GetInitFileDate( sal_True ); } } pMedium->ClearBackup_Impl(); + pMedium->LockOrigFileOnDemand( sal_True, sal_False ); return bOk; } @@ -3106,6 +3111,13 @@ void SfxObjectShell::SetSecurityOptOpenReadOnly( sal_Bool _b ) sal_Bool SfxObjectShell::LoadOwnFormat( SfxMedium& rMedium ) { + RTL_LOGFILE_PRODUCT_CONTEXT( aLog, "PERFORMANCE SfxObjectShell::LoadOwnFormat" ); + if( RTL_LOGFILE_HASLOGFILE() ) + { + ByteString aString( rMedium.GetName(), RTL_TEXTENCODING_ASCII_US ); + RTL_LOGFILE_PRODUCT_CONTEXT_TRACE1( aLog, "loading \"%s\"", aString.GetBuffer() ); + } + uno::Reference< embed::XStorage > xStorage = rMedium.GetStorage(); if ( xStorage.is() ) { diff --git a/sfx2/source/doc/objxtor.cxx b/sfx2/source/doc/objxtor.cxx index d91ec392aa92..3edf1ddb60d7 100644 --- a/sfx2/source/doc/objxtor.cxx +++ b/sfx2/source/doc/objxtor.cxx @@ -722,11 +722,11 @@ namespace { static BasicManager* lcl_getBasicManagerForDocument( const SfxObjectShell& _rDocument ) { - if ( !_rDocument.pImp->m_bNoBasicCapabilities ) + if ( !_rDocument.Get_Impl()->m_bNoBasicCapabilities ) { - if ( !_rDocument.pImp->bBasicInitialized ) + if ( !_rDocument.Get_Impl()->bBasicInitialized ) const_cast< SfxObjectShell& >( _rDocument ).InitBasicManager_Impl(); - return _rDocument.pImp->pBasicManager->get(); + return _rDocument.Get_Impl()->pBasicManager->get(); } // assume we do not have Basic ourself, but we can refer to another @@ -794,9 +794,13 @@ namespace try { Reference< XStorageBasedDocument > xStorageDoc( _rxDocument, UNO_QUERY ); + const Reference< XComponentContext > xContext( + ::comphelper::getProcessComponentContext() ); _rxContainer.set ( _bScript - ? DocumentScriptLibraryContainer::create( comphelper_getProcessComponentContext(), xStorageDoc ) - : DocumentDialogLibraryContainer::create( comphelper_getProcessComponentContext(), xStorageDoc ) + ? DocumentScriptLibraryContainer::create( + xContext, xStorageDoc ) + : DocumentDialogLibraryContainer::create( + xContext, xStorageDoc ) , UNO_QUERY_THROW ); } catch( const Exception& ) @@ -1065,6 +1069,12 @@ void SfxObjectShell::SetAutoStyleFilterIndex(sal_uInt16 nSet) pImp->nStyleFilter = nSet; } +sal_uInt16 SfxObjectShell::GetAutoStyleFilterIndex() +{ + return pImp->nStyleFilter; +} + + void SfxObjectShell::SetCurrentComponent( const Reference< XInterface >& _rxComponent ) { if ( _rxComponent.get() == s_xCurrentComponent.get().get() ) diff --git a/sfx2/source/doc/sfxbasemodel.cxx b/sfx2/source/doc/sfxbasemodel.cxx index 43ce1593bbaf..53673b505d6d 100644 --- a/sfx2/source/doc/sfxbasemodel.cxx +++ b/sfx2/source/doc/sfxbasemodel.cxx @@ -66,6 +66,7 @@ #include <com/sun/star/embed/ElementModes.hpp> #include <com/sun/star/embed/Aspects.hpp> #include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/frame/XTransientDocumentsDocumentContentFactory.hpp> #include <comphelper/enumhelper.hxx> // can be removed when this is a "real" service #include <cppuhelper/interfacecontainer.hxx> @@ -124,6 +125,8 @@ #include "brokenpackageint.hxx" #include "graphhelp.hxx" #include <sfx2/msgpool.hxx> +#include <sfx2/DocumentMetadataAccess.hxx> + #include <sfxresid.hxx> //________________________________________________________________________________________________________ @@ -135,13 +138,14 @@ static const ::rtl::OUString SERVICENAME_DESKTOP = ::rtl::OUString::createFromAs //________________________________________________________________________________________________________ namespace css = ::com::sun::star; -using namespace com::sun::star; +using namespace ::com::sun::star; using namespace ::com::sun::star::uno; //________________________________________________________________________________________________________ // impl. declarations //________________________________________________________________________________________________________ + struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument { // counter for SfxBaseModel instances created. @@ -172,6 +176,8 @@ struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument ::rtl::OUString m_sModuleIdentifier; css::uno::Reference< css::frame::XTitle > m_xTitleHelper; css::uno::Reference< css::frame::XUntitledNumbers > m_xNumberedControllers; + uno::Reference< rdf::XDocumentMetadataAccess> m_xDocumentMetadata; + IMPL_SfxBaseModel_DataContainer( ::osl::Mutex& rMutex, SfxObjectShell* pObjectShell ) : m_pObjectShell ( pObjectShell ) @@ -184,6 +190,7 @@ struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument , m_pStorageModifyListen ( NULL ) , m_xTitleHelper () , m_xNumberedControllers () + , m_xDocumentMetadata () // lazy { // increase global instance counter. ++g_nInstanceCounter; @@ -201,6 +208,58 @@ struct IMPL_SfxBaseModel_DataContainer : public ::sfx2::IModifiableDocument if ( m_pObjectShell.Is() && !m_pObjectShell->IsModified() ) m_pObjectShell->SetModified( sal_True ); } + + uno::Reference<rdf::XDocumentMetadataAccess> GetDMA() + { + if (!m_xDocumentMetadata.is()) + { + OSL_ENSURE(m_pObjectShell, "GetDMA: no object shell?"); + if (!m_pObjectShell) + { + return 0; + } + + const uno::Reference<uno::XComponentContext> xContext( + ::comphelper::getProcessComponentContext()); + ::rtl::OUString uri; + const uno::Reference<frame::XModel> xModel( + m_pObjectShell->GetModel()); + const uno::Reference<lang::XMultiComponentFactory> xMsf( + xContext->getServiceManager()); + const uno::Reference<frame:: + XTransientDocumentsDocumentContentFactory> xTDDCF( + xMsf->createInstanceWithContext( + ::rtl::OUString::createFromAscii( "com.sun.star.frame." + "TransientDocumentsDocumentContentFactory"), + xContext), + uno::UNO_QUERY_THROW); + const uno::Reference<ucb::XContent> xContent( + xTDDCF->createDocumentContent(xModel) ); + OSL_ENSURE(xContent.is(), "GetDMA: cannot create DocumentContent"); + if (!xContent.is()) + { + return 0; + } + uri = xContent->getIdentifier()->getContentIdentifier(); + OSL_ENSURE(uri.getLength(), "GetDMA: empty uri?"); + if (uri.getLength() && !uri.endsWithAsciiL("/", 1)) + { + uri = uri + ::rtl::OUString::createFromAscii("/"); + } + + m_xDocumentMetadata = new ::sfx2::DocumentMetadataAccess( + xContext, *m_pObjectShell, uri); + } + return m_xDocumentMetadata; + } + + uno::Reference<rdf::XDocumentMetadataAccess> CreateDMAUninitialized() + { + return (m_pObjectShell) + ? new ::sfx2::DocumentMetadataAccess( + ::comphelper::getProcessComponentContext(), *m_pObjectShell) + : 0; + } }; // static member initialization. @@ -417,9 +476,9 @@ SfxSaveGuard::~SfxSaveGuard() //________________________________________________________________________________________________________ DBG_NAME(sfx2_SfxBaseModel) SfxBaseModel::SfxBaseModel( SfxObjectShell *pObjectShell ) -: IMPL_SfxBaseModel_MutexContainer() +: BaseMutex() , m_pData( new IMPL_SfxBaseModel_DataContainer( m_aMutex, pObjectShell ) ) -, m_bSupportEmbeddedScripts( pObjectShell && pObjectShell->pImp ? !pObjectShell->pImp->m_bNoBasicCapabilities : false ) +, m_bSupportEmbeddedScripts( pObjectShell && pObjectShell->Get_Impl() ? !pObjectShell->Get_Impl()->m_bNoBasicCapabilities : false ) { DBG_CTOR(sfx2_SfxBaseModel,NULL); if ( pObjectShell != NULL ) @@ -686,10 +745,9 @@ void SAL_CALL SfxBaseModel::dispose() throw(::com::sun::star::uno::RuntimeExcept m_pData->m_xDocumentInfo = 0; } - if ( m_pData->m_xDocumentProperties.is() ) - { - m_pData->m_xDocumentProperties = 0; - } + m_pData->m_xDocumentProperties.clear(); + + m_pData->m_xDocumentMetadata.clear(); EndListening( *m_pData->m_pObjectShell ); @@ -3829,3 +3887,325 @@ css::uno::Reference< css::frame::XController2 > SAL_CALL SfxBaseModel::createVie { return css::uno::Reference< css::frame::XController2 >(); } + +//============================================================================= +// RDF DocumentMetadataAccess + +// ::com::sun::star::rdf::XRepositorySupplier: +uno::Reference< rdf::XRepository > SAL_CALL +SfxBaseModel::getRDFRepository() throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getRDFRepository(); +} + +// ::com::sun::star::rdf::XNode: +::rtl::OUString SAL_CALL +SfxBaseModel::getStringValue() throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getStringValue(); +} + +// ::com::sun::star::rdf::XURI: +::rtl::OUString SAL_CALL +SfxBaseModel::getNamespace() throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getNamespace(); +} + +::rtl::OUString SAL_CALL +SfxBaseModel::getLocalName() throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getLocalName(); +} + +// ::com::sun::star::rdf::XDocumentMetadataAccess: +uno::Reference< rdf::XMetadatable > SAL_CALL +SfxBaseModel::getElementByMetadataReference( + const ::com::sun::star::beans::StringPair & i_rReference) +throw (uno::RuntimeException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getElementByMetadataReference(i_rReference); +} + +uno::Reference< rdf::XMetadatable > SAL_CALL +SfxBaseModel::getElementByURI(const uno::Reference< rdf::XURI > & i_xURI) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getElementByURI(i_xURI); +} + +uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL +SfxBaseModel::getMetadataGraphsWithType( + const uno::Reference<rdf::XURI> & i_xType) +throw (uno::RuntimeException, lang::IllegalArgumentException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->getMetadataGraphsWithType(i_xType); +} + +uno::Reference<rdf::XURI> SAL_CALL +SfxBaseModel::addMetadataFile(const ::rtl::OUString & i_rFileName, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::ElementExistException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->addMetadataFile(i_rFileName, i_rTypes); +} + +uno::Reference<rdf::XURI> SAL_CALL +SfxBaseModel::importMetadataFile(::sal_Int16 i_Format, + const uno::Reference< io::XInputStream > & i_xInStream, + const ::rtl::OUString & i_rFileName, + const uno::Reference< rdf::XURI > & i_xBaseURI, + const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes) +throw (uno::RuntimeException, lang::IllegalArgumentException, + datatransfer::UnsupportedFlavorException, + container::ElementExistException, rdf::ParseException, io::IOException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->importMetadataFile(i_Format, + i_xInStream, i_rFileName, i_xBaseURI, i_rTypes); +} + +void SAL_CALL +SfxBaseModel::removeMetadataFile( + const uno::Reference< rdf::XURI > & i_xGraphName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::NoSuchElementException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->removeMetadataFile(i_xGraphName); +} + +void SAL_CALL +SfxBaseModel::addContentOrStylesFile(const ::rtl::OUString & i_rFileName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::ElementExistException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->addContentOrStylesFile(i_rFileName); +} + +void SAL_CALL +SfxBaseModel::removeContentOrStylesFile(const ::rtl::OUString & i_rFileName) +throw (uno::RuntimeException, lang::IllegalArgumentException, + container::NoSuchElementException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->removeContentOrStylesFile(i_rFileName); +} + +void SAL_CALL +SfxBaseModel::loadMetadataFromStorage( + uno::Reference< embed::XStorage > const & i_xStorage, + uno::Reference<rdf::XURI> const & i_xBaseURI, + uno::Reference<task::XInteractionHandler> const & i_xHandler) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA( + m_pData->CreateDMAUninitialized()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + try { + xDMA->loadMetadataFromStorage(i_xStorage, i_xBaseURI, i_xHandler); + } catch (lang::IllegalArgumentException &) { + throw; // not initialized + } catch (uno::Exception &) { + // UGLY: if it's a RuntimeException, we can't be sure DMA is initialzed + m_pData->m_xDocumentMetadata = xDMA; + throw; + } + m_pData->m_xDocumentMetadata = xDMA; + +} + +void SAL_CALL +SfxBaseModel::storeMetadataToStorage( + uno::Reference< embed::XStorage > const & i_xStorage) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->storeMetadataToStorage(i_xStorage); +} + +void SAL_CALL +SfxBaseModel::loadMetadataFromMedium( + const uno::Sequence< beans::PropertyValue > & i_rMedium) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA( + m_pData->CreateDMAUninitialized()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + try { + xDMA->loadMetadataFromMedium(i_rMedium); + } catch (lang::IllegalArgumentException &) { + throw; // not initialized + } catch (uno::Exception &) { + // UGLY: if it's a RuntimeException, we can't be sure DMA is initialzed + m_pData->m_xDocumentMetadata = xDMA; + throw; + } + m_pData->m_xDocumentMetadata = xDMA; +} + +void SAL_CALL +SfxBaseModel::storeMetadataToMedium( + const uno::Sequence< beans::PropertyValue > & i_rMedium) +throw (uno::RuntimeException, lang::IllegalArgumentException, + lang::WrappedTargetException) +{ + ::vos::OGuard aGuard( Application::GetSolarMutex() ); + if ( impl_isDisposed() ) + throw lang::DisposedException(); + + const uno::Reference<rdf::XDocumentMetadataAccess> xDMA(m_pData->GetDMA()); + if (!xDMA.is()) { + throw uno::RuntimeException( ::rtl::OUString::createFromAscii( + "model has no document metadata"), *this ); + } + + return xDMA->storeMetadataToMedium(i_rMedium); +} + diff --git a/sfx2/source/inc/objshimp.hxx b/sfx2/source/inc/objshimp.hxx index fc0440535a47..eb8719435406 100644 --- a/sfx2/source/inc/objshimp.hxx +++ b/sfx2/source/inc/objshimp.hxx @@ -174,6 +174,8 @@ struct SfxObjectShell_Impl : public ::sfx2::IMacroDocumentAccess SfxObjectShell_Impl( SfxObjectShell& _rDocShell ); virtual ~SfxObjectShell_Impl(); + static sal_Bool NeedsOfficeUpdateDialog(); + // IMacroDocumentAccess overridables virtual sal_Int16 getCurrentMacroExecMode() const; virtual sal_Bool setCurrentMacroExecMode( sal_uInt16 nMacroMode ); diff --git a/sfx2/source/toolbox/tbxitem.cxx b/sfx2/source/toolbox/tbxitem.cxx index c72989339a34..6a776f6a211e 100644 --- a/sfx2/source/toolbox/tbxitem.cxx +++ b/sfx2/source/toolbox/tbxitem.cxx @@ -1029,6 +1029,25 @@ void SfxToolBoxControl::Select( USHORT nModifier ) void SfxToolBoxControl::Select( BOOL /*bMod1*/ ) { + if(::comphelper::UiEventsLogger::isEnabled()) //#i88653# #i102805# + { + ::rtl::OUString sAppName; + try + { + static ::rtl::OUString our_aModuleManagerName = ::rtl::OUString::createFromAscii("com.sun.star.frame.ModuleManager"); + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceManager = + ::comphelper::getProcessServiceFactory(); + ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModuleManager > xModuleManager( + xServiceManager->createInstance(our_aModuleManagerName) + , ::com::sun::star::uno::UNO_QUERY_THROW); + sAppName = xModuleManager->identify(m_xFrame); + } catch(::com::sun::star::uno::Exception&) {} + Sequence<PropertyValue> vSource; + ::comphelper::UiEventsLogger::appendDispatchOrigin(vSource, sAppName, ::rtl::OUString::createFromAscii("SfxToolBoxControl")); + URL aURL; + aURL.Complete = m_aCommandURL; + ::comphelper::UiEventsLogger::logDispatch(aURL, vSource); + } svt::ToolboxController::execute( pImpl->nSelectModifier ); } diff --git a/sfx2/util/makefile.mk b/sfx2/util/makefile.mk index cfed0a838ffa..5ee6e64daca0 100644 --- a/sfx2/util/makefile.mk +++ b/sfx2/util/makefile.mk @@ -98,7 +98,9 @@ SHL1STDLIBS+=\ $(CPPULIB) \ $(VOSLIB) \ $(SALLIB) \ - $(SJLIB) + $(SJLIB) \ + $(LIBXML2LIB) \ + .IF "$(GUI)"=="WNT" |