// TODO/LATER: actually SwEmbedObjectLink should be used here, but because different objects are used to control // embedded object different link objects with the same functionality had to be implemented
namespace {
class SwEmbedObjectLink : public sfx2::SvBaseLink
{
SwOLENode* m_pOleNode;
::sfx2::SvBaseLink::UpdateResult SwEmbedObjectLink::DataChanged( const OUString&, const uno::Any& )
{ if (!m_pOleNode->UpdateLinkURL_Impl())
{ // the link URL was not changed
uno::Reference<embed::XEmbeddedObject> xObject = m_pOleNode->GetOLEObj().GetOleRef();
OSL_ENSURE( xObject.is(), "The object must exist always!" ); if ( xObject.is() )
{ // let the object reload the link // TODO/LATER: reload call could be used for this case
try
{
sal_Int32 nState = xObject->getCurrentState(); if ( nState != embed::EmbedStates::LOADED )
{ // in some cases the linked file probably is not locked so it could be changed
xObject->changeState( embed::EmbedStates::LOADED );
xObject->changeState( nState );
}
} catch (const uno::Exception&)
{
}
}
}
/** *LoadinganOLEobjectthathasbeenmovedtotheUndoArea
*/ bool SwOLENode::RestorePersistentData()
{
OSL_ENSURE( maOLEObj.GetOleRef().is(), "No object to restore!" ); if ( maOLEObj.m_xOLERef.is() )
{ // If a SvPersist instance already exists, we use it
rtl::Reference<SfxObjectShell> p = GetDoc().GetPersist(); if( !p )
{ // TODO/LATER: Isn't an EmbeddedObjectContainer sufficient here? // What happens to this document?
OSL_ENSURE( false, "Why are we creating a DocShell here?" );
p = new SwDocShell( GetDoc(), SfxObjectCreateMode::INTERNAL );
p->DoInitNew();
}
// TODO/LATER: aOLEObj.aName has no meaning here, since the undo container contains the object // by different name, in future it might makes sense that the name is transported here.
maOLEObj.m_xOLERef.AssignToContainer( nullptr, maOLEObj.m_aName ); try
{ // "unload" object
maOLEObj.m_xOLERef->changeState( embed::EmbedStates::LOADED );
} catch (const uno::Exception&)
{
}
}
}
SwOLENode *pNode = new SwOLENode( rWhere, xObj, pGrfColl, nullptr );
// set parent if XChild is supported //!! needed to supply Math objects with a valid reference device
uno::Reference< container::XChild > xChild( pNode->GetOLEObj().GetObject().GetObject(), UNO_QUERY ); if (xChild.is())
{
SwDocShell *pDocSh = GetDoc().GetDocShell(); if (pDocSh)
xChild->setParent( pDocSh->GetModel() );
}
// set parent if XChild is supported //!! needed to supply Math objects with a valid reference device
uno::Reference< container::XChild > xChild( pNode->GetOLEObj().GetObject().GetObject(), UNO_QUERY ); if (xChild.is())
{
SwDocShell *pDocSh = GetDoc().GetDocShell(); if (pDocSh)
xChild->setParent( pDocSh->GetModel() );
}
SwContentNode* SwOLENode::MakeCopy( SwDoc& rDoc, SwNode& rIdx, bool) const
{ // If there's already a SvPersist instance, we use it
rtl::Reference<SfxObjectShell> pPersistShell = rDoc.GetPersist(); if( !pPersistShell )
{ // TODO/LATER: is EmbeddedObjectContainer not enough? // the created document will be closed by rDoc ( should use SfxObjectShellLock )
pPersistShell = new SwDocShell( rDoc, SfxObjectCreateMode::INTERNAL );
rDoc.SetTmpDocShell(pPersistShell.get());
pPersistShell->DoInitNew();
}
// We insert it at SvPersist level // TODO/LATER: check if using the same naming scheme for all apps works here
OUString aNewName/*( Sw3Io::UniqueName( p->GetStorage(), "Obj" ) )*/;
SfxObjectShell* pSrc = GetDoc().GetPersist();
// pAnchorNd contains the most recently found Section Node, which // now must fulfill the prerequisites for the GlobalDoc
pSectNd = static_cast<const SwSectionNode*>(pAnchorNd); return SectionType::FileLink == pSectNd->GetSection().GetType() &&
pSectNd->GetIndex() > nEndExtraIdx;
}
bool SwOLENode::IsOLEObjectDeleted() const
{ if( maOLEObj.m_xOLERef.is() )
{
SfxObjectShell* p = GetDoc().GetPersist(); if( p ) // Must be there
{ return !p->GetEmbeddedObjectContainer().HasEmbeddedObject( maOLEObj.m_aName );
}
} returnfalse;
}
void SwOLENode::GetNewReplacement()
{ if ( maOLEObj.m_xOLERef.is() )
maOLEObj.m_xOLERef.UpdateReplacement();
}
if ( mpObjectLink )
{
OUString aNewLinkURL;
sfx2::LinkManager::GetDisplayNames( mpObjectLink, nullptr, &aNewLinkURL ); if ( !aNewLinkURL.equalsIgnoreAsciiCase( maLinkURL ) )
{ if ( !maOLEObj.m_xOLERef.is() )
maOLEObj.GetOleRef();
uno::Reference< embed::XEmbeddedObject > xObj = maOLEObj.m_xOLERef.GetObject();
uno::Reference< embed::XCommonEmbedPersist > xPersObj( xObj, uno::UNO_QUERY );
OSL_ENSURE( xPersObj.is(), "The object must exist!" ); if ( xPersObj.is() )
{ try
{
sal_Int32 nCurState = xObj->getCurrentState(); if ( nCurState != embed::EmbedStates::LOADED )
xObj->changeState( embed::EmbedStates::LOADED );
// TODO/LATER: there should be possible to get current mediadescriptor settings from the object
uno::Sequence< beans::PropertyValue > aArgs{ comphelper::makePropertyValue(
u"URL"_ustr, aNewLinkURL) };
xPersObj->reload( aArgs, uno::Sequence< beans::PropertyValue >() );
void SwOLENode::CheckFileLink_Impl()
{ if ( !maOLEObj.m_xOLERef.GetObject().is() || mpObjectLink ) return;
try
{
uno::Reference<embed::XEmbeddedObject> xObject = maOLEObj.m_xOLERef.GetObject(); if (!xObject) return;
bool bIFrame = false;
OUString aLinkURL;
uno::Reference<embed::XLinkageSupport> xLinkSupport(xObject, uno::UNO_QUERY); if (xLinkSupport)
{ if (xLinkSupport->isLink())
aLinkURL = xLinkSupport->getLinkURL();
} else
{ // get IFrame (Floating Frames) listed and updatable from the // manage links dialog
SvGlobalName aClassId(xObject->getClassID()); if (aClassId == SvGlobalName(SO3_IFRAME_CLASSID))
{
uno::Reference<beans::XPropertySet> xSet(xObject->getComponent(), uno::UNO_QUERY); if (xSet.is())
xSet->getPropertyValue(u"FrameURL"_ustr) >>= aLinkURL;
bIFrame = true;
}
}
if (!aLinkURL.isEmpty()) // this is a file link so the model link manager should handle it
{
SwEmbedObjectLink* pEmbedObjectLink = nullptr; if (!bIFrame)
{
pEmbedObjectLink = new SwEmbedObjectLink(this);
mpObjectLink = pEmbedObjectLink;
} else
{
mpObjectLink = new SwIFrameLink(this);
}
maLinkURL = aLinkURL;
GetDoc().getIDocumentLinksAdministration().GetLinkManager().InsertFileLink( *mpObjectLink, sfx2::SvBaseLinkObjectType::ClientOle, aLinkURL ); if (pEmbedObjectLink)
pEmbedObjectLink->Connect();
}
} catch( uno::Exception& )
{
}
}
// evtl.set from the SwOLEObj destructor when a WorkerThread is still active // since it is not possible to kill it - let it terminate and delete the // data working on itself
std::atomic< bool> mbKilled;
void waitFinished()
{ // need to wait until the load in progress is finished. // WorkerThreads need the SolarMutex to be able to continue // and finish the running import.
SolarMutexReleaser aReleaser;
comphelper::ThreadPool::getSharedOptimalPool().waitUntilDone(mpTag);
}
};
namespace {
/// Task for parallelly-executed task to load a chart model class DeflateThread : public comphelper::ThreadTask
{ // the data to work on
DeflateData& mrDeflateData;
private: virtualvoid doWork() override
{ try
{ // load the chart data and get the primitives
mrDeflateData.maPrimitive2DSequence = ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
mrDeflateData.maXModel,
mrDeflateData.maRange);
// model no longer needed and done
mrDeflateData.maXModel.clear();
} catch (const uno::Exception&)
{
}
if(mrDeflateData.mbKilled)
{ // need to cleanup myself - data will not be used delete &mrDeflateData;
}
}
};
SwOLEObj::~SwOLEObj() COVERITY_NOEXCEPT_FALSE
{ if(m_pDeflateData)
{ // set flag so that the worker thread will delete m_pDeflateData // when finished and forget about it
m_pDeflateData->mbKilled = true;
m_pDeflateData = nullptr;
}
if( m_pOLENode && !m_pOLENode->GetDoc().IsInDtor() )
{ // if the model is not currently in destruction it means that this object should be removed from the model
comphelper::EmbeddedObjectContainer* pCnt = m_xOLERef.GetContainer();
#if OSL_DEBUG_LEVEL > 0
SfxObjectShell* p = m_pOLENode->GetDoc().GetPersist();
OSL_ENSURE( p, "No document!" ); if( p )
{
comphelper::EmbeddedObjectContainer& rCnt = p->GetEmbeddedObjectContainer();
OSL_ENSURE( !pCnt || &rCnt == pCnt, "The helper is assigned to unexpected container!" );
} #endif
// not already removed by deleting the object
m_xOLERef.AssignToContainer( nullptr, m_aName );
// unlock object so that object can be closed in RemoveEmbeddedObject // successful closing of the object will automatically clear the reference then
m_xOLERef.Lock(false);
// Always remove object from container it is connected to try
{ // remove object from container but don't close it
pCnt->RemoveEmbeddedObject( m_aName );
} catch ( uno::Exception& )
{
}
}
}
if ( m_xOLERef.is() ) // in case the object wasn't closed: release it // in case the object was not in the container: it's still locked, try to close
m_xOLERef.Clear();
}
// If there's already a SvPersist instance, we use it
rtl::Reference<SfxObjectShell> p = rDoc.GetPersist(); if( !p )
{ // TODO/LATER: Isn't an EmbeddedObjectContainer sufficient here? // What happens to the document?
OSL_ENSURE( false, "Why are we creating a DocShell here??" );
p = new SwDocShell( rDoc, SfxObjectCreateMode::INTERNAL );
p->DoInitNew();
}
OUString aObjName;
uno::Reference < container::XChild > xChild( m_xOLERef.GetObject(), uno::UNO_QUERY ); if ( xChild.is() && xChild->getParent() != p->GetModel() ) // it is possible that the parent was set already
xChild->setParent( p->GetModel() );
rtl::OUString sTargetShellID = SfxObjectShell::CreateShellID(rDoc.GetDocShell());
if ( !xObj.is() )
{ // We could not load this part (probably broken)
tools::Rectangle aArea;
SwFrame *pFrame = m_pOLENode->getLayoutFrame(nullptr); if ( pFrame )
{
Size aSz( pFrame->getFrameArea().SSize() );
aSz = o3tl::convert( aSz, o3tl::Length::twip, o3tl::Length::mm100 );
aArea.SetSize( aSz );
} else
aArea.SetSize( Size( 5000, 5000 ) ); // TODO/LATER: set replacement graphic for dead object // It looks as if it should work even without the object, because the replace will be generated automatically
OUString aTmpName;
xObj = p->GetEmbeddedObjectContainer().CreateEmbeddedObject( SvGlobalName( SO3_DUMMY_CLASSID ).GetByteSequence(), aTmpName );
} if (xObj.is())
{
m_xOLERef.SetIsProtectedHdl(LINK(this, SwOLEObj, IsProtectedHdl));
m_xOLERef.Assign( xObj, m_xOLERef.GetViewAspect() );
m_xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), m_aName );
m_xListener = new SwOLEListener_Impl( this );
xObj->addStateChangeListener( m_xListener );
}
const_cast<SwOLENode*>(m_pOLENode)->CheckFileLink_Impl(); // for this notification nonconst access is required
} elseif ( m_xOLERef->getCurrentState() == embed::EmbedStates::RUNNING )
{ // move object to first position in cache if (!g_pOLELRU_Cache)
g_pOLELRU_Cache = std::make_shared<SwOLELRUCache>();
g_pOLELRU_Cache->InsertObj( *this );
}
if ( SotExchange::IsChart( aClassID ) ) return SwResId(STR_CHART);
return SwResId(STR_OLE);
}
drawinglayer::primitive2d::Primitive2DContainer const & SwOLEObj::tryToGetChartContentAsPrimitive2DSequence(
basegfx::B2DRange& rRange, bool bSynchron)
{ if(m_pDeflateData)
{ if(bSynchron)
{ // data in high quality is requested, wait until the data is available // since a WorkerThread was already started to load it
m_pDeflateData->waitFinished();
}
if(m_pDeflateData->isFinished())
{ // copy the result data and cleanup
m_aPrimitive2DSequence = m_pDeflateData->getSequence();
m_aRange = m_pDeflateData->getRange();
m_nGraphicVersion = GetObject().getGraphicVersion();
m_pDeflateData.reset();
}
}
if(!m_aPrimitive2DSequence.empty() && !m_aRange.isEmpty()
&& m_nGraphicVersion != GetObject().getGraphicVersion())
{ // tdf#149189 use getGraphicVersion() from EmbeddedObjectRef // to decide when to reset buffered data. It gets incremented // at all occasions where the graphic changes. An alternative // would be to extend SwOLEListener_Impl with a XModifyListener // as it is done in EmbedEventListener_Impl, that would // require all the (add|remove)ModifyListener calls and // managing these, plus having a 2nd listener to these when // EmbeddedObjectRef already provides that. Tried that this // works also if an alternative would be needed.
resetBufferedData();
}
if(aXModel.is())
{ // disabled for now, need to check deeper staticbool bAsynchronousLoadingAllowed = false; // loplugin:constvars:ignore
if(bSynchron ||
!bAsynchronousLoadingAllowed)
{ // load chart synchron in this Thread
m_aPrimitive2DSequence = ChartHelper::tryToGetChartContentAsPrimitive2DSequence(
aXModel,
m_aRange);
} else
{ // if not yet setup, initiate and start a WorkerThread to load the chart // and it's primitives asynchron. If it already works, returning nothing // is okay (preview will be reused) if(!m_pDeflateData)
{
m_pDeflateData.reset( new DeflateData(aXModel) );
std::unique_ptr<DeflateThread> pNew( new DeflateThread(*m_pDeflateData) );
comphelper::ThreadPool::getSharedOptimalPool().pushTask(std::move(pNew));
}
}
}
}
if(!m_aPrimitive2DSequence.empty() && !m_aRange.isEmpty())
{ // when we have data, also copy the buffered Range data as output
rRange = m_aRange;
// tdf#149189 ..and the GraphicVersion number to identify changes
m_nGraphicVersion = GetObject().getGraphicVersion();
}
return m_aPrimitive2DSequence;
}
SvxDrawPage* SwOLEObj::tryToGetChartDrawPage() const
{ if (!m_xOLERef.is() || !m_xOLERef.IsChart()) return nullptr; const uno::Reference<frame::XModel> xModel(m_xOLERef->getComponent(), uno::UNO_QUERY); if (!xModel.is()) return nullptr; const uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xModel, uno::UNO_QUERY); if (!xDrawPageSupplier) return nullptr; const uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPageSupplier->getDrawPage()); if (!xDrawPage) return nullptr; return comphelper::getFromUnoTunnel<SvxDrawPage>(xDrawPage);
}
if(m_pDeflateData)
{ // load is in progress, wait until finished and cleanup without using it
m_pDeflateData->waitFinished();
m_pDeflateData.reset();
}
}
void SwOLELRUCache::tryShrinkCacheTo(sal_Int32 nVal)
{ // size of cache has been changed
sal_Int32 nCount = m_OleObjects.size();
sal_Int32 nPos = nCount;
// try to remove the last entries until new maximum size is reached while( nCount > nVal )
{
SwOLEObj *const pObj = m_OleObjects[ --nPos ]; if ( pObj->UnloadObject() )
nCount--; if ( !nPos ) break;
}
}
void SwOLELRUCache::InsertObj( SwOLEObj& rObj )
{
SwOLEObj* pObj = &rObj; if (autoconst it = std::find(m_OleObjects.begin(), m_OleObjects.end(), pObj);
it != m_OleObjects.end())
{ if (it == m_OleObjects.begin()) return; // Everything is already in place // object in cache but is currently not the first in cache
m_OleObjects.erase(it);
}
std::shared_ptr<SwOLELRUCache> xKeepAlive(g_pOLELRU_Cache); // prevent delete this // try to remove objects if necessary
sal_Int32 nCount = m_OleObjects.size();
sal_Int32 nPos = nCount-1; while (nPos >= 0 && nCount >= m_nLRU_InitSize)
{
pObj = m_OleObjects[ nPos-- ]; if ( pObj->UnloadObject() )
nCount--;
}
m_OleObjects.push_front(&rObj);
}
void SwOLELRUCache::RemoveObj( SwOLEObj& rObj )
{ autoconst it = std::find(m_OleObjects.begin(), m_OleObjects.end(), &rObj); if (it != m_OleObjects.end())
{
m_OleObjects.erase(it);
} if (m_OleObjects.empty())
{ if (g_pOLELRU_Cache.use_count() == 1) // test that we're not in InsertObj()
{
g_pOLELRU_Cache.reset();
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.