1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <com/sun/star/awt/XVclWindowPeer.hpp>
23 #include <com/sun/star/embed/Aspects.hpp>
24 #include <com/sun/star/embed/EmbedStates.hpp>
25 #include <com/sun/star/embed/UnreachableStateException.hpp>
26 #include <com/sun/star/embed/XEmbeddedClient.hpp>
27 #include <com/sun/star/embed/XInplaceClient.hpp>
28 #include <com/sun/star/embed/XInplaceObject.hpp>
29 #include <com/sun/star/embed/XWindowSupplier.hpp>
30 #include <com/sun/star/embed/EmbedVerbs.hpp>
31 #include <com/sun/star/embed/XEmbeddedOleObject.hpp>
32 #include <com/sun/star/embed/XEmbeddedObject.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/beans/PropertyValue.hpp>
35 #include <com/sun/star/embed/XStateChangeListener.hpp>
36 #include <com/sun/star/embed/StateChangeInProgressException.hpp>
37 #include <com/sun/star/embed/XLinkageSupport.hpp>
38 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
39 #include <com/sun/star/task/ErrorCodeIOException.hpp>
40 #include <com/sun/star/task/StatusIndicatorFactory.hpp>
41 #include <com/sun/star/task/XStatusIndicator.hpp>
43 #include <com/sun/star/embed/EmbedMisc.hpp>
44 #include <svtools/embedhlp.hxx>
45 #include <vcl/svapp.hxx>
46 #include <vcl/unohelp.hxx>
48 #include <sfx2/ipclient.hxx>
49 #include <sfx2/viewsh.hxx>
50 #include <sfx2/viewfrm.hxx>
51 #include <sfx2/objsh.hxx>
52 #include <guisaveas.hxx>
53 #include <cppuhelper/implbase.hxx>
54 #include <svtools/ehdl.hxx>
56 #include <vcl/timer.hxx>
57 #include <vcl/window.hxx>
58 #include <toolkit/helper/vclunohelper.hxx>
59 #include <tools/debug.hxx>
60 #include <comphelper/diagnose_ex.hxx>
61 #include <tools/fract.hxx>
62 #include <tools/gen.hxx>
63 #include <svtools/soerr.hxx>
64 #include <comphelper/lok.hxx>
65 #include <comphelper/processfactory.hxx>
66 #include <comphelper/propertyvalue.hxx>
67 #include <cppuhelper/exc_hlp.hxx>
69 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
71 #define SFX_CLIENTACTIVATE_TIMEOUT 100
73 using namespace com::sun::star
;
77 // SfxEmbedResizeGuard
78 class SfxBooleanFlagGuard
82 explicit SfxBooleanFlagGuard(bool& bFlag
)
88 ~SfxBooleanFlagGuard()
94 tools::Rectangle
lcl_negateRectX(const tools::Rectangle
& rRect
)
96 return tools::Rectangle(
97 std::max(static_cast<tools::Long
>(0l), -rRect
.Right()),
99 std::max(static_cast<tools::Long
>(0l), -rRect
.Left()),
105 // SfxInPlaceClient_Impl
108 class SfxInPlaceClient_Impl
: public ::cppu::WeakImplHelper
< embed::XEmbeddedClient
,
109 embed::XInplaceClient
,
110 document::XEventListener
,
111 embed::XStateChangeListener
,
112 embed::XWindowSupplier
>
115 Timer m_aTimer
{ "sfx::SfxInPlaceClient m_xImpl::m_aTimer" }; // activation timeout, starts after object connection
116 tools::Rectangle m_aObjArea
; // area of object in coordinate system of the container (without scaling)
117 Fraction m_aScaleWidth
; // scaling that was applied to the object when it was not active
118 Fraction m_aScaleHeight
;
119 SfxInPlaceClient
* m_pClient
;
120 sal_Int64 m_nAspect
; // ViewAspect that is assigned from the container
122 bool m_bUIActive
; // set and cleared when notification for UI (de)activation is sent
123 bool m_bResizeNoScale
;
126 uno::Reference
< embed::XEmbeddedObject
> m_xObject
;
129 SfxInPlaceClient_Impl()
130 : m_pClient( nullptr )
132 , m_bStoreObject( true )
133 , m_bUIActive( false )
134 , m_bResizeNoScale( false )
135 , m_bNegativeX( false )
138 void SizeHasChanged();
139 DECL_LINK(TimerHdl
, Timer
*, void);
140 uno::Reference
< frame::XFrame
> const & GetFrame() const;
143 virtual void SAL_CALL
saveObject() override
;
144 virtual void SAL_CALL
visibilityChanged( sal_Bool bVisible
) override
;
147 virtual sal_Bool SAL_CALL
canInplaceActivate() override
;
148 virtual void SAL_CALL
activatingInplace() override
;
149 virtual void SAL_CALL
activatingUI() override
;
150 virtual void SAL_CALL
deactivatedInplace() override
;
151 virtual void SAL_CALL
deactivatedUI() override
;
152 virtual uno::Reference
< css::frame::XLayoutManager
> SAL_CALL
getLayoutManager() override
;
153 virtual uno::Reference
< frame::XDispatchProvider
> SAL_CALL
getInplaceDispatchProvider() override
;
154 virtual awt::Rectangle SAL_CALL
getPlacement() override
;
155 virtual awt::Rectangle SAL_CALL
getClipRectangle() override
;
156 virtual void SAL_CALL
translateAccelerators( const uno::Sequence
< awt::KeyEvent
>& aKeys
) override
;
157 virtual void SAL_CALL
scrollObject( const awt::Size
& aOffset
) override
;
158 virtual void SAL_CALL
changedPlacement( const awt::Rectangle
& aPosRect
) override
;
160 // XComponentSupplier
161 virtual uno::Reference
< util::XCloseable
> SAL_CALL
getComponent() override
;
164 virtual uno::Reference
< awt::XWindow
> SAL_CALL
getWindow() override
;
166 // document::XEventListener
167 virtual void SAL_CALL
notifyEvent( const document::EventObject
& aEvent
) override
;
169 // XStateChangeListener
170 virtual void SAL_CALL
changingState( const css::lang::EventObject
& aEvent
, ::sal_Int32 nOldState
, ::sal_Int32 nNewState
) override
;
171 virtual void SAL_CALL
stateChanged( const css::lang::EventObject
& aEvent
, ::sal_Int32 nOldState
, ::sal_Int32 nNewState
) override
;
172 virtual void SAL_CALL
disposing( const css::lang::EventObject
& aEvent
) override
;
175 void SAL_CALL
SfxInPlaceClient_Impl::changingState(
176 const css::lang::EventObject
& /*aEvent*/,
177 ::sal_Int32
/*nOldState*/,
178 ::sal_Int32
/*nNewState*/ )
182 void SAL_CALL
SfxInPlaceClient_Impl::stateChanged(
183 const css::lang::EventObject
& /*aEvent*/,
184 ::sal_Int32 nOldState
,
185 ::sal_Int32 nNewState
)
187 if ( m_pClient
&& nOldState
!= embed::EmbedStates::LOADED
&& nNewState
== embed::EmbedStates::RUNNING
)
189 // deactivation of object
190 uno::Reference
< frame::XModel
> xDocument
;
191 if ( m_pClient
->GetViewShell()->GetObjectShell() )
192 xDocument
= m_pClient
->GetViewShell()->GetObjectShell()->GetModel();
193 SfxObjectShell::SetCurrentComponent( xDocument
);
197 void SAL_CALL
SfxInPlaceClient_Impl::notifyEvent( const document::EventObject
& aEvent
)
199 SolarMutexGuard aGuard
;
201 if ( m_pClient
&& aEvent
.EventName
== "OnVisAreaChanged" && m_nAspect
!= embed::Aspects::MSOLE_ICON
)
203 m_pClient
->FormatChanged(); // for Writer when format of the object is changed with the area
204 m_pClient
->ViewChanged();
205 m_pClient
->Invalidate();
209 void SAL_CALL
SfxInPlaceClient_Impl::disposing( const css::lang::EventObject
& /*aEvent*/ )
217 uno::Reference
< frame::XFrame
> const & SfxInPlaceClient_Impl::GetFrame() const
220 throw uno::RuntimeException();
221 return m_pClient
->GetViewShell()->GetViewFrame().GetFrame().GetFrameInterface();
224 void SAL_CALL
SfxInPlaceClient_Impl::saveObject()
226 if (!m_bStoreObject
|| (m_pClient
&& m_pClient
->IsProtected()))
227 // client wants to discard the object (usually it means the container document is closed while an object is active
228 // and the user didn't request saving the changes
231 // the common persistence is supported by objects and links
232 uno::Reference
< embed::XCommonEmbedPersist
> xPersist( m_xObject
, uno::UNO_QUERY_THROW
);
234 uno::Reference
< frame::XFrame
> xFrame
;
235 uno::Reference
< task::XStatusIndicator
> xStatusIndicator
;
236 uno::Reference
< frame::XModel
> xModel( m_xObject
->getComponent(), uno::UNO_QUERY
);
237 const uno::Reference
< uno::XComponentContext
>& xContext( ::comphelper::getProcessComponentContext() );
241 uno::Reference
< frame::XController
> xController
= xModel
->getCurrentController();
242 if ( xController
.is() )
243 xFrame
= xController
->getFrame();
248 // set non-reschedule progress to prevent problems when asynchronous calls are made
249 // during storing of the embedded object
250 uno::Reference
< task::XStatusIndicatorFactory
> xStatusIndicatorFactory
=
251 task::StatusIndicatorFactory::createWithFrame( xContext
, xFrame
, true/*DisableReschedule*/, false/*AllowParentShow*/ );
253 uno::Reference
< beans::XPropertySet
> xPropSet( xFrame
, uno::UNO_QUERY
);
258 xStatusIndicator
= xStatusIndicatorFactory
->createStatusIndicator();
259 xPropSet
->setPropertyValue( u
"IndicatorInterception"_ustr
, uno::Any( xStatusIndicator
));
261 catch ( const uno::RuntimeException
& )
265 catch ( uno::Exception
& )
273 xPersist
->storeOwn();
276 catch ( uno::Exception
& )
278 //TODO/LATER: what should happen if object can't be saved?!
281 // reset status indicator interception after storing
284 uno::Reference
< beans::XPropertySet
> xPropSet( xFrame
, uno::UNO_QUERY
);
287 xStatusIndicator
.clear();
288 xPropSet
->setPropertyValue( u
"IndicatorInterception"_ustr
, uno::Any( xStatusIndicator
));
291 catch ( const uno::RuntimeException
& )
295 catch ( uno::Exception
& )
299 // the client can exist only in case there is a view shell
300 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
301 throw uno::RuntimeException();
303 SfxObjectShell
* pDocShell
= m_pClient
->GetViewShell()->GetObjectShell();
305 throw uno::RuntimeException();
307 pDocShell
->SetModified();
309 //TODO/LATER: invalidation might be necessary when object was modified, but is not
310 //saved through this method
311 // m_pClient->Invalidate();
315 void SAL_CALL
SfxInPlaceClient_Impl::visibilityChanged( sal_Bool bVisible
)
317 SolarMutexGuard aGuard
;
319 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
320 throw uno::RuntimeException();
322 m_pClient
->GetViewShell()->OutplaceActivated( bVisible
);
323 if (m_pClient
) // it can change in the above code
324 m_pClient
->Invalidate();
330 sal_Bool SAL_CALL
SfxInPlaceClient_Impl::canInplaceActivate()
332 if ( !m_xObject
.is() )
333 throw uno::RuntimeException();
335 // we don't want to switch directly from outplace to inplace mode
336 if ( m_xObject
->getCurrentState() == embed::EmbedStates::ACTIVE
|| m_nAspect
== embed::Aspects::MSOLE_ICON
)
343 void SAL_CALL
SfxInPlaceClient_Impl::activatingInplace()
345 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
346 throw uno::RuntimeException();
348 if ( !comphelper::LibreOfficeKit::isActive() )
351 if ( SfxViewShell
* pViewShell
= m_pClient
->GetViewShell() )
353 tools::Rectangle
aRect(m_pClient
->GetObjArea());
355 if (m_pClient
->GetEditWin())
357 if (m_pClient
->GetEditWin()->GetMapMode().GetMapUnit() == MapUnit::Map100thMM
)
358 aRect
= o3tl::convert(aRect
, o3tl::Length::mm100
, o3tl::Length::twip
);
361 OString str
= (m_bNegativeX
? lcl_negateRectX(aRect
) : aRect
).toString() + ", \"INPLACE\"";
362 pViewShell
->libreOfficeKitViewCallback( LOK_CALLBACK_GRAPHIC_SELECTION
, str
);
368 void SAL_CALL
SfxInPlaceClient_Impl::activatingUI()
370 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
371 throw uno::RuntimeException();
373 m_pClient
->GetViewShell()->ResetAllClients_Impl(m_pClient
);
375 m_pClient
->GetViewShell()->UIActivating( m_pClient
);
379 void SAL_CALL
SfxInPlaceClient_Impl::deactivatedInplace()
381 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
382 throw uno::RuntimeException();
384 if ( comphelper::LibreOfficeKit::isActive() )
386 if ( SfxViewShell
* pViewShell
= m_pClient
->GetViewShell() ) {
387 pViewShell
->libreOfficeKitViewCallback( LOK_CALLBACK_GRAPHIC_SELECTION
, "INPLACE EXIT"_ostr
);
393 void SAL_CALL
SfxInPlaceClient_Impl::deactivatedUI()
395 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
396 throw uno::RuntimeException();
398 m_pClient
->GetViewShell()->UIDeactivated( m_pClient
);
403 uno::Reference
< css::frame::XLayoutManager
> SAL_CALL
SfxInPlaceClient_Impl::getLayoutManager()
405 uno::Reference
< beans::XPropertySet
> xFrame( GetFrame(), uno::UNO_QUERY_THROW
);
407 uno::Reference
< css::frame::XLayoutManager
> xMan
;
410 uno::Any aAny
= xFrame
->getPropertyValue( u
"LayoutManager"_ustr
);
413 catch ( uno::Exception
& ex
)
415 css::uno::Any anyEx
= cppu::getCaughtException();
416 throw css::lang::WrappedTargetRuntimeException( ex
.Message
,
424 uno::Reference
< frame::XDispatchProvider
> SAL_CALL
SfxInPlaceClient_Impl::getInplaceDispatchProvider()
426 return uno::Reference
< frame::XDispatchProvider
>( GetFrame(), uno::UNO_QUERY_THROW
);
430 awt::Rectangle SAL_CALL
SfxInPlaceClient_Impl::getPlacement()
432 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
433 throw uno::RuntimeException();
435 // apply scaling to object area and convert to pixels
436 tools::Rectangle
aRealObjArea( m_aObjArea
);
437 aRealObjArea
.SetSize( Size( tools::Long( aRealObjArea
.GetWidth() * m_aScaleWidth
),
438 tools::Long( aRealObjArea
.GetHeight() * m_aScaleHeight
) ) );
440 vcl::Window
* pEditWin
= m_pClient
->GetEditWin();
441 // In Writer and Impress the map mode is disabled. So when a chart is
442 // activated (for in place editing) we get the chart win size in 100th mm
443 // and any method that should return pixels returns 100th mm and the chart
444 // window map mode has a ~26.485 scale factor.
445 // All that does not fit with current implementation for handling chart
447 if (comphelper::LibreOfficeKit::isActive())
449 bool bMapModeEnabled
= pEditWin
->IsMapModeEnabled();
450 if (!bMapModeEnabled
)
451 pEditWin
->EnableMapMode();
452 aRealObjArea
= pEditWin
->LogicToPixel(aRealObjArea
);
453 if (!bMapModeEnabled
&& pEditWin
->IsMapModeEnabled())
454 pEditWin
->EnableMapMode(false);
458 aRealObjArea
= pEditWin
->LogicToPixel(aRealObjArea
);
461 return vcl::unohelper::ConvertToAWTRect(aRealObjArea
);
465 awt::Rectangle SAL_CALL
SfxInPlaceClient_Impl::getClipRectangle()
467 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
468 throw uno::RuntimeException();
470 // currently(?) same as placement
471 tools::Rectangle
aRealObjArea( m_aObjArea
);
472 aRealObjArea
.SetSize( Size( tools::Long( aRealObjArea
.GetWidth() * m_aScaleWidth
),
473 tools::Long( aRealObjArea
.GetHeight() * m_aScaleHeight
) ) );
475 vcl::Window
* pEditWin
= m_pClient
->GetEditWin();
476 // See comment for SfxInPlaceClient_Impl::getPlacement.
477 if (comphelper::LibreOfficeKit::isActive())
479 bool bMapModeEnabled
= pEditWin
->IsMapModeEnabled();
480 if (!bMapModeEnabled
)
481 pEditWin
->EnableMapMode();
482 aRealObjArea
= pEditWin
->LogicToPixel(aRealObjArea
);
483 if (!bMapModeEnabled
&& pEditWin
->IsMapModeEnabled())
484 pEditWin
->EnableMapMode(false);
488 aRealObjArea
= pEditWin
->LogicToPixel(aRealObjArea
);
491 return vcl::unohelper::ConvertToAWTRect(aRealObjArea
);
495 void SAL_CALL
SfxInPlaceClient_Impl::translateAccelerators( const uno::Sequence
< awt::KeyEvent
>& /*aKeys*/ )
497 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
498 throw uno::RuntimeException();
500 // TODO/MBA: keyboard accelerators
504 void SAL_CALL
SfxInPlaceClient_Impl::scrollObject( const awt::Size
& /*aOffset*/ )
506 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
507 throw uno::RuntimeException();
511 void SAL_CALL
SfxInPlaceClient_Impl::changedPlacement( const awt::Rectangle
& aPosRect
)
513 uno::Reference
< embed::XInplaceObject
> xInplace( m_xObject
, uno::UNO_QUERY_THROW
);
514 if ( !m_pClient
|| !m_pClient
->GetEditWin() || !m_pClient
->GetViewShell() )
515 throw uno::RuntimeException();
517 // check if the change is at least one pixel in size
518 awt::Rectangle aOldRect
= getPlacement();
519 tools::Rectangle aNewPixelRect
= vcl::unohelper::ConvertToVCLRect(aPosRect
);
520 tools::Rectangle aOldPixelRect
= vcl::unohelper::ConvertToVCLRect(aOldRect
);
521 if ( aOldPixelRect
== aNewPixelRect
)
522 // nothing has changed
525 // new scaled object area
526 tools::Rectangle aNewLogicRect
= m_pClient
->GetEditWin()->PixelToLogic( aNewPixelRect
);
528 // all the size changes in this method should happen without scaling
529 // SfxBooleanFlagGuard aGuard( m_bResizeNoScale, sal_True );
531 // allow container to apply restrictions on the requested new area;
532 // the container might change the object view during size calculation;
533 // currently only writer does it
534 m_pClient
->RequestNewObjectArea( aNewLogicRect
);
536 if ( aNewLogicRect
!= m_pClient
->GetScaledObjArea() )
538 // the calculation of the object area has not changed the object size
539 // it should be done here then
540 SfxBooleanFlagGuard
aGuard( m_bResizeNoScale
);
542 // new size of the object area without scaling
543 Size
aNewObjSize( tools::Long( aNewLogicRect
.GetWidth() / m_aScaleWidth
),
544 tools::Long( aNewLogicRect
.GetHeight() / m_aScaleHeight
) );
546 // now remove scaling from new placement and keep this at the new object area
547 aNewLogicRect
.SetSize( aNewObjSize
);
548 m_aObjArea
= aNewLogicRect
;
550 // let the window size be recalculated
554 // notify container view about changes
555 m_pClient
->ObjectAreaChanged();
558 // XComponentSupplier
560 uno::Reference
< util::XCloseable
> SAL_CALL
SfxInPlaceClient_Impl::getComponent()
562 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
563 throw uno::RuntimeException();
565 SfxObjectShell
* pDocShell
= m_pClient
->GetViewShell()->GetObjectShell();
567 throw uno::RuntimeException();
569 // all the components must implement XCloseable
570 uno::Reference
< util::XCloseable
> xComp( pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
577 uno::Reference
< awt::XWindow
> SAL_CALL
SfxInPlaceClient_Impl::getWindow()
579 if ( !m_pClient
|| !m_pClient
->GetEditWin() )
580 throw uno::RuntimeException();
582 uno::Reference
< awt::XWindow
> xWin( m_pClient
->GetEditWin()->GetComponentInterface(), uno::UNO_QUERY
);
587 // notification to the client implementation that either the object area or the scaling has been changed
588 // as a result the logical size of the window has changed also
589 void SfxInPlaceClient_Impl::SizeHasChanged()
591 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
592 throw uno::RuntimeException();
596 && ( m_xObject
->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE
597 || m_xObject
->getCurrentState() == embed::EmbedStates::UI_ACTIVE
) )
599 // only possible in active states
600 uno::Reference
< embed::XInplaceObject
> xInplace( m_xObject
, uno::UNO_QUERY_THROW
);
602 if ( m_bResizeNoScale
)
604 // the resizing should be done without scaling
605 // set the correct size to the object to avoid the scaling
606 MapMode
aObjectMap( VCLUnoHelper::UnoEmbed2VCLMapUnit( m_xObject
->getMapUnit( m_nAspect
) ) );
607 MapMode
aClientMap( m_pClient
->GetEditWin()->GetMapMode().GetMapUnit() );
609 // convert to logical coordinates of the embedded object
610 Size aNewSize
= m_pClient
->GetEditWin()->LogicToLogic( m_aObjArea
.GetSize(), &aClientMap
, &aObjectMap
);
611 m_xObject
->setVisualAreaSize( m_nAspect
, awt::Size( aNewSize
.Width(), aNewSize
.Height() ) );
614 xInplace
->setObjectRectangles( getPlacement(), getClipRectangle() );
617 catch( uno::Exception
& )
619 // TODO/LATER: handle error
624 IMPL_LINK_NOARG(SfxInPlaceClient_Impl
, TimerHdl
, Timer
*, void)
626 if ( m_pClient
&& m_xObject
.is() )
628 m_pClient
->GetViewShell()->CheckIPClient_Impl(m_pClient
,
629 m_pClient
->GetViewShell()->GetObjectShell()->GetVisArea());
637 SfxInPlaceClient::SfxInPlaceClient( SfxViewShell
* pViewShell
, vcl::Window
*pDraw
, sal_Int64 nAspect
) :
638 m_xImp( new SfxInPlaceClient_Impl
),
639 m_pViewSh( pViewShell
),
642 m_xImp
->m_pClient
= this;
643 m_xImp
->m_nAspect
= nAspect
;
644 m_xImp
->m_aScaleWidth
= m_xImp
->m_aScaleHeight
= Fraction(1,1);
645 pViewShell
->NewIPClient_Impl(this);
646 m_xImp
->m_aTimer
.SetTimeout( SFX_CLIENTACTIVATE_TIMEOUT
);
647 m_xImp
->m_aTimer
.SetInvokeHandler( LINK( m_xImp
.get(), SfxInPlaceClient_Impl
, TimerHdl
) );
651 SfxInPlaceClient::~SfxInPlaceClient()
653 m_pViewSh
->IPClientGone_Impl(this);
655 // deleting the client before storing the object means discarding all changes
656 m_xImp
->m_bStoreObject
= false;
659 m_xImp
->m_pClient
= nullptr;
661 // the next call will destroy m_xImp if no other reference to it exists
665 // the class is not intended to be used in multithreaded environment;
666 // if it will this disconnection and all the parts that use the m_pClient
667 // must be guarded with mutex
671 void SfxInPlaceClient::SetObjectState( sal_Int32 nState
)
673 if ( !GetObject().is() )
676 if ( m_xImp
->m_nAspect
== embed::Aspects::MSOLE_ICON
677 && ( nState
== embed::EmbedStates::UI_ACTIVE
|| nState
== embed::EmbedStates::INPLACE_ACTIVE
) )
679 OSL_FAIL( "Iconified object should not be activated inplace!" );
685 GetObject()->changeState( nState
);
687 catch ( uno::Exception
& )
692 sal_Int64
SfxInPlaceClient::GetObjectMiscStatus() const
694 if ( GetObject().is() )
695 return GetObject()->getStatus( m_xImp
->m_nAspect
);
700 const uno::Reference
< embed::XEmbeddedObject
>& SfxInPlaceClient::GetObject() const
702 return m_xImp
->m_xObject
;
706 void SfxInPlaceClient::SetObject( const uno::Reference
< embed::XEmbeddedObject
>& rObject
)
708 if ( m_xImp
->m_xObject
.is() && rObject
!= m_xImp
->m_xObject
)
710 DBG_ASSERT( GetObject()->getClientSite() == getXWeak(m_xImp
.get()), "Wrong ClientSite!" );
711 if ( GetObject()->getClientSite() == getXWeak(m_xImp
.get()) )
713 if ( GetObject()->getCurrentState() != embed::EmbedStates::LOADED
)
714 SetObjectState( embed::EmbedStates::RUNNING
);
715 m_xImp
->m_xObject
->removeEventListener( m_xImp
);
716 m_xImp
->m_xObject
->removeStateChangeListener( m_xImp
);
719 m_xImp
->m_xObject
->setClientSite( nullptr );
721 catch( uno::Exception
& )
723 OSL_FAIL( "Can not clean the client site!" );
728 if ( m_pViewSh
->GetViewFrame().GetFrame().IsClosing_Impl() )
729 // sometimes applications reconnect clients on shutting down because it happens in their Paint methods
732 m_xImp
->m_xObject
= rObject
;
736 // as soon as an object was connected to a client it has to be checked whether the object wants
738 rObject
->addStateChangeListener( m_xImp
);
739 rObject
->addEventListener( m_xImp
);
743 rObject
->setClientSite( m_xImp
);
745 catch( uno::Exception
& )
747 OSL_FAIL( "Can not set the client site!" );
750 m_xImp
->m_aTimer
.Start();
753 m_xImp
->m_aTimer
.Stop();
757 bool SfxInPlaceClient::SetObjArea( const tools::Rectangle
& rArea
)
759 if( rArea
!= m_xImp
->m_aObjArea
)
761 m_xImp
->m_aObjArea
= rArea
;
762 m_xImp
->SizeHasChanged();
772 const tools::Rectangle
& SfxInPlaceClient::GetObjArea() const
774 return m_xImp
->m_aObjArea
;
777 tools::Rectangle
SfxInPlaceClient::GetScaledObjArea() const
779 tools::Rectangle
aRealObjArea( m_xImp
->m_aObjArea
);
780 aRealObjArea
.SetSize( Size( tools::Long( aRealObjArea
.GetWidth() * m_xImp
->m_aScaleWidth
),
781 tools::Long( aRealObjArea
.GetHeight() * m_xImp
->m_aScaleHeight
) ) );
786 void SfxInPlaceClient::SetSizeScale( const Fraction
& rScaleWidth
, const Fraction
& rScaleHeight
)
788 if ( m_xImp
->m_aScaleWidth
!= rScaleWidth
|| m_xImp
->m_aScaleHeight
!= rScaleHeight
)
790 m_xImp
->m_aScaleWidth
= rScaleWidth
;
791 m_xImp
->m_aScaleHeight
= rScaleHeight
;
793 m_xImp
->SizeHasChanged();
795 // TODO/LATER: Invalidate seems to trigger (wrong) recalculations of the ObjArea, so it's better
796 // not to call it here, but maybe it sounds reasonable to do so.
802 void SfxInPlaceClient::SetObjAreaAndScale( const tools::Rectangle
& rArea
, const Fraction
& rScaleWidth
, const Fraction
& rScaleHeight
)
804 if( rArea
!= m_xImp
->m_aObjArea
|| m_xImp
->m_aScaleWidth
!= rScaleWidth
|| m_xImp
->m_aScaleHeight
!= rScaleHeight
)
806 m_xImp
->m_aObjArea
= rArea
;
807 m_xImp
->m_aScaleWidth
= rScaleWidth
;
808 m_xImp
->m_aScaleHeight
= rScaleHeight
;
810 m_xImp
->SizeHasChanged();
817 const Fraction
& SfxInPlaceClient::GetScaleWidth() const
819 return m_xImp
->m_aScaleWidth
;
823 const Fraction
& SfxInPlaceClient::GetScaleHeight() const
825 return m_xImp
->m_aScaleHeight
;
829 void SfxInPlaceClient::Invalidate()
831 // TODO/LATER: do we need both?
833 // the object area is provided in logical coordinates of the window but without scaling applied
834 tools::Rectangle
aRealObjArea( m_xImp
->m_aObjArea
);
835 aRealObjArea
.SetSize( Size( tools::Long( aRealObjArea
.GetWidth() * m_xImp
->m_aScaleWidth
),
836 tools::Long( aRealObjArea
.GetHeight() * m_xImp
->m_aScaleHeight
) ) );
838 m_pEditWin
->Invalidate( IsNegativeX() ? lcl_negateRectX(aRealObjArea
) : aRealObjArea
);
844 bool SfxInPlaceClient::IsObjectUIActive() const
847 return ( m_xImp
->m_xObject
.is() && ( m_xImp
->m_xObject
->getCurrentState() == embed::EmbedStates::UI_ACTIVE
) );
849 catch( uno::Exception
& )
856 bool SfxInPlaceClient::IsObjectInPlaceActive() const
861 m_xImp
->m_xObject
.is() &&
862 (m_xImp
->m_xObject
->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE
)
865 m_xImp
->m_xObject
.is() &&
866 (m_xImp
->m_xObject
->getCurrentState() == embed::EmbedStates::UI_ACTIVE
)
870 catch( uno::Exception
& )
877 SfxInPlaceClient
* SfxInPlaceClient::GetClient( SfxObjectShell
const * pDoc
, const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObject
)
879 for ( SfxViewFrame
* pFrame
= SfxViewFrame::GetFirst(pDoc
); pFrame
; pFrame
=SfxViewFrame::GetNext(*pFrame
,pDoc
) )
881 if( pFrame
->GetViewShell() )
883 SfxInPlaceClient
* pClient
= pFrame
->GetViewShell()->FindIPClient( xObject
, nullptr );
892 sal_Int64
SfxInPlaceClient::GetAspect() const
894 return m_xImp
->m_nAspect
;
897 ErrCodeMsg
SfxInPlaceClient::DoVerb(sal_Int32 nVerb
)
899 SfxErrorContext
aEc(ERRCTX_SO_DOVERB
, m_pViewSh
->GetFrameWeld(), RID_SO_ERRCTX
);
900 ErrCodeMsg nError
= ERRCODE_NONE
;
902 if ( m_xImp
->m_xObject
.is() )
904 bool bSaveCopyAs
= false;
905 if ( nVerb
== -8 ) // "Save Copy as..."
907 svt::EmbeddedObjectRef::TryRunningState( m_xImp
->m_xObject
);
908 // TODO/LATER: this special verb should disappear when outplace activation is completely available
909 uno::Reference
< frame::XModel
> xEmbModel( m_xImp
->m_xObject
->getComponent(), uno::UNO_QUERY
);
910 if ( xEmbModel
.is() )
916 SfxStoringHelper aHelper
;
917 uno::Sequence
< beans::PropertyValue
> aDispatchArgs
{
918 comphelper::makePropertyValue(u
"SaveTo"_ustr
, true)
921 aHelper
.GUIStoreModel( xEmbModel
,
925 SignatureState::NOSIGNATURES
,
928 catch( const task::ErrorCodeIOException
& aErrorEx
)
930 nError
= ErrCode(aErrorEx
.ErrCode
);
932 catch( uno::Exception
& )
934 nError
= ERRCODE_IO_GENERAL
;
935 // TODO/LATER: better error handling
942 if ( m_xImp
->m_nAspect
== embed::Aspects::MSOLE_ICON
)
944 // the common persistence is supported by objects and links
946 uno::Reference
< embed::XEmbeddedOleObject
> xEmbeddedOleObject( m_xImp
->m_xObject
, uno::UNO_QUERY
);
948 if ( xEmbeddedOleObject
.is() && (nVerb
== embed::EmbedVerbs::MS_OLEVERB_PRIMARY
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_OPEN
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_SHOW
))
949 nVerb
= embed::EmbedVerbs::MS_OLEVERB_SHOW
;
950 else if ( nVerb
== embed::EmbedVerbs::MS_OLEVERB_PRIMARY
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_SHOW
)
951 nVerb
= embed::EmbedVerbs::MS_OLEVERB_OPEN
; // outplace activation
952 else if ( nVerb
== embed::EmbedVerbs::MS_OLEVERB_UIACTIVATE
953 || nVerb
== embed::EmbedVerbs::MS_OLEVERB_IPACTIVATE
)
954 nError
= ERRCODE_SO_GENERALERROR
;
959 // See comment for SfxInPlaceClient_Impl::getPlacement.
960 vcl::Window
* pEditWin
= GetEditWin();
961 bool bMapModeEnabled
= pEditWin
->IsMapModeEnabled();
962 if (comphelper::LibreOfficeKit::isActive() && !bMapModeEnabled
)
964 pEditWin
->EnableMapMode();
966 m_pViewSh
->GetViewFrame().GetFrame().LockResize_Impl(true);
969 m_xImp
->m_xObject
->setClientSite( m_xImp
);
971 m_xImp
->m_xObject
->doVerb( nVerb
);
973 catch ( embed::UnreachableStateException
& e
)
975 if (nVerb
== embed::EmbedVerbs::MS_OLEVERB_PRIMARY
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_OPEN
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_SHOW
)
977 // a workaround for the default verb, usually makes sense for alien objects
980 m_xImp
->m_xObject
->doVerb( -9 ); // open own view, a workaround verb that is not visible
982 if ( m_xImp
->m_xObject
->getCurrentState() == embed::EmbedStates::UI_ACTIVE
)
984 // the object was converted to OOo object
985 awt::Size aSize
= m_xImp
->m_xObject
->getVisualAreaSize( m_xImp
->m_nAspect
);
986 MapMode
aObjectMap( VCLUnoHelper::UnoEmbed2VCLMapUnit( m_xImp
->m_xObject
->getMapUnit( m_xImp
->m_nAspect
) ) );
987 MapMode
aClientMap( GetEditWin()->GetMapMode().GetMapUnit() );
988 Size aNewSize
= GetEditWin()->LogicToLogic( Size( aSize
.Width
, aSize
.Height
), &aObjectMap
, &aClientMap
);
990 tools::Rectangle aScaledArea
= GetScaledObjArea();
991 m_xImp
->m_aObjArea
.SetSize( aNewSize
);
992 m_xImp
->m_aScaleWidth
= Fraction( aScaledArea
.GetWidth(), aNewSize
.Width() );
993 m_xImp
->m_aScaleHeight
= Fraction( aScaledArea
.GetHeight(), aNewSize
.Height() );
996 catch (uno::Exception
const&)
998 TOOLS_WARN_EXCEPTION("embeddedobj", "SfxInPlaceClient::DoVerb: -9 fallback path");
999 nError
= ErrCodeMsg(ERRCODE_SO_GENERALERROR
, e
.Message
);
1003 catch ( embed::StateChangeInProgressException
& )
1005 // TODO/LATER: it would be nice to be able to provide the current target state outside
1006 nError
= ERRCODE_SO_CANNOT_DOVERB_NOW
;
1008 catch (uno::Exception
const&)
1010 TOOLS_WARN_EXCEPTION("embeddedobj", "SfxInPlaceClient::DoVerb");
1011 nError
= ERRCODE_SO_GENERALERROR
;
1012 //TODO/LATER: better error handling
1015 if (comphelper::LibreOfficeKit::isActive() && !bMapModeEnabled
1016 && pEditWin
->IsMapModeEnabled())
1018 pEditWin
->EnableMapMode(false);
1020 SfxViewFrame
& rFrame
= m_pViewSh
->GetViewFrame();
1021 rFrame
.GetFrame().LockResize_Impl(false);
1022 rFrame
.GetFrame().Resize();
1028 ErrorHandler::HandleError( nError
);
1033 void SfxInPlaceClient::VisAreaChanged()
1035 uno::Reference
< embed::XInplaceObject
> xObj( m_xImp
->m_xObject
, uno::UNO_QUERY
);
1037 m_xImp
->SizeHasChanged();
1040 void SfxInPlaceClient::ObjectAreaChanged()
1042 // dummy implementation
1045 void SfxInPlaceClient::RequestNewObjectArea( tools::Rectangle
& )
1047 // dummy implementation
1050 void SfxInPlaceClient::ViewChanged()
1052 // dummy implementation
1055 void SfxInPlaceClient::FormatChanged()
1057 // dummy implementation
1060 bool SfxInPlaceClient::IsProtected() const { return false; }
1062 void SfxInPlaceClient::DeactivateObject()
1064 if ( !GetObject().is() )
1069 m_xImp
->m_bUIActive
= false;
1070 bool bHasFocus
= false;
1071 uno::Reference
< frame::XModel
> xModel( m_xImp
->m_xObject
->getComponent(), uno::UNO_QUERY
);
1074 uno::Reference
< frame::XController
> xController
= xModel
->getCurrentController();
1075 if ( xController
.is() )
1077 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow( xController
->getFrame()->getContainerWindow() );
1078 bHasFocus
= pWindow
->HasChildPathFocus( true );
1082 m_pViewSh
->GetViewFrame().GetFrame().LockResize_Impl(true);
1084 if ( m_xImp
->m_xObject
->getStatus( m_xImp
->m_nAspect
) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE
)
1086 m_xImp
->m_xObject
->changeState( embed::EmbedStates::INPLACE_ACTIVE
);
1088 m_pViewSh
->GetWindow()->GrabFocus();
1092 // the links should not stay in running state for long time because of locking
1093 uno::Reference
< embed::XLinkageSupport
> xLink( m_xImp
->m_xObject
, uno::UNO_QUERY
);
1094 if ( xLink
.is() && xLink
->isLink() )
1095 m_xImp
->m_xObject
->changeState( embed::EmbedStates::LOADED
);
1097 m_xImp
->m_xObject
->changeState( embed::EmbedStates::RUNNING
);
1100 SfxViewFrame
& rFrame
= m_pViewSh
->GetViewFrame();
1101 SfxViewFrame::SetViewFrame( &rFrame
);
1102 rFrame
.GetFrame().LockResize_Impl(false);
1103 rFrame
.GetFrame().Resize();
1105 catch (css::uno::Exception
& )
1109 void SfxInPlaceClient::ResetObject()
1111 if ( !GetObject().is() )
1116 m_xImp
->m_bUIActive
= false;
1117 if ( m_xImp
->m_xObject
->getStatus( m_xImp
->m_nAspect
) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE
)
1118 m_xImp
->m_xObject
->changeState( embed::EmbedStates::INPLACE_ACTIVE
);
1121 // the links should not stay in running state for long time because of locking
1122 uno::Reference
< embed::XLinkageSupport
> xLink( m_xImp
->m_xObject
, uno::UNO_QUERY
);
1123 if ( xLink
.is() && xLink
->isLink() )
1124 m_xImp
->m_xObject
->changeState( embed::EmbedStates::LOADED
);
1126 m_xImp
->m_xObject
->changeState( embed::EmbedStates::RUNNING
);
1129 catch (css::uno::Exception
& )
1133 bool SfxInPlaceClient::IsUIActive() const
1135 return m_xImp
->m_bUIActive
;
1138 void SfxInPlaceClient::SetNegativeX(bool bSet
)
1140 m_xImp
->m_bNegativeX
= bSet
;
1143 bool SfxInPlaceClient::IsNegativeX() const
1145 return m_xImp
->m_bNegativeX
;
1148 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */