summaryrefslogtreecommitdiff
path: root/dbaccess
diff options
context:
space:
mode:
authorNoel Power <noel.power@novell.com>2011-08-22 15:41:30 +0100
committerNoel Power <noel.power@novell.com>2011-08-22 15:44:55 +0100
commit117281ba12e703fcd04ca87309dfd4a31432d1c5 (patch)
treee530aa17f0781b1296f1d45ec4ad5c21e1f029b4 /dbaccess
parentdcd3f14c52d056ccb7117622a6b2bf939ab0567d (diff)
fix leaking 'Pictures' streams from basic dialogs in base
With database document, any contents of the Pictures folder ( afaics only basic dialogs store content here ) is never cleaned up between saves.
Diffstat (limited to 'dbaccess')
-rw-r--r--dbaccess/source/core/dataaccess/databasedocument.cxx104
1 files changed, 104 insertions, 0 deletions
diff --git a/dbaccess/source/core/dataaccess/databasedocument.cxx b/dbaccess/source/core/dataaccess/databasedocument.cxx
index d8132a543e28..37f60919d56b 100644
--- a/dbaccess/source/core/dataaccess/databasedocument.cxx
+++ b/dbaccess/source/core/dataaccess/databasedocument.cxx
@@ -64,6 +64,12 @@
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#include <com/sun/star/ucb/XContent.hpp>
#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+
+#include <com/sun/star/script/XStorageBasedLibraryContainer.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/XDialogProvider.hpp>
+#include <com/sun/star/document/XGraphicObjectResolver.hpp>
+
/** === end UNO includes === **/
#include <comphelper/documentconstants.hxx>
@@ -95,6 +101,7 @@
#include <functional>
#include <list>
+#include <svtools/grfmgr.hxx>
#define MAP_LEN(x) x, sizeof(x) - 1
using namespace ::com::sun::star::uno;
@@ -384,6 +391,85 @@ namespace
}
}
+static rtl::OUString sPictures( RTL_CONSTASCII_USTRINGPARAM("Pictures") );
+
+// base documents seem to have a different behaviour to other documents, the
+// root storage contents at least seem to be re-used over different saves, thus if there is a
+// top level Picture directory it is never cleared.
+// If we delete the 'Pictures' directory then the dialog library storage which does store
+// any embed images will not work properly. ( this is due to the fact it will
+// try to load the dialog which will try and access the embed images, if those images are not cached in
+// memory it will try to read them from the Picture directory which is now gone, so... we have to use this
+// inglorious hack below which basically will
+// a) create a temp storage
+// b) introspect any dialogs for any embed graphics and grab the associate URL(s)
+// c) populate the temp storage with the associated embed images ( will be stored in a 'Pictures' folder )
+// d) delete the 'Picture' element from the root storage
+// e) copy the Pictures element of the temp storage to the root storage
+//
+// this assumes that we don't use the Pictures folder in the root of the base
+// document for anything, I believe this is a valid assumption ( as much as
+// I could check anyway )
+
+void lcl_uglyHackToStoreDialogeEmbedImages( const Reference< XStorageBasedLibraryContainer >& xDlgCont, const Reference< XStorage >& xStorage, const Reference< XModel >& rxModel, const ::comphelper::ComponentContext& aContext ) throw ( RuntimeException )
+{
+ Sequence< rtl::OUString > sLibraries = xDlgCont->getElementNames();
+ Reference< XStorage > xTmpPic = xStorage->openStorageElement( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("tempPictures") ), ElementModes::READWRITE );
+
+ std::vector< rtl::OUString > vEmbedImgUrls;
+ for ( sal_Int32 i=0; i < sLibraries.getLength(); ++i )
+ {
+ rtl::OUString sLibrary( sLibraries[ i ] );
+ xDlgCont->loadLibrary( sLibrary );
+ Reference< XNameContainer > xLib;
+ xDlgCont->getByName( sLibrary ) >>= xLib;
+ if ( xLib.is() )
+ {
+ Sequence< rtl::OUString > sDialogs = xLib->getElementNames();
+ sal_Int32 nDialogs( sDialogs.getLength() );
+ for ( sal_Int32 j=0; j < nDialogs; ++j )
+ {
+ Reference < ::com::sun::star::awt::XDialogProvider > xDlgPrv;
+ Sequence< Any > aArgs(1);
+ aArgs[ 0 ] <<= rxModel;
+ xDlgPrv.set( aContext.createComponentWithArguments( ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.awt.DialogProvider")) , aArgs), UNO_QUERY );
+ rtl::OUString sDialogUrl = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("vnd.sun.star.script:") );
+ sDialogUrl = sDialogUrl.concat( sLibraries[ i ] ).concat( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("." ) ) ).concat ( sDialogs[ j ] ).concat( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("?location=document") ) );
+
+ Reference< ::com::sun::star::awt::XControl > xDialog( xDlgPrv->createDialog( sDialogUrl ), UNO_QUERY );
+ Reference< XInterface > xModel = xDialog->getModel();
+ GraphicObject::InspectForGraphicObjectImageURL( xModel, vEmbedImgUrls );
+ }
+ }
+ }
+ // if we have any image urls, make sure we copy the associated images into tempPictures
+ if ( vEmbedImgUrls.size() )
+ {
+ // Export the images to the storage
+ Sequence< Any > aArgs( 1 );
+ aArgs[ 0 ] <<= xTmpPic;
+ Reference< XGraphicObjectResolver > xGraphicResolver(
+ aContext.createComponentWithArguments( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.Svx.GraphicExportHelper" ) ), aArgs ), UNO_QUERY );
+ std::vector< rtl::OUString >::iterator it = vEmbedImgUrls.begin();
+ std::vector< rtl::OUString >::iterator it_end = vEmbedImgUrls.end();
+ if ( xGraphicResolver.is() )
+ {
+ for ( sal_Int32 count = 0; it != it_end; ++it, ++count )
+ xGraphicResolver->resolveGraphicObjectURL( *it );
+ }
+
+ // delete old 'Pictures' storage and copy the contents of tempPictures into xStorage
+ xStorage->removeElement( sPictures );
+ xTmpPic->copyElementTo( sPictures, xStorage, sPictures );
+ }
+ else
+ {
+ // clean up an existing Pictures dir
+ if ( xStorage->isStorageElement( sPictures ) )
+ xStorage->removeElement( sPictures );
+ }
+}
+
void ODatabaseDocument::impl_setInitialized()
{
m_eInitState = Initialized;
@@ -1600,6 +1686,24 @@ void ODatabaseDocument::impl_writeStorage_throw( const Reference< XStorage >& _r
WriteThroughComponent( xComponent, "content.xml", "com.sun.star.comp.sdb.DBExportFilter",
aDelegatorArguments, aMediaDescriptor, _rxTargetStorage );
+ if ( _rxTargetStorage->hasByName ( sPictures ) )
+ {
+ try
+ {
+ // Delete any previously existing Pictures folder and regenerate
+ // any needed content if needed
+ Reference< XStorageBasedLibraryContainer > xDlgs = m_pImpl->getLibraryContainer( false );
+ if ( xDlgs.is() )
+ {
+ Reference< XModel > xModel(const_cast< ODatabaseDocument*>(this));
+ lcl_uglyHackToStoreDialogeEmbedImages( m_pImpl->getLibraryContainer(false), _rxTargetStorage, xModel, m_pImpl->m_aContext );
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION();
+ }
+ }
m_pImpl->storeLibraryContainersTo( _rxTargetStorage );
}