office-gobmx/svx/source/svdraw/svdoole2.cxx
Stephan Bergmann f853ec317f Extend loplugin:external to warn about classes
...following up on 314f15bff0 "Extend
loplugin:external to warn about enums".

Cases where free functions were moved into an unnamed namespace along with a
class, to not break ADL, are in:

  filter/source/svg/svgexport.cxx
  sc/source/filter/excel/xelink.cxx
  sc/source/filter/excel/xilink.cxx
  svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx

All other free functions mentioning moved classes appear to be harmless and not
give rise to (silent, even) ADL breakage.  (One remaining TODO in
compilerplugins/clang/external.cxx is that derived classes are not covered by
computeAffectedTypes, even though they could also be affected by ADL-breakage---
but don't seem to be in any acutal case across the code base.)

For friend declarations using elaborate type specifiers, like

  class C1 {};
  class C2 { friend class C1; };

* If C2 (but not C1) is moved into an unnamed namespace, the friend declaration
must be changed to not use an elaborate type specifier (i.e., "friend C1;"; see
C++17 [namespace.memdef]/3: "If the name in a friend declaration is neither
qualified nor a template-id and the declaration is a function or an
elaborated-type-specifier, the lookup to determine whether the entity has been
previously declared shall not consider any scopes outside the innermost
enclosing namespace.")

* If C1 (but not C2) is moved into an unnamed namespace, the friend declaration
must be changed too, see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71882>
"elaborated-type-specifier friend not looked up in unnamed namespace".

Apart from that, to keep changes simple and mostly mechanical (which should help
avoid regressions), out-of-line definitions of class members have been left in
the enclosing (named) namespace.  But explicit specializations of class
templates had to be moved into the unnamed namespace to appease
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92598> "explicit specialization of
template from unnamed namespace using unqualified-id in enclosing namespace".

Also, accompanying declarations (of e.g. typedefs or static variables) that
could arguably be moved into the unnamed namespace too have been left alone.

And in some cases, mention of affected types in blacklists in other loplugins
needed to be adapted.

And sc/qa/unit/mark_test.cxx uses a hack of including other .cxx, one of which
is sc/source/core/data/segmenttree.cxx where e.g. ScFlatUInt16SegmentsImpl is
not moved into an unnamed namespace (because it is declared in
sc/inc/segmenttree.hxx), but its base ScFlatSegmentsImpl is.  GCC warns about
such combinations with enabled-by-default -Wsubobject-linkage, but "The compiler
doesn’t give this warning for types defined in the main .C file, as those are
unlikely to have multiple definitions."
(<https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Warning-Options.html>)  The
warned-about classes also don't have multiple definitions in the given test, so
disable the warning when including the .cxx.

Change-Id: Ib694094c0d8168be68f8fe90dfd0acbb66a3f1e4
Reviewed-on: https://gerrit.libreoffice.org/83239
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2019-11-22 12:57:32 +01:00

1957 lines
66 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <svx/svdoole2.hxx>
#include <com/sun/star/util/XModifyBroadcaster.hpp>
#include <com/sun/star/util/XModifiable.hpp>
#include <com/sun/star/chart2/XChartDocument.hpp>
#include <com/sun/star/embed/EmbedStates.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/EmbedMisc.hpp>
#include <com/sun/star/embed/Aspects.hpp>
#include <com/sun/star/embed/ObjectSaveVetoException.hpp>
#include <com/sun/star/embed/XEmbeddedObject.hpp>
#include <com/sun/star/embed/XEmbedPersist2.hpp>
#include <com/sun/star/embed/XInplaceClient.hpp>
#include <com/sun/star/embed/XInplaceObject.hpp>
#include <com/sun/star/embed/XLinkageSupport.hpp>
#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
#include <com/sun/star/embed/XWindowSupplier.hpp>
#include <com/sun/star/document/XEventListener.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/document/XStorageBasedDocument.hpp>
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
#include <cppuhelper/exc_hlp.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <toolkit/awt/vclxwindow.hxx>
#include <toolkit/helper/convert.hxx>
#include <vcl/graphicfilter.hxx>
#include <svtools/embedhlp.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/ipclient.hxx>
#include <sfx2/lnkbase.hxx>
#include <tools/stream.hxx>
#include <comphelper/anytostring.hxx>
#include <svx/svdpagv.hxx>
#include <tools/debug.hxx>
#include <tools/globname.hxx>
#include <tools/diagnose_ex.h>
#include <vcl/jobset.hxx>
#include <comphelper/classids.hxx>
#include <sot/formats.hxx>
#include <vcl/transfer.hxx>
#include <cppuhelper/implbase.hxx>
#include <svl/solar.hrc>
#include <svl/urihelper.hxx>
#include <vcl/svapp.hxx>
#include <svx/charthelper.hxx>
#include <svx/svdmodel.hxx>
#include <svx/dialmgr.hxx>
#include <svx/strings.hrc>
#include <svx/svdetc.hxx>
#include <svx/svdview.hxx>
#include <unomlstr.hxx>
#include <sdr/contact/viewcontactofsdrole2obj.hxx>
#include <svx/svdograf.hxx>
#include <sdr/properties/oleproperties.hxx>
#include <svx/xlineit0.hxx>
#include <svx/xlnclit.hxx>
#include <svx/xbtmpit.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xflbmtit.hxx>
#include <svx/xflbstit.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <editeng/outlobj.hxx>
#include <svx/svdpage.hxx>
#include <rtl/ref.hxx>
#include <bitmaps.hlst>
#include <sal/log.hxx>
using namespace ::com::sun::star;
static uno::Reference < beans::XPropertySet > lcl_getFrame_throw(const SdrOle2Obj* _pObject)
{
uno::Reference < beans::XPropertySet > xFrame;
if ( _pObject )
{
uno::Reference< frame::XController> xController = _pObject->GetParentXModel()->getCurrentController();
if ( xController.is() )
{
xFrame.set( xController->getFrame(),uno::UNO_QUERY_THROW);
}
} // if ( _pObject )
return xFrame;
}
namespace {
class SdrLightEmbeddedClient_Impl : public ::cppu::WeakImplHelper
< embed::XStateChangeListener
, document::XEventListener
, embed::XInplaceClient
, embed::XEmbeddedClient
, embed::XWindowSupplier
>
{
uno::Reference< awt::XWindow > m_xWindow;
SdrOle2Obj* mpObj;
Fraction m_aScaleWidth;
Fraction m_aScaleHeight;
public:
explicit SdrLightEmbeddedClient_Impl( SdrOle2Obj* pObj );
virtual ~SdrLightEmbeddedClient_Impl() override;
void SetSizeScale( const Fraction& aScaleWidth, const Fraction& aScaleHeight )
{
m_aScaleWidth = aScaleWidth;
m_aScaleHeight = aScaleHeight;
}
const Fraction& GetScaleWidth() const { return m_aScaleWidth; }
const Fraction& GetScaleHeight() const { return m_aScaleHeight; }
void setWindow(const uno::Reference< awt::XWindow >& _xWindow);
void disconnect();
private:
tools::Rectangle impl_getScaledRect_nothrow() const;
// XStateChangeListener
virtual void SAL_CALL changingState( const css::lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
virtual void SAL_CALL stateChanged( const css::lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
virtual void SAL_CALL disposing( const css::lang::EventObject& aEvent ) override;
// document::XEventListener
virtual void SAL_CALL notifyEvent( const document::EventObject& aEvent ) override;
// XEmbeddedClient
virtual void SAL_CALL saveObject() override;
virtual void SAL_CALL visibilityChanged( sal_Bool bVisible ) override;
// XComponentSupplier
virtual uno::Reference< util::XCloseable > SAL_CALL getComponent() override;
// XInplaceClient
virtual sal_Bool SAL_CALL canInplaceActivate() override;
virtual void SAL_CALL activatingInplace() override;
virtual void SAL_CALL activatingUI() override;
virtual void SAL_CALL deactivatedInplace() override;
virtual void SAL_CALL deactivatedUI() override;
virtual uno::Reference< css::frame::XLayoutManager > SAL_CALL getLayoutManager() override;
virtual uno::Reference< frame::XDispatchProvider > SAL_CALL getInplaceDispatchProvider() override;
virtual awt::Rectangle SAL_CALL getPlacement() override;
virtual awt::Rectangle SAL_CALL getClipRectangle() override;
virtual void SAL_CALL translateAccelerators( const uno::Sequence< awt::KeyEvent >& aKeys ) override;
virtual void SAL_CALL scrollObject( const awt::Size& aOffset ) override;
virtual void SAL_CALL changedPlacement( const awt::Rectangle& aPosRect ) override;
// XWindowSupplier
virtual uno::Reference< awt::XWindow > SAL_CALL getWindow() override;
};
}
SdrLightEmbeddedClient_Impl::SdrLightEmbeddedClient_Impl( SdrOle2Obj* pObj )
: mpObj( pObj )
{
}
SdrLightEmbeddedClient_Impl::~SdrLightEmbeddedClient_Impl()
{
assert(!mpObj);
}
tools::Rectangle SdrLightEmbeddedClient_Impl::impl_getScaledRect_nothrow() const
{
tools::Rectangle aLogicRect( mpObj->GetLogicRect() );
// apply scaling to object area and convert to pixels
aLogicRect.SetSize( Size( long( aLogicRect.GetWidth() * m_aScaleWidth),
long( aLogicRect.GetHeight() * m_aScaleHeight) ) );
return aLogicRect;
}
void SAL_CALL SdrLightEmbeddedClient_Impl::changingState( const css::lang::EventObject& /*aEvent*/, ::sal_Int32 /*nOldState*/, ::sal_Int32 /*nNewState*/ )
{
}
void SAL_CALL SdrLightEmbeddedClient_Impl::stateChanged( const css::lang::EventObject& /*aEvent*/, ::sal_Int32 nOldState, ::sal_Int32 nNewState )
{
SolarMutexGuard aGuard;
if ( mpObj && nOldState == embed::EmbedStates::LOADED && nNewState == embed::EmbedStates::RUNNING )
{
mpObj->ObjectLoaded();
GetSdrGlobalData().GetOLEObjCache().InsertObj(mpObj);
}
else if ( mpObj && nNewState == embed::EmbedStates::LOADED && nOldState == embed::EmbedStates::RUNNING )
{
GetSdrGlobalData().GetOLEObjCache().RemoveObj(mpObj);
}
}
void SdrLightEmbeddedClient_Impl::disconnect()
{
SolarMutexGuard aGuard;
if (!mpObj)
return;
GetSdrGlobalData().GetOLEObjCache().RemoveObj(mpObj);
mpObj = nullptr;
}
void SAL_CALL SdrLightEmbeddedClient_Impl::disposing( const css::lang::EventObject& /*aEvent*/ )
{
disconnect();
}
void SAL_CALL SdrLightEmbeddedClient_Impl::notifyEvent( const document::EventObject& aEvent )
{
// TODO/LATER: when writer uses this implementation the code could be shared with SfxInPlaceClient_Impl
SolarMutexGuard aGuard;
// the code currently makes sense only in case there is no other client
if ( mpObj && mpObj->GetAspect() != embed::Aspects::MSOLE_ICON && aEvent.EventName == "OnVisAreaChanged"
&& mpObj->GetObjRef().is() && mpObj->GetObjRef()->getClientSite() == uno::Reference< embed::XEmbeddedClient >( this ) )
{
try
{
MapUnit aContainerMapUnit( MapUnit::Map100thMM );
uno::Reference< embed::XVisualObject > xParentVis( mpObj->GetParentXModel(), uno::UNO_QUERY );
if ( xParentVis.is() )
aContainerMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xParentVis->getMapUnit( mpObj->GetAspect() ) );
MapUnit aObjMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( mpObj->GetObjRef()->getMapUnit( mpObj->GetAspect() ) );
tools::Rectangle aVisArea;
awt::Size aSz;
try
{
aSz = mpObj->GetObjRef()->getVisualAreaSize( mpObj->GetAspect() );
}
catch( embed::NoVisualAreaSizeException& )
{
OSL_FAIL( "No visual area size!" );
aSz.Width = 5000;
aSz.Height = 5000;
}
catch( uno::Exception& )
{
OSL_FAIL( "Unexpected exception!" );
aSz.Width = 5000;
aSz.Height = 5000;
}
aVisArea.SetSize( Size( aSz.Width, aSz.Height ) );
aVisArea = OutputDevice::LogicToLogic(aVisArea, MapMode(aObjMapUnit), MapMode(aContainerMapUnit));
Size aScaledSize( static_cast< long >( m_aScaleWidth * Fraction( aVisArea.GetWidth() ) ),
static_cast< long >( m_aScaleHeight * Fraction( aVisArea.GetHeight() ) ) );
tools::Rectangle aLogicRect( mpObj->GetLogicRect() );
// react to the change if the difference is bigger than one pixel
Size aPixelDiff =
Application::GetDefaultDevice()->LogicToPixel(
Size( aLogicRect.GetWidth() - aScaledSize.Width(),
aLogicRect.GetHeight() - aScaledSize.Height() ),
MapMode(aContainerMapUnit));
if( aPixelDiff.Width() || aPixelDiff.Height() )
{
mpObj->SetLogicRect( tools::Rectangle( aLogicRect.TopLeft(), aScaledSize ) );
mpObj->BroadcastObjectChange();
}
else
mpObj->ActionChanged();
}
catch( uno::Exception& )
{
OSL_FAIL( "Unexpected exception!" );
}
}
}
void SAL_CALL SdrLightEmbeddedClient_Impl::saveObject()
{
// TODO/LATER: when writer uses this implementation the code could be shared with SfxInPlaceClient_Impl
uno::Reference< embed::XCommonEmbedPersist > xPersist;
uno::Reference< util::XModifiable > xModifiable;
{
SolarMutexGuard aGuard;
if ( !mpObj )
throw embed::ObjectSaveVetoException();
// the common persistence is supported by objects and links
xPersist.set( mpObj->GetObjRef(), uno::UNO_QUERY_THROW );
xModifiable.set( mpObj->GetParentXModel(), uno::UNO_QUERY );
}
xPersist->storeOwn();
if ( xModifiable.is() )
xModifiable->setModified( true );
}
void SAL_CALL SdrLightEmbeddedClient_Impl::visibilityChanged( sal_Bool /*bVisible*/ )
{
// nothing to do currently
// TODO/LATER: when writer uses this implementation the code could be shared with SfxInPlaceClient_Impl
if ( mpObj )
{
tools::Rectangle aLogicRect( mpObj->GetLogicRect() );
Size aLogicSize( aLogicRect.GetWidth(), aLogicRect.GetHeight() );
if( mpObj->IsChart() )
{
//charts never should be stretched see #i84323# for example
mpObj->SetLogicRect( tools::Rectangle( aLogicRect.TopLeft(), aLogicSize ) );
mpObj->BroadcastObjectChange();
} // if( mpObj->IsChart() )
}
}
uno::Reference< util::XCloseable > SAL_CALL SdrLightEmbeddedClient_Impl::getComponent()
{
uno::Reference< util::XCloseable > xResult;
SolarMutexGuard aGuard;
if ( mpObj )
xResult.set( mpObj->GetParentXModel(), uno::UNO_QUERY );
return xResult;
}
// XInplaceClient
sal_Bool SAL_CALL SdrLightEmbeddedClient_Impl::canInplaceActivate()
{
bool bRet = false;
SolarMutexGuard aGuard;
if ( mpObj )
{
uno::Reference< embed::XEmbeddedObject > xObject = mpObj->GetObjRef();
if ( !xObject.is() )
throw uno::RuntimeException();
// we don't want to switch directly from outplace to inplace mode
bRet = !( xObject->getCurrentState() == embed::EmbedStates::ACTIVE || mpObj->GetAspect() == embed::Aspects::MSOLE_ICON );
} // if ( mpObj )
return bRet;
}
void SAL_CALL SdrLightEmbeddedClient_Impl::activatingInplace()
{
}
void SAL_CALL SdrLightEmbeddedClient_Impl::activatingUI()
{
SolarMutexGuard aGuard;
uno::Reference < beans::XPropertySet > xFrame( lcl_getFrame_throw(mpObj));
uno::Reference < frame::XFrame > xOwnFrame( xFrame,uno::UNO_QUERY);
uno::Reference < frame::XFramesSupplier > xParentFrame = xOwnFrame->getCreator();
if ( xParentFrame.is() )
xParentFrame->setActiveFrame( xOwnFrame );
OLEObjCache& rObjCache = GetSdrGlobalData().GetOLEObjCache();
const sal_uIntPtr nCount = rObjCache.size();
for(sal_Int32 i = nCount-1 ; i >= 0;--i)
{
SdrOle2Obj* pObj = rObjCache[i];
if ( pObj != mpObj )
{
// only deactivate ole objects which belongs to the same frame
if ( xFrame == lcl_getFrame_throw(pObj) )
{
const uno::Reference< embed::XEmbeddedObject >& xObject = pObj->GetObjRef();
try
{
if ( xObject->getStatus( pObj->GetAspect() ) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE )
xObject->changeState( embed::EmbedStates::INPLACE_ACTIVE );
else
{
// the links should not stay in running state for long time because of locking
uno::Reference< embed::XLinkageSupport > xLink( xObject, uno::UNO_QUERY );
if ( xLink.is() && xLink->isLink() )
xObject->changeState( embed::EmbedStates::LOADED );
else
xObject->changeState( embed::EmbedStates::RUNNING );
}
}
catch (css::uno::Exception& )
{}
}
}
} // for(sal_Int32 i = nCount-1 ; i >= 0;--i)
}
void SAL_CALL SdrLightEmbeddedClient_Impl::deactivatedInplace()
{
}
void SAL_CALL SdrLightEmbeddedClient_Impl::deactivatedUI()
{
SolarMutexGuard aGuard;
css::uno::Reference< css::frame::XLayoutManager > xLayoutManager(getLayoutManager());
if ( xLayoutManager.is() )
{
static const char aMenuBarURL[] = "private:resource/menubar/menubar";
if ( !xLayoutManager->isElementVisible( aMenuBarURL ) )
xLayoutManager->createElement( aMenuBarURL );
}
}
uno::Reference< css::frame::XLayoutManager > SAL_CALL SdrLightEmbeddedClient_Impl::getLayoutManager()
{
uno::Reference< css::frame::XLayoutManager > xMan;
SolarMutexGuard aGuard;
uno::Reference < beans::XPropertySet > xFrame( lcl_getFrame_throw(mpObj));
try
{
xMan.set(xFrame->getPropertyValue("LayoutManager"),uno::UNO_QUERY);
}
catch ( uno::Exception& ex )
{
css::uno::Any anyEx = cppu::getCaughtException();
throw css::lang::WrappedTargetRuntimeException( ex.Message,
nullptr, anyEx );
}
return xMan;
}
uno::Reference< frame::XDispatchProvider > SAL_CALL SdrLightEmbeddedClient_Impl::getInplaceDispatchProvider()
{
SolarMutexGuard aGuard;
return uno::Reference < frame::XDispatchProvider >( lcl_getFrame_throw(mpObj), uno::UNO_QUERY_THROW );
}
awt::Rectangle SAL_CALL SdrLightEmbeddedClient_Impl::getPlacement()
{
SolarMutexGuard aGuard;
if ( !mpObj )
throw uno::RuntimeException();
tools::Rectangle aLogicRect = impl_getScaledRect_nothrow();
MapUnit aContainerMapUnit( MapUnit::Map100thMM );
uno::Reference< embed::XVisualObject > xParentVis( mpObj->GetParentXModel(), uno::UNO_QUERY );
if ( xParentVis.is() )
aContainerMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xParentVis->getMapUnit( mpObj->GetAspect() ) );
aLogicRect = Application::GetDefaultDevice()->LogicToPixel(aLogicRect, MapMode(aContainerMapUnit));
return AWTRectangle( aLogicRect );
}
awt::Rectangle SAL_CALL SdrLightEmbeddedClient_Impl::getClipRectangle()
{
return getPlacement();
}
void SAL_CALL SdrLightEmbeddedClient_Impl::translateAccelerators( const uno::Sequence< awt::KeyEvent >& /*aKeys*/ )
{
}
void SAL_CALL SdrLightEmbeddedClient_Impl::scrollObject( const awt::Size& /*aOffset*/ )
{
}
void SAL_CALL SdrLightEmbeddedClient_Impl::changedPlacement( const awt::Rectangle& aPosRect )
{
SolarMutexGuard aGuard;
if ( !mpObj )
throw uno::RuntimeException();
uno::Reference< embed::XInplaceObject > xInplace( mpObj->GetObjRef(), uno::UNO_QUERY_THROW );
// check if the change is at least one pixel in size
awt::Rectangle aOldRect = getPlacement();
tools::Rectangle aNewPixelRect = VCLRectangle( aPosRect );
tools::Rectangle aOldPixelRect = VCLRectangle( aOldRect );
if ( aOldPixelRect == aNewPixelRect )
// nothing has changed
return;
// new scaled object area
MapUnit aContainerMapUnit( MapUnit::Map100thMM );
uno::Reference< embed::XVisualObject > xParentVis( mpObj->GetParentXModel(), uno::UNO_QUERY );
if ( xParentVis.is() )
aContainerMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xParentVis->getMapUnit( mpObj->GetAspect() ) );
tools::Rectangle aNewLogicRect = Application::GetDefaultDevice()->PixelToLogic(aNewPixelRect, MapMode(aContainerMapUnit));
tools::Rectangle aLogicRect = impl_getScaledRect_nothrow();
if ( aNewLogicRect != aLogicRect )
{
// the calculation of the object area has not changed the object size
// it should be done here then
//SfxBooleanFlagGuard aGuard( m_bResizeNoScale, true );
// new size of the object area without scaling
Size aNewObjSize( long( aNewLogicRect.GetWidth() / m_aScaleWidth ),
long( aNewLogicRect.GetHeight() / m_aScaleHeight ) );
// now remove scaling from new placement and keep this at the new object area
aNewLogicRect.SetSize( aNewObjSize );
// react to the change if the difference is bigger than one pixel
Size aPixelDiff =
Application::GetDefaultDevice()->LogicToPixel(
Size( aLogicRect.GetWidth() - aNewObjSize.Width(),
aLogicRect.GetHeight() - aNewObjSize.Height() ),
MapMode(aContainerMapUnit));
if( aPixelDiff.Width() || aPixelDiff.Height() )
{
mpObj->SetLogicRect( tools::Rectangle( aLogicRect.TopLeft(), aNewObjSize ) );
mpObj->BroadcastObjectChange();
}
else
mpObj->ActionChanged();
}
}
// XWindowSupplier
uno::Reference< awt::XWindow > SAL_CALL SdrLightEmbeddedClient_Impl::getWindow()
{
SolarMutexGuard aGuard;
uno::Reference< awt::XWindow > xCurrent = m_xWindow;
if ( !xCurrent.is() )
{
if ( !mpObj )
throw uno::RuntimeException();
uno::Reference< frame::XFrame> xFrame(lcl_getFrame_throw(mpObj),uno::UNO_QUERY_THROW);
xCurrent = xFrame->getComponentWindow();
} // if ( !xCurrent.is() )
return xCurrent;
}
void SdrLightEmbeddedClient_Impl::setWindow(const uno::Reference< awt::XWindow >& _xWindow)
{
m_xWindow = _xWindow;
}
SdrEmbedObjectLink::SdrEmbedObjectLink(SdrOle2Obj* pObject):
::sfx2::SvBaseLink( ::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB ),
pObj(pObject)
{
SetSynchron( false );
}
SdrEmbedObjectLink::~SdrEmbedObjectLink()
{
}
::sfx2::SvBaseLink::UpdateResult SdrEmbedObjectLink::DataChanged(
const OUString& /*rMimeType*/, const css::uno::Any & /*rValue*/ )
{
if ( !pObj->UpdateLinkURL_Impl() )
{
// the link URL was not changed
uno::Reference< embed::XEmbeddedObject > xObject = pObj->GetObjRef();
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 ( uno::Exception& )
{
}
}
}
pObj->GetNewReplacement();
pObj->SetChanged();
return SUCCESS;
}
void SdrEmbedObjectLink::Closed()
{
pObj->BreakFileLink_Impl();
SvBaseLink::Closed();
}
class SdrOle2ObjImpl
{
public:
svt::EmbeddedObjectRef mxObjRef;
std::unique_ptr<Graphic> mxGraphic;
OUString maProgName;
OUString aPersistName; // name of object in persist
rtl::Reference<SdrLightEmbeddedClient_Impl> mxLightClient; // must be registered as client only using AddOwnLightClient() call
bool mbFrame:1; // Due to compatibility at SdrTextObj for now
bool mbSuppressSetVisAreaSize:1; // #i118524#
mutable bool mbTypeAsked:1;
mutable bool mbIsChart:1;
bool mbLoadingOLEObjectFailed:1; // New local var to avoid repeated loading if load of OLE2 fails
bool mbConnected:1;
SdrEmbedObjectLink* mpObjectLink;
OUString maLinkURL;
rtl::Reference<SvxUnoShapeModifyListener> mxModifyListener;
explicit SdrOle2ObjImpl( bool bFrame ) :
mbFrame(bFrame),
mbSuppressSetVisAreaSize(false),
mbTypeAsked(false),
mbIsChart(false),
mbLoadingOLEObjectFailed(false),
mbConnected(false),
mpObjectLink(nullptr)
{
mxObjRef.Lock();
}
SdrOle2ObjImpl( bool bFrame, const svt::EmbeddedObjectRef& rObjRef ) :
mxObjRef(rObjRef),
mbFrame(bFrame),
mbSuppressSetVisAreaSize(false),
mbTypeAsked(false),
mbIsChart(false),
mbLoadingOLEObjectFailed(false),
mbConnected(false),
mpObjectLink(nullptr)
{
mxObjRef.Lock();
}
~SdrOle2ObjImpl()
{
mxGraphic.reset();
if (mxModifyListener.is())
{
mxModifyListener->invalidate();
}
}
};
// Predicate determining whether the given OLE is an internal math
// object
static bool ImplIsMathObj( const uno::Reference < embed::XEmbeddedObject >& rObjRef )
{
if ( !rObjRef.is() )
return false;
SvGlobalName aClassName( rObjRef->getClassID() );
return aClassName == SvGlobalName(SO3_SM_CLASSID_30) ||
aClassName == SvGlobalName(SO3_SM_CLASSID_40) ||
aClassName == SvGlobalName(SO3_SM_CLASSID_50) ||
aClassName == SvGlobalName(SO3_SM_CLASSID_60) ||
aClassName == SvGlobalName(SO3_SM_CLASSID);
}
// BaseProperties section
std::unique_ptr<sdr::properties::BaseProperties> SdrOle2Obj::CreateObjectSpecificProperties()
{
return std::make_unique<sdr::properties::OleProperties>(*this);
}
// DrawContact section
std::unique_ptr<sdr::contact::ViewContact> SdrOle2Obj::CreateObjectSpecificViewContact()
{
return std::make_unique<sdr::contact::ViewContactOfSdrOle2Obj>(*this);
}
void SdrOle2Obj::Init()
{
// Stuff that was done from old SetModel:
// #i43086# #i85304 redo the change for charts for the above bugfix, as #i43086# does not occur anymore
// so maybe the ImpSetVisAreaSize call can be removed here completely
// Nevertheless I leave it in for other objects as I am not sure about the side effects when removing now
if(!getSdrModelFromSdrObject().isLocked() && !IsChart())
{
ImpSetVisAreaSize();
}
::comphelper::IEmbeddedHelper* pDestPers(getSdrModelFromSdrObject().GetPersist());
if(pDestPers && !IsEmptyPresObj())
{
// object wasn't connected, now it should be
Connect_Impl();
}
AddListeners_Impl();
}
SdrOle2Obj::SdrOle2Obj(
SdrModel& rSdrModel,
bool bFrame_)
: SdrRectObj(rSdrModel),
mpImpl(new SdrOle2ObjImpl(bFrame_))
{
Init();
}
SdrOle2Obj::SdrOle2Obj(
SdrModel& rSdrModel,
const svt::EmbeddedObjectRef& rNewObjRef,
const OUString& rNewObjName,
const tools::Rectangle& rNewRect)
: SdrRectObj(rSdrModel, rNewRect),
mpImpl(new SdrOle2ObjImpl(false/*bFrame_*/, rNewObjRef))
{
mpImpl->aPersistName = rNewObjName;
if (mpImpl->mxObjRef.is() && (mpImpl->mxObjRef->getStatus( GetAspect() ) & embed::EmbedMisc::EMBED_NEVERRESIZE ) )
SetResizeProtect(true);
// For math objects, set closed state to transparent
SetClosedObj(!ImplIsMathObj( mpImpl->mxObjRef.GetObject() ));
Init();
}
OUString SdrOle2Obj::GetStyleString()
{
OUString strStyle;
if (mpImpl->mxObjRef.is() && mpImpl->mxObjRef.IsChart())
{
strStyle = mpImpl->mxObjRef.GetChartType();
}
return strStyle;
}
SdrOle2Obj::~SdrOle2Obj()
{
if ( mpImpl->mbConnected )
Disconnect();
DisconnectFileLink_Impl();
if (mpImpl->mxLightClient)
{
mpImpl->mxLightClient->disconnect();
mpImpl->mxLightClient.clear();
}
}
void SdrOle2Obj::SetAspect( sal_Int64 nAspect )
{
mpImpl->mxObjRef.SetViewAspect( nAspect );
}
const svt::EmbeddedObjectRef& SdrOle2Obj::getEmbeddedObjectRef() const
{
return mpImpl->mxObjRef;
}
sal_Int64 SdrOle2Obj::GetAspect() const
{
return mpImpl->mxObjRef.GetViewAspect();
}
bool SdrOle2Obj::isInplaceActive() const
{
return mpImpl->mxObjRef.is() && embed::EmbedStates::INPLACE_ACTIVE == mpImpl->mxObjRef->getCurrentState();
}
bool SdrOle2Obj::isUiActive() const
{
return mpImpl->mxObjRef.is() && embed::EmbedStates::UI_ACTIVE == mpImpl->mxObjRef->getCurrentState();
}
void SdrOle2Obj::SetGraphic(const Graphic& rGrf)
{
// only for setting a preview graphic
mpImpl->mxGraphic.reset(new Graphic(rGrf));
SetChanged();
BroadcastObjectChange();
}
void SdrOle2Obj::ClearGraphic()
{
mpImpl->mxGraphic.reset();
SetChanged();
BroadcastObjectChange();
}
void SdrOle2Obj::SetProgName( const OUString& rName )
{
mpImpl->maProgName = rName;
}
const OUString& SdrOle2Obj::GetProgName() const
{
return mpImpl->maProgName;
}
bool SdrOle2Obj::IsEmpty() const
{
return !mpImpl->mxObjRef.is();
}
void SdrOle2Obj::Connect()
{
if( IsEmptyPresObj() )
return;
if( mpImpl->mbConnected )
{
// currently there are situations where it seems to be unavoidable to have multiple connects
// changing this would need a larger code rewrite, so for now I remove the assertion
// OSL_FAIL("Connect() called on connected object!");
return;
}
Connect_Impl();
AddListeners_Impl();
}
bool SdrOle2Obj::UpdateLinkURL_Impl()
{
bool bResult = false;
if ( mpImpl->mpObjectLink )
{
sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
if ( pLinkManager )
{
OUString aNewLinkURL;
sfx2::LinkManager::GetDisplayNames( mpImpl->mpObjectLink, nullptr, &aNewLinkURL );
if ( !aNewLinkURL.equalsIgnoreAsciiCase( mpImpl->maLinkURL ) )
{
GetObjRef_Impl();
uno::Reference<embed::XCommonEmbedPersist> xPersObj( mpImpl->mxObjRef.GetObject(), uno::UNO_QUERY );
OSL_ENSURE( xPersObj.is(), "The object must exist!" );
if ( xPersObj.is() )
{
try
{
sal_Int32 nCurState = mpImpl->mxObjRef->getCurrentState();
if ( nCurState != embed::EmbedStates::LOADED )
mpImpl->mxObjRef->changeState(embed::EmbedStates::LOADED);
// TODO/LATER: there should be possible to get current mediadescriptor settings from the object
uno::Sequence< beans::PropertyValue > aArgs( 1 );
aArgs[0].Name = "URL";
aArgs[0].Value <<= aNewLinkURL;
xPersObj->reload( aArgs, uno::Sequence< beans::PropertyValue >() );
mpImpl->maLinkURL = aNewLinkURL;
bResult = true;
if ( nCurState != embed::EmbedStates::LOADED )
mpImpl->mxObjRef->changeState(nCurState);
}
catch( css::uno::Exception const & )
{
TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::UpdateLinkURL_Impl()" );
}
}
if ( !bResult )
{
// TODO/LATER: return the old name to the link manager, is it possible?
}
}
}
}
return bResult;
}
void SdrOle2Obj::BreakFileLink_Impl()
{
uno::Reference<document::XStorageBasedDocument> xDoc(getSdrModelFromSdrObject().getUnoModel(), uno::UNO_QUERY);
if ( xDoc.is() )
{
uno::Reference< embed::XStorage > xStorage = xDoc->getDocumentStorage();
if ( xStorage.is() )
{
try
{
uno::Reference< embed::XLinkageSupport > xLinkSupport( mpImpl->mxObjRef.GetObject(), uno::UNO_QUERY_THROW );
xLinkSupport->breakLink( xStorage, mpImpl->aPersistName );
DisconnectFileLink_Impl();
mpImpl->maLinkURL.clear();
}
catch( css::uno::Exception& )
{
TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::BreakFileLink_Impl()" );
}
}
}
}
void SdrOle2Obj::DisconnectFileLink_Impl()
{
sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
if ( pLinkManager && mpImpl->mpObjectLink )
{
pLinkManager->Remove( mpImpl->mpObjectLink );
mpImpl->mpObjectLink = nullptr;
}
}
void SdrOle2Obj::CheckFileLink_Impl()
{
if (mpImpl->mxObjRef.GetObject().is() && !mpImpl->mpObjectLink)
{
try
{
uno::Reference< embed::XLinkageSupport > xLinkSupport( mpImpl->mxObjRef.GetObject(), uno::UNO_QUERY );
if ( xLinkSupport.is() && xLinkSupport->isLink() )
{
OUString aLinkURL = xLinkSupport->getLinkURL();
if ( !aLinkURL.isEmpty() )
{
// this is a file link so the model link manager should handle it
sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
if ( pLinkManager )
{
mpImpl->mpObjectLink = new SdrEmbedObjectLink( this );
mpImpl->maLinkURL = aLinkURL;
pLinkManager->InsertFileLink( *mpImpl->mpObjectLink, OBJECT_CLIENT_OLE, aLinkURL );
mpImpl->mpObjectLink->Connect();
}
}
}
}
catch (const css::uno::Exception&)
{
TOOLS_WARN_EXCEPTION("svx", "SdrOle2Obj::CheckFileLink_Impl()");
}
}
}
void SdrOle2Obj::Connect_Impl()
{
if(!mpImpl->aPersistName.isEmpty() )
{
try
{
::comphelper::IEmbeddedHelper* pPers(getSdrModelFromSdrObject().GetPersist());
if ( pPers )
{
comphelper::EmbeddedObjectContainer& rContainer = pPers->getEmbeddedObjectContainer();
if ( !rContainer.HasEmbeddedObject( mpImpl->aPersistName )
|| ( mpImpl->mxObjRef.is() && !rContainer.HasEmbeddedObject( mpImpl->mxObjRef.GetObject() ) ) )
{
// object not known to container document
// No object -> disaster!
DBG_ASSERT( mpImpl->mxObjRef.is(), "No object in connect!");
if ( mpImpl->mxObjRef.is() )
{
// object came from the outside, now add it to the container
OUString aTmp;
rContainer.InsertEmbeddedObject( mpImpl->mxObjRef.GetObject(), aTmp );
mpImpl->aPersistName = aTmp;
}
}
else if ( !mpImpl->mxObjRef.is() )
{
mpImpl->mxObjRef.Assign( rContainer.GetEmbeddedObject( mpImpl->aPersistName ), mpImpl->mxObjRef.GetViewAspect() );
mpImpl->mbTypeAsked = false;
}
if ( mpImpl->mxObjRef.GetObject().is() )
{
mpImpl->mxObjRef.AssignToContainer( &rContainer, mpImpl->aPersistName );
mpImpl->mbConnected = true;
mpImpl->mxObjRef.Lock();
}
}
if ( mpImpl->mxObjRef.is() )
{
if ( !mpImpl->mxLightClient.is() )
mpImpl->mxLightClient = new SdrLightEmbeddedClient_Impl( this );
mpImpl->mxObjRef->addStateChangeListener( mpImpl->mxLightClient.get() );
mpImpl->mxObjRef->addEventListener( uno::Reference< document::XEventListener >( mpImpl->mxLightClient.get() ) );
if ( mpImpl->mxObjRef->getCurrentState() != embed::EmbedStates::LOADED )
GetSdrGlobalData().GetOLEObjCache().InsertObj(this);
CheckFileLink_Impl();
uno::Reference< container::XChild > xChild( mpImpl->mxObjRef.GetObject(), uno::UNO_QUERY );
if( xChild.is() )
{
uno::Reference< uno::XInterface > xParent( getSdrModelFromSdrObject().getUnoModel());
if( xParent.is())
xChild->setParent( getSdrModelFromSdrObject().getUnoModel() );
}
}
}
catch( css::uno::Exception& )
{
TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::Connect_Impl()" );
}
}
}
void SdrOle2Obj::ObjectLoaded()
{
AddListeners_Impl();
}
void SdrOle2Obj::AddListeners_Impl()
{
if( mpImpl->mxObjRef.is() && mpImpl->mxObjRef->getCurrentState() != embed::EmbedStates::LOADED )
{
// register modify listener
if (!mpImpl->mxModifyListener.is())
{
mpImpl->mxModifyListener = new SvxUnoShapeModifyListener(this);
}
uno::Reference< util::XModifyBroadcaster > xBC( getXModel(), uno::UNO_QUERY );
if (xBC.is())
{
uno::Reference<util::XModifyListener> xListener(mpImpl->mxModifyListener.get());
xBC->addModifyListener( xListener );
}
}
}
void SdrOle2Obj::Disconnect()
{
if( IsEmptyPresObj() )
return;
if( !mpImpl->mbConnected )
{
OSL_FAIL("Disconnect() called on disconnected object!");
return;
}
RemoveListeners_Impl();
Disconnect_Impl();
}
void SdrOle2Obj::RemoveListeners_Impl()
{
if ( mpImpl->mxObjRef.is() && !mpImpl->aPersistName.isEmpty() )
{
try
{
sal_Int32 nState = mpImpl->mxObjRef->getCurrentState();
if ( nState != embed::EmbedStates::LOADED )
{
uno::Reference< util::XModifyBroadcaster > xBC( getXModel(), uno::UNO_QUERY );
if (xBC.is() && mpImpl->mxModifyListener.is())
{
uno::Reference<util::XModifyListener> xListener(mpImpl->mxModifyListener.get());
xBC->removeModifyListener( xListener );
}
}
}
catch( css::uno::Exception& )
{
TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::RemoveListeners_Impl()" );
}
}
}
void SdrOle2Obj::Disconnect_Impl()
{
try
{
if ( !mpImpl->aPersistName.isEmpty() )
{
if( getSdrModelFromSdrObject().IsInDestruction() )
{
// TODO/LATER: here we must assume that the destruction of the model is enough to make clear that we will not
// remove the object from the container, even if the DrawingObject itself is not destroyed (unfortunately this
// There is no real need to do the following removing of the object from the container
// in case the model has correct persistence, but in case of problems such a removing
// would make the behavior of the office more stable
comphelper::EmbeddedObjectContainer* pContainer = mpImpl->mxObjRef.GetContainer();
if ( pContainer )
{
pContainer->CloseEmbeddedObject( mpImpl->mxObjRef.GetObject() );
mpImpl->mxObjRef.AssignToContainer( nullptr, mpImpl->aPersistName );
}
// happens later than the destruction of the model, so we can't assert that).
//DBG_ASSERT( bInDestruction, "Model is destroyed, but not me?!" );
//TODO/LATER: should be make sure that the ObjectShell also forgets the object, because we will close it soon?
/*
uno::Reference < util::XCloseable > xClose( xObjRef, uno::UNO_QUERY );
if ( xClose.is() )
{
try
{
xClose->close( true );
}
catch ( util::CloseVetoException& )
{
// there's still someone who needs the object!
}
}
xObjRef = NULL;*/
}
else if ( mpImpl->mxObjRef.is() )
{
if ( getSdrModelFromSdrObject().getUnoModel().is() )
{
// remove object, but don't close it (that's up to someone else)
comphelper::EmbeddedObjectContainer* pContainer = mpImpl->mxObjRef.GetContainer();
if ( pContainer )
{
pContainer->RemoveEmbeddedObject( mpImpl->mxObjRef.GetObject() );
// TODO/LATER: mpImpl->aPersistName contains outdated information, to keep it updated
// it should be returned from RemoveEmbeddedObject call. Currently it is no problem,
// since no container is adjusted, actually the empty string could be provided as a name here
mpImpl->mxObjRef.AssignToContainer( nullptr, mpImpl->aPersistName );
}
DisconnectFileLink_Impl();
}
}
}
if ( mpImpl->mxObjRef.is() && mpImpl->mxLightClient.is() )
{
mpImpl->mxObjRef->removeStateChangeListener ( mpImpl->mxLightClient.get() );
mpImpl->mxObjRef->removeEventListener( uno::Reference< document::XEventListener >( mpImpl->mxLightClient.get() ) );
mpImpl->mxObjRef->setClientSite( nullptr );
GetSdrGlobalData().GetOLEObjCache().RemoveObj(this);
}
}
catch( css::uno::Exception& )
{
TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::Disconnect_Impl()" );
}
mpImpl->mbConnected = false;
}
SdrObjectUniquePtr SdrOle2Obj::createSdrGrafObjReplacement(bool bAddText) const
{
const Graphic* pOLEGraphic = GetGraphic();
if(pOLEGraphic)
{
// #i118485# allow creating a SdrGrafObj representation
SdrGrafObj* pClone = new SdrGrafObj(
getSdrModelFromSdrObject(),
*pOLEGraphic);
// copy transformation
basegfx::B2DHomMatrix aMatrix;
basegfx::B2DPolyPolygon aPolyPolygon;
TRGetBaseGeometry(aMatrix, aPolyPolygon);
pClone->TRSetBaseGeometry(aMatrix, aPolyPolygon);
// copy all attributes to support graphic styles for OLEs
pClone->SetStyleSheet(GetStyleSheet(), false);
pClone->SetMergedItemSet(GetMergedItemSet());
if(bAddText)
{
// #i118485# copy text (Caution! Model needed, as guaranteed in aw080)
OutlinerParaObject* pOPO = GetOutlinerParaObject();
if(pOPO)
{
pClone->NbcSetOutlinerParaObject(std::make_unique<OutlinerParaObject>(*pOPO));
}
}
return SdrObjectUniquePtr(pClone);
}
else
{
// #i100710# pOLEGraphic may be zero (no visualisation available),
// so we need to use the OLE replacement graphic
SdrRectObj* pClone = new SdrRectObj(
getSdrModelFromSdrObject(),
GetSnapRect());
// gray outline
pClone->SetMergedItem(XLineStyleItem(css::drawing::LineStyle_SOLID));
const svtools::ColorConfig aColorConfig;
const svtools::ColorConfigValue aColor(aColorConfig.GetColorValue(svtools::OBJECTBOUNDARIES));
pClone->SetMergedItem(XLineColorItem(OUString(), aColor.nColor));
// bitmap fill
pClone->SetMergedItem(XFillStyleItem(drawing::FillStyle_BITMAP));
pClone->SetMergedItem(XFillBitmapItem(OUString(), GetEmptyOLEReplacementGraphic()));
pClone->SetMergedItem(XFillBmpTileItem(false));
pClone->SetMergedItem(XFillBmpStretchItem(false));
return SdrObjectUniquePtr(pClone);
}
}
SdrObjectUniquePtr SdrOle2Obj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
{
// #i118485# missing converter added
SdrObjectUniquePtr pRetval = createSdrGrafObjReplacement(true);
if(pRetval)
{
return pRetval->DoConvertToPolyObj(bBezier, bAddText);
}
return nullptr;
}
void SdrOle2Obj::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
{
const bool bRemove(pNewPage == nullptr && pOldPage != nullptr);
const bool bInsert(pNewPage != nullptr && pOldPage == nullptr);
if (bRemove && mpImpl->mbConnected )
{
Disconnect();
}
// call parent
SdrRectObj::handlePageChange(pOldPage, pNewPage);
if (bInsert && !mpImpl->mbConnected )
{
Connect();
}
}
void SdrOle2Obj::SetObjRef( const css::uno::Reference < css::embed::XEmbeddedObject >& rNewObjRef )
{
DBG_ASSERT( !rNewObjRef.is() || !mpImpl->mxObjRef.GetObject().is(), "SetObjRef called on already initialized object!");
if( rNewObjRef == mpImpl->mxObjRef.GetObject() )
return;
// the caller of the method is responsible to control the old object, it will not be closed here
// Otherwise WW8 import crashes because it transfers control to OLENode by this method
if ( mpImpl->mxObjRef.GetObject().is() )
mpImpl->mxObjRef.Lock( false );
// avoid removal of object in Disconnect! It is definitely a HACK to call SetObjRef(0)!
// This call will try to close the objects; so if anybody else wants to keep it, it must be locked by a CloseListener
mpImpl->mxObjRef.Clear();
if ( mpImpl->mbConnected )
Disconnect();
mpImpl->mxObjRef.Assign( rNewObjRef, GetAspect() );
mpImpl->mbTypeAsked = false;
if ( mpImpl->mxObjRef.is() )
{
mpImpl->mxGraphic.reset();
if ( mpImpl->mxObjRef->getStatus( GetAspect() ) & embed::EmbedMisc::EMBED_NEVERRESIZE )
SetResizeProtect(true);
// For math objects, set closed state to transparent
SetClosedObj(!ImplIsMathObj( rNewObjRef ));
Connect();
}
SetChanged();
BroadcastObjectChange();
}
void SdrOle2Obj::SetClosedObj( bool bIsClosed )
{
// TODO/LATER: do we still need this hack?
// Allow changes to the closed state of OLE objects
bClosedObj = bIsClosed;
}
SdrObjectUniquePtr SdrOle2Obj::getFullDragClone() const
{
// #i118485# use central replacement generator
return createSdrGrafObjReplacement(false);
}
void SdrOle2Obj::SetPersistName( const OUString& rPersistName )
{
DBG_ASSERT( mpImpl->aPersistName.isEmpty(), "Persist name changed!");
mpImpl->aPersistName = rPersistName;
mpImpl->mbLoadingOLEObjectFailed = false;
Connect();
SetChanged();
}
void SdrOle2Obj::AbandonObject()
{
mpImpl->aPersistName.clear();
mpImpl->mbLoadingOLEObjectFailed = false;
SetObjRef(nullptr);
}
const OUString& SdrOle2Obj::GetPersistName() const
{
return mpImpl->aPersistName;
}
void SdrOle2Obj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
{
// #i118485# Allowing much more attributes for OLEs
rInfo.bRotateFreeAllowed = true;
rInfo.bRotate90Allowed = true;
rInfo.bMirrorFreeAllowed = true;
rInfo.bMirror45Allowed = true;
rInfo.bMirror90Allowed = true;
rInfo.bTransparenceAllowed = true;
rInfo.bShearAllowed = true;
rInfo.bEdgeRadiusAllowed = false;
rInfo.bNoOrthoDesired = false;
rInfo.bCanConvToPath = true;
rInfo.bCanConvToPoly = true;
rInfo.bCanConvToPathLineToArea = false;
rInfo.bCanConvToPolyLineToArea = false;
rInfo.bCanConvToContour = true;
}
sal_uInt16 SdrOle2Obj::GetObjIdentifier() const
{
return mpImpl->mbFrame ? sal_uInt16(OBJ_FRAME) : sal_uInt16(OBJ_OLE2);
}
OUString SdrOle2Obj::TakeObjNameSingul() const
{
OUStringBuffer sName(SvxResId(mpImpl->mbFrame ? STR_ObjNameSingulFrame : STR_ObjNameSingulOLE2));
const OUString aName(GetName());
if (!aName.isEmpty())
{
sName.append(" '");
sName.append(aName);
sName.append('\'');
}
return sName.makeStringAndClear();
}
OUString SdrOle2Obj::TakeObjNamePlural() const
{
return SvxResId(mpImpl->mbFrame ? STR_ObjNamePluralFrame : STR_ObjNamePluralOLE2);
}
SdrOle2Obj* SdrOle2Obj::CloneSdrObject(SdrModel& rTargetModel) const
{
return CloneHelper< SdrOle2Obj >(rTargetModel);
}
SdrOle2Obj& SdrOle2Obj::operator=(const SdrOle2Obj& rObj)
{
return assignFrom(rObj);
}
SdrOle2Obj& SdrOle2Obj::assignFrom(const SdrOle2Obj& rObj)
{
//TODO/LATER: who takes over control of my old object?!
if( &rObj == this )
{
return *this;
}
// ImpAssign( rObj );
const SdrOle2Obj& rOle2Obj = rObj;
if( mpImpl->mbConnected )
Disconnect();
SdrRectObj::operator=( rObj );
// Manually copying bClosedObj attribute
SetClosedObj( rObj.IsClosedObj() );
mpImpl->aPersistName = rOle2Obj.mpImpl->aPersistName;
mpImpl->maProgName = rOle2Obj.mpImpl->maProgName;
mpImpl->mbFrame = rOle2Obj.mpImpl->mbFrame;
if (rOle2Obj.mpImpl->mxGraphic)
{
mpImpl->mxGraphic.reset(new Graphic(*rOle2Obj.mpImpl->mxGraphic));
}
if( !IsEmptyPresObj() )
{
::comphelper::IEmbeddedHelper* pDestPers(getSdrModelFromSdrObject().GetPersist());
::comphelper::IEmbeddedHelper* pSrcPers(rObj.getSdrModelFromSdrObject().GetPersist());
if( pDestPers && pSrcPers )
{
DBG_ASSERT( !mpImpl->mxObjRef.is(), "Object already existing!" );
comphelper::EmbeddedObjectContainer& rContainer = pSrcPers->getEmbeddedObjectContainer();
uno::Reference < embed::XEmbeddedObject > xObj = rContainer.GetEmbeddedObject( mpImpl->aPersistName );
if ( xObj.is() )
{
OUString aTmp;
mpImpl->mxObjRef.Assign( pDestPers->getEmbeddedObjectContainer().CopyAndGetEmbeddedObject(
rContainer, xObj, aTmp, pSrcPers->getDocumentBaseURL(), pDestPers->getDocumentBaseURL()), rOle2Obj.GetAspect());
mpImpl->mbTypeAsked = false;
mpImpl->aPersistName = aTmp;
CheckFileLink_Impl();
}
Connect();
}
}
return *this;
}
void SdrOle2Obj::ImpSetVisAreaSize()
{
// #i118524# do not again set VisAreaSize when the call comes from OLE client (e.g. ObjectAreaChanged)
if (mpImpl->mbSuppressSetVisAreaSize)
return;
// currently there is no need to recalculate scaling for iconified objects
// TODO/LATER: it might be needed in future when it is possible to change the icon
if ( GetAspect() == embed::Aspects::MSOLE_ICON )
return;
// the object area of an embedded object was changed, e.g. by user interaction an a selected object
GetObjRef();
if (mpImpl->mxObjRef.is())
{
sal_Int64 nMiscStatus = mpImpl->mxObjRef->getStatus( GetAspect() );
// the client is required to get access to scaling
SfxInPlaceClient* pClient(
SfxInPlaceClient::GetClient(
dynamic_cast<SfxObjectShell*>(
getSdrModelFromSdrObject().GetPersist()),
mpImpl->mxObjRef.GetObject()));
const bool bHasOwnClient(
mpImpl->mxLightClient.is() &&
mpImpl->mxObjRef->getClientSite() == uno::Reference< embed::XEmbeddedClient >( mpImpl->mxLightClient.get() ) );
if ( pClient || bHasOwnClient )
{
// TODO: IMHO we need to do similar things when object is UIActive or OutplaceActive?!
if ( ((nMiscStatus & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE) &&
svt::EmbeddedObjectRef::TryRunningState( mpImpl->mxObjRef.GetObject() ))
|| mpImpl->mxObjRef->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE
)
{
Fraction aScaleWidth;
Fraction aScaleHeight;
if ( pClient )
{
aScaleWidth = pClient->GetScaleWidth();
aScaleHeight = pClient->GetScaleHeight();
}
else
{
aScaleWidth = mpImpl->mxLightClient->GetScaleWidth();
aScaleHeight = mpImpl->mxLightClient->GetScaleHeight();
}
// The object wants to resize itself (f.e. Chart wants to recalculate the layout)
// or object is inplace active and so has a window that must be resized also
// In these cases the change in the object area size will be reflected in a change of the
// objects' visual area. The scaling will not change, but it might exist already and must
// be used in calculations
MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( mpImpl->mxObjRef->getMapUnit( GetAspect() ) );
Size aVisSize( static_cast<long>( Fraction( maRect.GetWidth() ) / aScaleWidth ),
static_cast<long>( Fraction( maRect.GetHeight() ) / aScaleHeight ) );
aVisSize = OutputDevice::LogicToLogic(
aVisSize,
MapMode(getSdrModelFromSdrObject().GetScaleUnit()),
MapMode(aMapUnit));
awt::Size aSz;
aSz.Width = aVisSize.Width();
aSz.Height = aVisSize.Height();
mpImpl->mxObjRef->setVisualAreaSize( GetAspect(), aSz );
try
{
aSz = mpImpl->mxObjRef->getVisualAreaSize( GetAspect() );
}
catch( embed::NoVisualAreaSizeException& )
{}
tools::Rectangle aAcceptedVisArea;
aAcceptedVisArea.SetSize( Size( static_cast<long>( Fraction( long( aSz.Width ) ) * aScaleWidth ),
static_cast<long>( Fraction( long( aSz.Height ) ) * aScaleHeight ) ) );
if (aVisSize != aAcceptedVisArea.GetSize())
{
// server changed VisArea to its liking and the VisArea is different than the suggested one
// store the new value as given by the object
MapUnit aNewMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( mpImpl->mxObjRef->getMapUnit( GetAspect() ) );
maRect.SetSize(
OutputDevice::LogicToLogic(
aAcceptedVisArea.GetSize(),
MapMode(aNewMapUnit),
MapMode(getSdrModelFromSdrObject().GetScaleUnit())));
}
// make the new object area known to the client
// compared to the "else" branch aRect might have been changed by the object and no additional scaling was applied
// WHY this -> OSL_ASSERT( pClient );
if( pClient )
pClient->SetObjArea(maRect);
// we need a new replacement image as the object has resized itself
//#i79578# don't request a new replacement image for charts to often
//a chart sends a modified call to the framework if it was changed
//thus the replacement update is already handled there
if( !IsChart() )
mpImpl->mxObjRef.UpdateReplacement();
}
else
{
// The object isn't active and does not want to resize itself so the changed object area size
// will be reflected in a changed object scaling
Fraction aScaleWidth;
Fraction aScaleHeight;
Size aObjAreaSize;
if ( CalculateNewScaling( aScaleWidth, aScaleHeight, aObjAreaSize ) )
{
if ( pClient )
{
tools::Rectangle aScaleRect(maRect.TopLeft(), aObjAreaSize);
pClient->SetObjAreaAndScale( aScaleRect, aScaleWidth, aScaleHeight);
}
else
{
mpImpl->mxLightClient->SetSizeScale( aScaleWidth, aScaleHeight );
}
}
}
}
else if( (nMiscStatus & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE) &&
svt::EmbeddedObjectRef::TryRunningState( mpImpl->mxObjRef.GetObject() ) )
{
//also handle not sfx based ole objects e.g. charts
//#i83860# resizing charts in impress distorts fonts
uno::Reference< embed::XVisualObject > xVisualObject( getXModel(), uno::UNO_QUERY );
if( xVisualObject.is() )
{
const MapUnit aMapUnit(
VCLUnoHelper::UnoEmbed2VCLMapUnit(
mpImpl->mxObjRef->getMapUnit(GetAspect())));
const Point aTL( maRect.TopLeft() );
const Point aBR( maRect.BottomRight() );
const Point aTL2(
OutputDevice::LogicToLogic(
aTL,
MapMode(getSdrModelFromSdrObject().GetScaleUnit()),
MapMode(aMapUnit)));
const Point aBR2(
OutputDevice::LogicToLogic(
aBR,
MapMode(getSdrModelFromSdrObject().GetScaleUnit()),
MapMode(aMapUnit)));
const tools::Rectangle aNewRect(
aTL2,
aBR2);
xVisualObject->setVisualAreaSize(
GetAspect(),
awt::Size(
aNewRect.GetWidth(),
aNewRect.GetHeight()));
}
}
}
}
void SdrOle2Obj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
{
if(!getSdrModelFromSdrObject().isLocked())
{
GetObjRef();
if ( mpImpl->mxObjRef.is() && ( mpImpl->mxObjRef->getStatus( GetAspect() ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE ) )
{
// if the object needs recompose on resize
// the client site should be created before the resize will take place
// check whether there is no client site and create it if necessary
AddOwnLightClient();
}
}
SdrRectObj::NbcResize(rRef,xFact,yFact);
if( !getSdrModelFromSdrObject().isLocked() )
ImpSetVisAreaSize();
}
void SdrOle2Obj::SetGeoData(const SdrObjGeoData& rGeo)
{
SdrRectObj::SetGeoData(rGeo);
if( !getSdrModelFromSdrObject().isLocked() )
ImpSetVisAreaSize();
}
void SdrOle2Obj::NbcSetSnapRect(const tools::Rectangle& rRect)
{
SdrRectObj::NbcSetSnapRect(rRect);
if( !getSdrModelFromSdrObject().isLocked() )
ImpSetVisAreaSize();
if ( mpImpl->mxObjRef.is() && IsChart() )
{
//#i103460# charts do not necessarily have an own size within ODF files,
//for this case they need to use the size settings from the surrounding frame,
//which is made available with this method as there is no other way
mpImpl->mxObjRef.SetDefaultSizeForChart( Size( rRect.GetWidth(), rRect.GetHeight() ) );
}
}
void SdrOle2Obj::NbcSetLogicRect(const tools::Rectangle& rRect)
{
SdrRectObj::NbcSetLogicRect(rRect);
if( !getSdrModelFromSdrObject().isLocked() )
ImpSetVisAreaSize();
}
const Graphic* SdrOle2Obj::GetGraphic() const
{
if ( mpImpl->mxObjRef.is() )
return mpImpl->mxObjRef.GetGraphic();
return mpImpl->mxGraphic.get();
}
void SdrOle2Obj::GetNewReplacement()
{
if ( mpImpl->mxObjRef.is() )
mpImpl->mxObjRef.UpdateReplacement();
}
Size SdrOle2Obj::GetOrigObjSize( MapMode const * pTargetMapMode ) const
{
return mpImpl->mxObjRef.GetSize( pTargetMapMode );
}
void SdrOle2Obj::setSuppressSetVisAreaSize( bool bNew )
{
mpImpl->mbSuppressSetVisAreaSize = bNew;
}
void SdrOle2Obj::NbcMove(const Size& rSize)
{
SdrRectObj::NbcMove(rSize);
if( !getSdrModelFromSdrObject().isLocked() )
ImpSetVisAreaSize();
}
bool SdrOle2Obj::CanUnloadRunningObj( const uno::Reference< embed::XEmbeddedObject >& xObj, sal_Int64 nAspect )
{
uno::Reference<embed::XEmbedPersist2> xPersist(xObj, uno::UNO_QUERY);
if (xPersist.is())
{
if (!xPersist->isStored())
// It doesn't have persistent storage. We can't unload this.
return false;
}
bool bResult = false;
sal_Int32 nState = xObj->getCurrentState();
if ( nState == embed::EmbedStates::LOADED )
{
// the object is already unloaded
bResult = true;
}
else
{
uno::Reference < util::XModifiable > xModifiable( xObj->getComponent(), uno::UNO_QUERY );
if ( !xModifiable.is() )
bResult = true;
else
{
sal_Int64 nMiscStatus = xObj->getStatus( nAspect );
if ( embed::EmbedMisc::MS_EMBED_ALWAYSRUN != ( nMiscStatus & embed::EmbedMisc::MS_EMBED_ALWAYSRUN ) &&
embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY != ( nMiscStatus & embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY ) &&
!( xModifiable.is() && xModifiable->isModified() ) &&
!( nState == embed::EmbedStates::INPLACE_ACTIVE || nState == embed::EmbedStates::UI_ACTIVE || nState == embed::EmbedStates::ACTIVE ) )
{
bResult = true;
}
}
}
return bResult;
}
bool SdrOle2Obj::Unload( const uno::Reference< embed::XEmbeddedObject >& xObj, sal_Int64 nAspect )
{
bool bResult = false;
if ( CanUnloadRunningObj( xObj, nAspect ) )
{
try
{
xObj->changeState( embed::EmbedStates::LOADED );
bResult = true;
}
catch( css::uno::Exception& )
{
TOOLS_WARN_EXCEPTION( "svx", "SdrOle2Obj::Unload()" );
}
}
return bResult;
}
bool SdrOle2Obj::Unload()
{
if (!mpImpl->mxObjRef.is())
// Already unloaded.
return true;
bool bUnloaded = false;
if ( mpImpl->mxObjRef.is() )
{
bUnloaded = Unload( mpImpl->mxObjRef.GetObject(), GetAspect() );
}
return bUnloaded;
}
void SdrOle2Obj::GetObjRef_Impl()
{
if ( !mpImpl->mxObjRef.is() && !mpImpl->aPersistName.isEmpty() && getSdrModelFromSdrObject().GetPersist() )
{
// Only try loading if it did not went wrong up to now
if(!mpImpl->mbLoadingOLEObjectFailed)
{
mpImpl->mxObjRef.Assign(
getSdrModelFromSdrObject().GetPersist()->getEmbeddedObjectContainer().GetEmbeddedObject(mpImpl->aPersistName),
GetAspect());
mpImpl->mbTypeAsked = false;
CheckFileLink_Impl();
// If loading of OLE object failed, remember that to not invoke an endless
// loop trying to load it again and again.
if( mpImpl->mxObjRef.is() )
{
mpImpl->mbLoadingOLEObjectFailed = true;
}
// For math objects, set closed state to transparent
SetClosedObj(!ImplIsMathObj( mpImpl->mxObjRef.GetObject() ));
}
if ( mpImpl->mxObjRef.is() )
{
if( !IsEmptyPresObj() )
{
// remember modified status of model
const bool bWasChanged(getSdrModelFromSdrObject().IsChanged());
// perhaps preview not valid anymore
// This line changes the modified state of the model
ClearGraphic();
// if status was not set before, force it back
// to not set, so that SetGraphic(0) above does not
// set the modified state of the model.
if(!bWasChanged && getSdrModelFromSdrObject().IsChanged())
{
getSdrModelFromSdrObject().SetChanged( false );
}
}
}
if ( mpImpl->mxObjRef.is() )
Connect();
}
if ( mpImpl->mbConnected )
{
// move object to first position in cache
GetSdrGlobalData().GetOLEObjCache().InsertObj(this);
}
}
uno::Reference < embed::XEmbeddedObject > const & SdrOle2Obj::GetObjRef() const
{
const_cast<SdrOle2Obj*>(this)->GetObjRef_Impl();
return mpImpl->mxObjRef.GetObject();
}
uno::Reference < embed::XEmbeddedObject > const & SdrOle2Obj::GetObjRef_NoInit() const
{
return mpImpl->mxObjRef.GetObject();
}
uno::Reference< frame::XModel > SdrOle2Obj::getXModel() const
{
GetObjRef();
if ( svt::EmbeddedObjectRef::TryRunningState(mpImpl->mxObjRef.GetObject()) )
return uno::Reference< frame::XModel >( mpImpl->mxObjRef->getComponent(), uno::UNO_QUERY );
else
return uno::Reference< frame::XModel >();
}
bool SdrOle2Obj::IsChart() const
{
if (!mpImpl->mbTypeAsked)
{
mpImpl->mbIsChart = mpImpl->mxObjRef.IsChart();
mpImpl->mbTypeAsked = true;
}
return mpImpl->mbIsChart;
}
void SdrOle2Obj::SetGraphicToObj( const Graphic& aGraphic )
{
mpImpl->mxObjRef.SetGraphic( aGraphic, OUString() );
// if the object isn't valid, e.g. link to something that doesn't exist, set the fallback
// graphic as mxGraphic so SdrOle2Obj::GetGraphic will show the fallback
if (const Graphic* pObjGraphic = mpImpl->mxObjRef.is() ? nullptr : mpImpl->mxObjRef.GetGraphic())
mpImpl->mxGraphic.reset(new Graphic(*pObjGraphic));
}
void SdrOle2Obj::SetGraphicToObj( const uno::Reference< io::XInputStream >& xGrStream, const OUString& aMediaType )
{
mpImpl->mxObjRef.SetGraphicStream( xGrStream, aMediaType );
// if the object isn't valid, e.g. link to something that doesn't exist, set the fallback
// graphic as mxGraphic so SdrOle2Obj::GetGraphic will show the fallback
if (const Graphic* pObjGraphic = mpImpl->mxObjRef.is() ? nullptr : mpImpl->mxObjRef.GetGraphic())
mpImpl->mxGraphic.reset(new Graphic(*pObjGraphic));
}
bool SdrOle2Obj::IsCalc() const
{
if ( !mpImpl->mxObjRef.is() )
return false;
SvGlobalName aObjClsId( mpImpl->mxObjRef->getClassID() );
return SvGlobalName(SO3_SC_CLASSID_30) == aObjClsId
|| SvGlobalName(SO3_SC_CLASSID_40) == aObjClsId
|| SvGlobalName(SO3_SC_CLASSID_50) == aObjClsId
|| SvGlobalName(SO3_SC_CLASSID_60) == aObjClsId
|| SvGlobalName(SO3_SC_OLE_EMBED_CLASSID_60) == aObjClsId
|| SvGlobalName(SO3_SC_OLE_EMBED_CLASSID_8) == aObjClsId
|| SvGlobalName(SO3_SC_CLASSID) == aObjClsId;
}
uno::Reference< frame::XModel > SdrOle2Obj::GetParentXModel() const
{
uno::Reference< frame::XModel > xDoc(getSdrModelFromSdrObject().getUnoModel(), uno::UNO_QUERY);
return xDoc;
}
bool SdrOle2Obj::CalculateNewScaling( Fraction& aScaleWidth, Fraction& aScaleHeight, Size& aObjAreaSize )
{
// TODO/LEAN: to avoid rounding errors scaling always uses the VisArea.
// If we don't cache it for own objects also we must load the object here
if (!mpImpl->mxObjRef.is())
return false;
MapMode aMapMode(getSdrModelFromSdrObject().GetScaleUnit());
aObjAreaSize = mpImpl->mxObjRef.GetSize( &aMapMode );
Size aSize = maRect.GetSize();
aScaleWidth = Fraction(aSize.Width(), aObjAreaSize.Width() );
aScaleHeight = Fraction(aSize.Height(), aObjAreaSize.Height() );
// reduce to 10 binary digits
aScaleHeight.ReduceInaccurate(10);
aScaleWidth.ReduceInaccurate(10);
return true;
}
bool SdrOle2Obj::AddOwnLightClient()
{
// The Own Light Client must be registered in object only using this method!
if ( !SfxInPlaceClient::GetClient( dynamic_cast<SfxObjectShell*>(getSdrModelFromSdrObject().GetPersist()), mpImpl->mxObjRef.GetObject() )
&& !( mpImpl->mxLightClient.is() && mpImpl->mxObjRef->getClientSite() == uno::Reference< embed::XEmbeddedClient >( mpImpl->mxLightClient.get() ) ) )
{
Connect();
if ( mpImpl->mxObjRef.is() && mpImpl->mxLightClient.is() )
{
Fraction aScaleWidth;
Fraction aScaleHeight;
Size aObjAreaSize;
if ( CalculateNewScaling( aScaleWidth, aScaleHeight, aObjAreaSize ) )
{
mpImpl->mxLightClient->SetSizeScale( aScaleWidth, aScaleHeight );
try {
mpImpl->mxObjRef->setClientSite( mpImpl->mxLightClient.get() );
return true;
} catch( uno::Exception& )
{}
}
}
return false;
}
return true;
}
Graphic SdrOle2Obj::GetEmptyOLEReplacementGraphic()
{
return Graphic(BitmapEx(BMP_SVXOLEOBJ));
}
void SdrOle2Obj::SetWindow(const css::uno::Reference < css::awt::XWindow >& _xWindow)
{
if ( mpImpl->mxObjRef.is() && mpImpl->mxLightClient.is() )
{
mpImpl->mxLightClient->setWindow(_xWindow);
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */