diff options
author | Juergen Funk <juergen.funk_ml@cib.de> | 2022-02-22 09:19:29 +0100 |
---|---|---|
committer | Samuel Mehrbrodt <samuel.mehrbrodt@allotropia.de> | 2022-05-10 09:02:01 +0200 |
commit | cf650ceaafb4d3a3f46991dc1b12efa0e37a71f9 (patch) | |
tree | 0bcbc4178c8f940c747507f4d24bef2685dfa399 /embeddedobj | |
parent | 63a2f314250b05d484747fafc4a814a4553f461e (diff) |
tdf#147590 update OLE object after document refresh
Regression from b099da78a6f0b3e120f706714003b05d84d11e70
we didn't update linked OLE document after document reload
Change-Id: I8e52f6430f454b276cb43449c6f7a3b0e07e909f
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130692
Reviewed-by: Samuel Mehrbrodt <samuel.mehrbrodt@allotropia.de>
Tested-by: Jenkins
Diffstat (limited to 'embeddedobj')
-rw-r--r-- | embeddedobj/Library_embobj.mk | 4 | ||||
-rw-r--r-- | embeddedobj/source/commonembedding/embedobj.cxx | 7 | ||||
-rw-r--r-- | embeddedobj/source/commonembedding/miscobj.cxx | 153 | ||||
-rw-r--r-- | embeddedobj/source/commonembedding/persistence.cxx | 31 | ||||
-rw-r--r-- | embeddedobj/source/inc/commonembobj.hxx | 20 | ||||
-rw-r--r-- | embeddedobj/source/inc/strings.hrc | 19 |
6 files changed, 195 insertions, 39 deletions
diff --git a/embeddedobj/Library_embobj.mk b/embeddedobj/Library_embobj.mk index 35a654835dae..18cf55518d44 100644 --- a/embeddedobj/Library_embobj.mk +++ b/embeddedobj/Library_embobj.mk @@ -21,6 +21,10 @@ $(eval $(call gb_Library_set_include,embobj,\ $$(INCLUDE) \ )) +$(eval $(call gb_Library_add_defs,embobj,\ + -DEMBOBJ_DLLIMPLEMENTATION \ +)) + $(eval $(call gb_Library_use_external,embobj,boost_headers)) $(eval $(call gb_Library_use_sdk_api,embobj)) diff --git a/embeddedobj/source/commonembedding/embedobj.cxx b/embeddedobj/source/commonembedding/embedobj.cxx index 223f25e6302c..240112b2483e 100644 --- a/embeddedobj/source/commonembedding/embedobj.cxx +++ b/embeddedobj/source/commonembedding/embedobj.cxx @@ -639,6 +639,13 @@ void SAL_CALL OCommonEmbeddedObject::setContainerName( const OUString& sName ) m_aContainerName = sName; } +void OCommonEmbeddedObject::SetOleState(bool bIsOleUpdate) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + m_bOleUpdate = bIsOleUpdate; +} + css::uno::Reference< css::uno::XInterface > SAL_CALL OCommonEmbeddedObject::getParent() { return m_xParent; diff --git a/embeddedobj/source/commonembedding/miscobj.cxx b/embeddedobj/source/commonembedding/miscobj.cxx index a5d5573416d1..f41d35957b5d 100644 --- a/embeddedobj/source/commonembedding/miscobj.cxx +++ b/embeddedobj/source/commonembedding/miscobj.cxx @@ -35,6 +35,13 @@ #include <cppuhelper/queryinterface.hxx> #include <comphelper/mimeconfighelper.hxx> +#include <vcl/weld.hxx> +#include <unotools/resmgr.hxx> +#include <vcl/stdtext.hxx> +#include <strings.hrc> +#include <osl/file.hxx> +#include <comphelper/DirectoryHelper.hxx> + #include <vcl/svapp.hxx> #include <tools/diagnose_ex.h> #include <cppuhelper/supportsservice.hxx> @@ -62,7 +69,11 @@ OCommonEmbeddedObject::OCommonEmbeddedObject( const uno::Reference< uno::XCompon , m_bWaitSaveCompleted( false ) , m_bIsLinkURL( false ) , m_bLinkTempFileChanged( false ) +, m_pLinkFile( ) +, m_bOleUpdate( false ) +, m_bInHndFunc( false ) , m_bLinkHasPassword( false ) +, m_aLinkTempFile( ) , m_bHasClonedSize( false ) , m_nClonedMapUnit( 0 ) { @@ -88,7 +99,11 @@ OCommonEmbeddedObject::OCommonEmbeddedObject( , m_bWaitSaveCompleted( false ) , m_bIsLinkURL( true ) , m_bLinkTempFileChanged( false ) +, m_pLinkFile( ) +, m_bOleUpdate( false ) +, m_bInHndFunc( false ) , m_bLinkHasPassword( false ) +, m_aLinkTempFile( ) , m_bHasClonedSize( false ) , m_nClonedMapUnit( 0 ) { @@ -224,26 +239,13 @@ void OCommonEmbeddedObject::LinkInit_Impl( // task-ID above) // // open OLE original data as read input file - uno::Reference< ucb::XSimpleFileAccess3 > xTempAccess( ucb::SimpleFileAccess::create( m_xContext ) ); - uno::Reference< io::XInputStream > xInStream( xTempAccess->openFileRead( m_aLinkURL ) ); - - if(xInStream.is()) + if ( comphelper::DirectoryHelper::fileExists( m_aLinkURL ) ) { // create temporary file - m_aLinkTempFile = io::TempFile::create(m_xContext); - uno::Reference< ucb::XSimpleFileAccess > xTempOutAccess(ucb::SimpleFileAccess::create(m_xContext)); - // if the temp stream is used, then the temp file remains locked - uno::Reference< io::XOutputStream > xOutStream(xTempOutAccess->openFileWrite(m_aLinkTempFile->getUri())); - - if(m_aLinkTempFile.is()) - { - // completely copy content of original OLE data - ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream); + m_aLinkTempFile = io::TempFile::create( m_xContext ); - // reset flag m_bLinkTempFileChanged, so it will also work for multiple - // save op's of the containing file/document - m_bLinkTempFileChanged = false; - } + m_pLinkFile.reset( new FileChangedChecker( m_aLinkURL ) ); + handleLinkedOLE( CopyBackToOLELink::CopyLinkToTempInit ); } } @@ -379,6 +381,123 @@ void OCommonEmbeddedObject::PostEvent_Impl( const OUString& aEventName ) } +static int ShowMsgDialog( TranslateId Msg, const OUString& sFileName ) +{ + std::locale aResLocale = Translate::Create( "emo" ); + OUString aMsg = Translate::get( Msg, aResLocale ); + OUString aBtn = Translate::get( BTN_OVERWRITE_TEXT, aResLocale ); + OUString aTemp = sFileName; + + osl::FileBase::getSystemPathFromFileURL( sFileName, aTemp ); + + aMsg = aMsg.replaceFirst( "%{filename}", aTemp ); + weld::Window* pParent = Application::GetFrameWeld( nullptr ); + + std::unique_ptr<weld::MessageDialog> xQueryBox (Application::CreateMessageDialog( pParent, + VclMessageType::Warning, VclButtonsType::NONE, aMsg ) ); + xQueryBox->add_button( aBtn, RET_YES ); + xQueryBox->add_button( GetStandardText( StandardButtonType::Cancel ), RET_CANCEL ); + xQueryBox->set_default_response( RET_CANCEL ); + + return xQueryBox->run(); +} + + +void OCommonEmbeddedObject::handleLinkedOLE( CopyBackToOLELink eState ) +{ + // do not refresh and autosave at the same time + // when refresh all, then get both Link and Ole Update, in this case ignore OLE-refresh + if ( m_bInHndFunc || m_bOleUpdate || !m_aLinkTempFile.is() ) + return; + + m_bInHndFunc = true; + + bool bLnkFileChg = m_pLinkFile->hasFileChanged( false ); + bool bTmpFileChg = m_bLinkTempFileChanged; + + + if ( eState != CopyBackToOLELink::CopyLinkToTempInit && !bLnkFileChg && !bTmpFileChg ) + { + // no changes + eState = CopyBackToOLELink::NoCopy; + } + else if ( ( eState == CopyBackToOLELink::CopyTempToLink ) && bLnkFileChg && !bTmpFileChg ) + { + // Save pressed, but the Link-file is changed, but not the temp-file + // in this case update the object with new link data + eState = CopyBackToOLELink::CopyLinkToTempRefresh; + } + else if ( ( eState == CopyBackToOLELink::CopyTempToLink ) && bLnkFileChg && bTmpFileChg ) + { + // Save pressed, but the Link-file is changed, question to user for overwrite + if ( ShowMsgDialog(STR_OVERWRITE_LINK, m_aLinkURL) == RET_CANCEL ) + eState = CopyBackToOLELink::NoCopy; + } + else if ( ( eState == CopyBackToOLELink::CopyLinkToTemp ) && bTmpFileChg ) + { + // Refresh pressed, but the Temp-file is changed, question to user for overwrite + // it is not importent it has bLnkFileChg, always overwite the temp-file + if ( ShowMsgDialog( STR_OVERWRITE_TEMP, m_aLinkURL ) == RET_CANCEL ) + eState = CopyBackToOLELink::NoCopy; + } + + auto writeFile = [ this ]( const OUString& SrcName, const OUString& DesName ) + { + uno::Reference < ucb::XSimpleFileAccess2 > xWriteAccess( ucb::SimpleFileAccess::create( m_xContext ) ); + uno::Reference < ucb::XSimpleFileAccess > xReadAccess( ucb::SimpleFileAccess::create( m_xContext ) ); + + try + { + uno::Reference < io::XInputStream > xInStream( xReadAccess->openFileRead (SrcName ) ); + + // This is *needed* since OTempFileService calls OTempFileService::readBytes which + // ensures the SvStream mpStream gets/is opened, *but* also sets the mnCachedPos from + // OTempFileService which still points to the end-of-file (from write-cc'ing). + uno::Reference < io::XSeekable > xSeek( xInStream, uno::UNO_QUERY_THROW ); + xSeek->seek( 0 ); + + xWriteAccess->writeFile( DesName, xInStream ); + m_bLinkTempFileChanged = false; + // store the new timestamp + m_pLinkFile->hasFileChanged(); + } + catch ( const uno::Exception& ex ) + { + OUString aMsg; + osl::FileBase::getSystemPathFromFileURL( SrcName, aMsg ); + aMsg = ex.Message + "\n\n" + aMsg; + weld::Window* pParent = Application::GetFrameWeld( nullptr ); + std::unique_ptr<weld::MessageDialog> xQueryBox( Application::CreateMessageDialog( pParent, + VclMessageType::Error, VclButtonsType::Ok, aMsg ) ); + + xQueryBox->run(); + } + }; + + switch ( eState ) + { + case CopyBackToOLELink::NoCopy: + break; + case CopyBackToOLELink::CopyLinkToTemp: // copy Link-File to Temp-File (Refresh) + case CopyBackToOLELink::CopyLinkToTempInit: //create temp file + writeFile( m_aLinkURL, m_aLinkTempFile->getUri() ); + break; + case CopyBackToOLELink::CopyTempToLink: // copy Temp-File to Link-File (Save) + // tdf#141529 if we have a changed copy of the original OLE data we now + // need to write it back 'over' the original OLE data + writeFile( m_aLinkTempFile->getUri(), m_aLinkURL ); + break; + case CopyBackToOLELink::CopyLinkToTempRefresh: // need a Refresh not save + // do nothing + break; + default: + break; + } + + m_bInHndFunc = false; +} + + uno::Any SAL_CALL OCommonEmbeddedObject::queryInterface( const uno::Type& rType ) { uno::Any aReturn; diff --git a/embeddedobj/source/commonembedding/persistence.cxx b/embeddedobj/source/commonembedding/persistence.cxx index 77bc947650af..b32d07f1c59c 100644 --- a/embeddedobj/source/commonembedding/persistence.cxx +++ b/embeddedobj/source/commonembedding/persistence.cxx @@ -54,6 +54,7 @@ #include <comphelper/mimeconfighelper.hxx> #include <comphelper/namedvaluecollection.hxx> #include <comphelper/propertyvalue.hxx> +#include <unotools/mediadescriptor.hxx> #include <tools/diagnose_ex.h> #include <sal/log.hxx> @@ -392,6 +393,8 @@ uno::Reference< util::XCloseable > OCommonEmbeddedObject::LoadLink_Impl() try { + handleLinkedOLE(CopyBackToOLELink::CopyLinkToTemp); + // the document is not really an embedded one, it is a link EmbedAndReparentDoc_Impl( xDocument ); @@ -1254,12 +1257,14 @@ void SAL_CALL OCommonEmbeddedObject::storeAsEntry( const uno::Reference< embed:: const uno::Sequence< beans::PropertyValue >& lArguments, const uno::Sequence< beans::PropertyValue >& lObjArgs ) { - // TODO: use lObjArgs - ::osl::ResettableMutexGuard aGuard( m_aMutex ); if ( m_bDisposed ) throw lang::DisposedException(); // TODO + bool AutoSaveEvent = false; + utl::MediaDescriptor lArgs(lObjArgs); + lArgs[utl::MediaDescriptor::PROP_AUTOSAVEEVENT] >>= AutoSaveEvent; + if ( m_nObjectState == -1 ) { // the object is still not loaded @@ -1279,26 +1284,8 @@ void SAL_CALL OCommonEmbeddedObject::storeAsEntry( const uno::Reference< embed:: { m_aNewEntryName = sEntName; - if(m_aLinkTempFile.is() && m_bLinkTempFileChanged) - { - // tdf#141529 if we have a changed copy of the original OLE data we now - // need to write it back 'over' the original OLE data - uno::Reference < ucb::XSimpleFileAccess2 > xFileAccess(ucb::SimpleFileAccess::create( m_xContext )); - - uno::Reference< ucb::XSimpleFileAccess > xTempAccess(ucb::SimpleFileAccess::create(m_xContext)); - // if the temp stream is used, then the temp file remains locked - uno::Reference< io::XInputStream > xInStream(xTempAccess->openFileRead(m_aLinkTempFile->getUri())); - // This is *needed* since OTempFileService calls OTempFileService::readBytes which - // ensures the SvStream mpStream gets/is opened, *but* also sets the mnCachedPos from - // OTempFileService which still points to the end-of-file (from write-cc'ing). - uno::Reference < io::XSeekable > xSeek( xInStream, uno::UNO_QUERY_THROW ); - xSeek->seek(0); - - xFileAccess->writeFile(m_aLinkURL, xInStream); - - // reset flag m_bLinkTempFileChanged - m_bLinkTempFileChanged = false; - } + if ( !AutoSaveEvent ) + handleLinkedOLE(CopyBackToOLELink::CopyTempToLink); return; } diff --git a/embeddedobj/source/inc/commonembobj.hxx b/embeddedobj/source/inc/commonembobj.hxx index 785a28eaf0fd..61abe0299ee1 100644 --- a/embeddedobj/source/inc/commonembobj.hxx +++ b/embeddedobj/source/inc/commonembobj.hxx @@ -36,9 +36,11 @@ #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/lang/XInitialization.hpp> #include <cppuhelper/weak.hxx> +#include <embeddedobj/embeddedupdate.hxx> #include <rtl/ref.hxx> #include <map> #include <memory> +#include <svtools/filechangedchecker.hxx> namespace com::sun::star { namespace embed { @@ -76,6 +78,7 @@ class Interceptor; * document model successfully. */ class OCommonEmbeddedObject : public css::embed::XEmbeddedObject + , public css::embed::EmbeddedUpdate , public css::embed::XEmbedPersist2 , public css::embed::XLinkageSupport , public css::embed::XInplaceObject @@ -141,6 +144,9 @@ protected: bool m_bIsLinkURL; bool m_bLinkTempFileChanged; + ::std::unique_ptr< FileChangedChecker > m_pLinkFile; + bool m_bOleUpdate; + bool m_bInHndFunc; // embedded object related stuff OUString m_aEntryName; @@ -193,6 +199,16 @@ private: void Deactivate(); + // when State = CopyTempToLink -> the user pressed the save button + // when change in embedded part then copy to the linked-file + // CopyLinkToTemp -> the user pressed the refresh button + // when change in linked-file then copy to the embedded part (temp-file) + // CopyLinkToTempInit -> create the temp file + // CopyLinkToTempRefresh -> when save and Link change but not temp then update temp + enum class CopyBackToOLELink {NoCopy, CopyTempToLink, CopyLinkToTemp, CopyLinkToTempInit, CopyLinkToTempRefresh}; + + void handleLinkedOLE( CopyBackToOLELink eState ); + void StateChangeNotification_Impl( bool bBeforeChange, sal_Int32 nOldState, sal_Int32 nNewState,::osl::ResettableMutexGuard& _rGuard ); void SwitchStateTo_Impl( sal_Int32 nNextState ); @@ -294,6 +310,10 @@ public: virtual void SAL_CALL setContainerName( const OUString& sName ) override; +// EmbeddedUpdate + + virtual void SetOleState(bool bIsOleUpdate) override; + // XVisualObject diff --git a/embeddedobj/source/inc/strings.hrc b/embeddedobj/source/inc/strings.hrc new file mode 100644 index 000000000000..a3b323c54cf3 --- /dev/null +++ b/embeddedobj/source/inc/strings.hrc @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#define NC_(Context, String) TranslateId(Context, reinterpret_cast<char const *>(u8##String)) + +#define BTN_OVERWRITE_TEXT NC_("BTN_OVERWRITE_TEXT", "Overwrite") +#define STR_OVERWRITE_LINK NC_("STR_OVERWRITE_LINK", "You have made changes to the %{filename}, saving will overwrite the data from the inserted object.\n\nDo you still want to overwrite this data?") +#define STR_OVERWRITE_TEMP NC_("STR_OVERWRITE_TEMP", "You have changed the data in the inserted object which will be overwritten by updating the %{filename}.\n\nDo you still want to overwrite this data?") + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |