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 <com/sun/star/embed/EmbedStates.hpp>
21 #include <com/sun/star/embed/UnreachableStateException.hpp>
22 #include <com/sun/star/embed/XVisualObject.hpp>
23 #include <com/sun/star/embed/XEmbeddedClient.hpp>
24 #include <com/sun/star/embed/XInplaceClient.hpp>
25 #include <com/sun/star/embed/XInplaceObject.hpp>
26 #include <com/sun/star/embed/XComponentSupplier.hpp>
27 #include <com/sun/star/embed/XWindowSupplier.hpp>
28 #include <com/sun/star/embed/XEmbedPersist.hpp>
29 #include <com/sun/star/embed/EmbedVerbs.hpp>
30 #include <com/sun/star/embed/XEmbeddedOleObject.hpp>
31 #include <com/sun/star/container/XChild.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <com/sun/star/embed/XStateChangeListener.hpp>
35 #include <com/sun/star/embed/StateChangeInProgressException.hpp>
36 #include <com/sun/star/embed/XLinkageSupport.hpp>
37 #include <com/sun/star/lang/XInitialization.hpp>
38 #include <com/sun/star/task/ErrorCodeIOException.hpp>
39 #include <com/sun/star/task/StatusIndicatorFactory.hpp>
40 #include <com/sun/star/task/XStatusIndicator.hpp>
42 #include <com/sun/star/embed/EmbedMisc.hpp>
43 #include <svtools/embedhlp.hxx>
44 #include <vcl/svapp.hxx>
46 #include <sfx2/ipclient.hxx>
47 #include <sfx2/viewsh.hxx>
48 #include <sfx2/viewfrm.hxx>
49 #include <sfx2/objsh.hxx>
50 #include <sfx2/dispatch.hxx>
51 #include <workwin.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/awt/vclxwindow.hxx>
59 #include <toolkit/helper/vclunohelper.hxx>
60 #include <toolkit/helper/convert.hxx>
61 #include <tools/fract.hxx>
62 #include <tools/gen.hxx>
63 #include <svl/rectitem.hxx>
64 #include <svtools/soerr.hxx>
65 #include <comphelper/processfactory.hxx>
67 #include <sfx2/lokhelper.hxx>
69 #define SFX_CLIENTACTIVATE_TIMEOUT 100
71 using namespace com::sun::star
;
74 // SfxEmbedResizeGuard
75 class SfxBooleanFlagGuard
80 explicit SfxBooleanFlagGuard(bool& bFlag
)
82 , m_bLifeValue( true )
84 m_rFlag
= m_bLifeValue
;
87 ~SfxBooleanFlagGuard()
89 m_rFlag
= !m_bLifeValue
;
94 // SfxInPlaceClient_Impl
97 class SfxInPlaceClient_Impl
: public ::cppu::WeakImplHelper
< embed::XEmbeddedClient
,
98 embed::XInplaceClient
,
99 document::XEventListener
,
100 embed::XStateChangeListener
,
101 embed::XWindowSupplier
>
104 Timer m_aTimer
; // activation timeout, starts after object connection
105 tools::Rectangle m_aObjArea
; // area of object in coordinate system of the container (without scaling)
106 Fraction m_aScaleWidth
; // scaling that was applied to the object when it was not active
107 Fraction m_aScaleHeight
;
108 SfxInPlaceClient
* m_pClient
;
109 sal_Int64 m_nAspect
; // ViewAspect that is assigned from the container
111 bool m_bUIActive
; // set and cleared when notification for UI (de)activation is sent
112 bool m_bResizeNoScale
;
114 uno::Reference
< embed::XEmbeddedObject
> m_xObject
;
115 uno::Reference
< embed::XEmbeddedClient
> m_xClient
;
118 SfxInPlaceClient_Impl()
119 : m_pClient( nullptr )
121 , m_bStoreObject( true )
122 , m_bUIActive( false )
123 , m_bResizeNoScale( false )
126 void SizeHasChanged();
127 DECL_LINK(TimerHdl
, Timer
*, void);
128 uno::Reference
< frame::XFrame
> const & GetFrame() const;
131 virtual void SAL_CALL
saveObject() override
;
132 virtual void SAL_CALL
visibilityChanged( sal_Bool bVisible
) override
;
135 virtual sal_Bool SAL_CALL
canInplaceActivate() override
;
136 virtual void SAL_CALL
activatingInplace() override
;
137 virtual void SAL_CALL
activatingUI() override
;
138 virtual void SAL_CALL
deactivatedInplace() override
;
139 virtual void SAL_CALL
deactivatedUI() override
;
140 virtual uno::Reference
< css::frame::XLayoutManager
> SAL_CALL
getLayoutManager() override
;
141 virtual uno::Reference
< frame::XDispatchProvider
> SAL_CALL
getInplaceDispatchProvider() override
;
142 virtual awt::Rectangle SAL_CALL
getPlacement() override
;
143 virtual awt::Rectangle SAL_CALL
getClipRectangle() override
;
144 virtual void SAL_CALL
translateAccelerators( const uno::Sequence
< awt::KeyEvent
>& aKeys
) override
;
145 virtual void SAL_CALL
scrollObject( const awt::Size
& aOffset
) override
;
146 virtual void SAL_CALL
changedPlacement( const awt::Rectangle
& aPosRect
) override
;
148 // XComponentSupplier
149 virtual uno::Reference
< util::XCloseable
> SAL_CALL
getComponent() override
;
152 virtual uno::Reference
< awt::XWindow
> SAL_CALL
getWindow() override
;
154 // document::XEventListener
155 virtual void SAL_CALL
notifyEvent( const document::EventObject
& aEvent
) override
;
157 // XStateChangeListener
158 virtual void SAL_CALL
changingState( const css::lang::EventObject
& aEvent
, ::sal_Int32 nOldState
, ::sal_Int32 nNewState
) override
;
159 virtual void SAL_CALL
stateChanged( const css::lang::EventObject
& aEvent
, ::sal_Int32 nOldState
, ::sal_Int32 nNewState
) override
;
160 virtual void SAL_CALL
disposing( const css::lang::EventObject
& aEvent
) override
;
163 void SAL_CALL
SfxInPlaceClient_Impl::changingState(
164 const css::lang::EventObject
& /*aEvent*/,
165 ::sal_Int32
/*nOldState*/,
166 ::sal_Int32
/*nNewState*/ )
170 void SAL_CALL
SfxInPlaceClient_Impl::stateChanged(
171 const css::lang::EventObject
& /*aEvent*/,
172 ::sal_Int32 nOldState
,
173 ::sal_Int32 nNewState
)
175 if ( m_pClient
&& nOldState
!= embed::EmbedStates::LOADED
&& nNewState
== embed::EmbedStates::RUNNING
)
177 // deactivation of object
178 uno::Reference
< frame::XModel
> xDocument
;
179 if ( m_pClient
->GetViewShell()->GetObjectShell() )
180 xDocument
= m_pClient
->GetViewShell()->GetObjectShell()->GetModel();
181 SfxObjectShell::SetCurrentComponent( xDocument
);
185 void SAL_CALL
SfxInPlaceClient_Impl::notifyEvent( const document::EventObject
& aEvent
)
187 SolarMutexGuard aGuard
;
189 if ( m_pClient
&& aEvent
.EventName
== "OnVisAreaChanged" && m_nAspect
!= embed::Aspects::MSOLE_ICON
)
191 m_pClient
->FormatChanged(); // for Writer when format of the object is changed with the area
192 m_pClient
->ViewChanged();
193 m_pClient
->Invalidate();
197 void SAL_CALL
SfxInPlaceClient_Impl::disposing( const css::lang::EventObject
& /*aEvent*/ )
199 DELETEZ( m_pClient
);
204 uno::Reference
< frame::XFrame
> const & SfxInPlaceClient_Impl::GetFrame() const
207 throw uno::RuntimeException();
208 return m_pClient
->GetViewShell()->GetViewFrame()->GetFrame().GetFrameInterface();
211 void SAL_CALL
SfxInPlaceClient_Impl::saveObject()
213 if ( !m_bStoreObject
)
214 // client wants to discard the object (usually it means the container document is closed while an object is active
215 // and the user didn't request saving the changes
218 // the common persistence is supported by objects and links
219 uno::Reference
< embed::XCommonEmbedPersist
> xPersist( m_xObject
, uno::UNO_QUERY_THROW
);
221 uno::Reference
< frame::XFrame
> xFrame
;
222 uno::Reference
< task::XStatusIndicator
> xStatusIndicator
;
223 uno::Reference
< frame::XModel
> xModel( m_xObject
->getComponent(), uno::UNO_QUERY
);
224 uno::Reference
< uno::XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
228 uno::Reference
< frame::XController
> xController
= xModel
->getCurrentController();
229 if ( xController
.is() )
230 xFrame
= xController
->getFrame();
235 // set non-reschedule progress to prevent problems when asynchronous calls are made
236 // during storing of the embedded object
237 uno::Reference
< task::XStatusIndicatorFactory
> xStatusIndicatorFactory
=
238 task::StatusIndicatorFactory::createWithFrame( xContext
, xFrame
, true/*DisableReschedule*/, false/*AllowParentShow*/ );
240 uno::Reference
< beans::XPropertySet
> xPropSet( xFrame
, uno::UNO_QUERY
);
245 xStatusIndicator
= xStatusIndicatorFactory
->createStatusIndicator();
246 xPropSet
->setPropertyValue( "IndicatorInterception" , uno::makeAny( xStatusIndicator
));
248 catch ( const uno::RuntimeException
& )
252 catch ( uno::Exception
& )
260 xPersist
->storeOwn();
263 catch ( uno::Exception
& )
265 //TODO/LATER: what should happen if object can't be saved?!
268 // reset status indicator interception after storing
271 uno::Reference
< beans::XPropertySet
> xPropSet( xFrame
, uno::UNO_QUERY
);
274 xStatusIndicator
.clear();
275 xPropSet
->setPropertyValue( "IndicatorInterception" , uno::makeAny( xStatusIndicator
));
278 catch ( const uno::RuntimeException
& )
282 catch ( uno::Exception
& )
286 // the client can exist only in case there is a view shell
287 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
288 throw uno::RuntimeException();
290 SfxObjectShell
* pDocShell
= m_pClient
->GetViewShell()->GetObjectShell();
292 throw uno::RuntimeException();
294 pDocShell
->SetModified();
296 //TODO/LATER: invalidation might be necessary when object was modified, but is not
297 //saved through this method
298 // m_pClient->Invalidate();
302 void SAL_CALL
SfxInPlaceClient_Impl::visibilityChanged( sal_Bool bVisible
)
304 SolarMutexGuard aGuard
;
306 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
307 throw uno::RuntimeException();
309 m_pClient
->GetViewShell()->OutplaceActivated( bVisible
);
310 m_pClient
->Invalidate();
316 sal_Bool SAL_CALL
SfxInPlaceClient_Impl::canInplaceActivate()
318 if ( !m_xObject
.is() )
319 throw uno::RuntimeException();
321 // we don't want to switch directly from outplace to inplace mode
322 if ( m_xObject
->getCurrentState() == embed::EmbedStates::ACTIVE
|| m_nAspect
== embed::Aspects::MSOLE_ICON
)
329 void SAL_CALL
SfxInPlaceClient_Impl::activatingInplace()
331 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
332 throw uno::RuntimeException();
336 void SAL_CALL
SfxInPlaceClient_Impl::activatingUI()
338 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
339 throw uno::RuntimeException();
341 m_pClient
->GetViewShell()->ResetAllClients_Impl(m_pClient
);
343 m_pClient
->GetViewShell()->UIActivating( m_pClient
);
347 void SAL_CALL
SfxInPlaceClient_Impl::deactivatedInplace()
349 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
350 throw uno::RuntimeException();
354 void SAL_CALL
SfxInPlaceClient_Impl::deactivatedUI()
356 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
357 throw uno::RuntimeException();
359 m_pClient
->GetViewShell()->UIDeactivated( m_pClient
);
364 uno::Reference
< css::frame::XLayoutManager
> SAL_CALL
SfxInPlaceClient_Impl::getLayoutManager()
366 uno::Reference
< beans::XPropertySet
> xFrame( GetFrame(), uno::UNO_QUERY_THROW
);
368 uno::Reference
< css::frame::XLayoutManager
> xMan
;
371 uno::Any aAny
= xFrame
->getPropertyValue( "LayoutManager" );
374 catch ( uno::Exception
& )
376 throw uno::RuntimeException();
383 uno::Reference
< frame::XDispatchProvider
> SAL_CALL
SfxInPlaceClient_Impl::getInplaceDispatchProvider()
385 return uno::Reference
< frame::XDispatchProvider
>( GetFrame(), uno::UNO_QUERY_THROW
);
389 awt::Rectangle SAL_CALL
SfxInPlaceClient_Impl::getPlacement()
391 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
392 throw uno::RuntimeException();
394 // apply scaling to object area and convert to pixels
395 tools::Rectangle
aRealObjArea( m_aObjArea
);
396 aRealObjArea
.SetSize( Size( long( aRealObjArea
.GetWidth() * m_aScaleWidth
),
397 long( aRealObjArea
.GetHeight() * m_aScaleHeight
) ) );
399 // In Writer and Impress the map mode is disabled. So when a chart is
400 // activated (for in place editing) we get the chart win size in 100th mm
401 // and any method that should return pixels returns 100th mm and the chart
402 // window map mode has a ~26.485 scale factor.
403 // All that does not fit with current implementation for handling chart
405 if (comphelper::LibreOfficeKit::isActive())
407 vcl::Window
* pEditWin
= m_pClient
->GetEditWin();
408 bool bMapModeEnabled
= pEditWin
->IsMapModeEnabled();
409 if (!bMapModeEnabled
)
410 pEditWin
->EnableMapMode();
411 aRealObjArea
= m_pClient
->GetEditWin()->LogicToPixel( aRealObjArea
);
412 if (!bMapModeEnabled
&& pEditWin
->IsMapModeEnabled())
413 pEditWin
->EnableMapMode(false);
417 aRealObjArea
= m_pClient
->GetEditWin()->LogicToPixel( aRealObjArea
);
420 return AWTRectangle( aRealObjArea
);
424 awt::Rectangle SAL_CALL
SfxInPlaceClient_Impl::getClipRectangle()
426 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
427 throw uno::RuntimeException();
429 // currently(?) same as placement
430 tools::Rectangle
aRealObjArea( m_aObjArea
);
431 aRealObjArea
.SetSize( Size( long( aRealObjArea
.GetWidth() * m_aScaleWidth
),
432 long( aRealObjArea
.GetHeight() * m_aScaleHeight
) ) );
434 // See comment for SfxInPlaceClient_Impl::getPlacement.
435 if (comphelper::LibreOfficeKit::isActive())
437 vcl::Window
* pEditWin
= m_pClient
->GetEditWin();
438 bool bMapModeEnabled
= pEditWin
->IsMapModeEnabled();
439 if (!bMapModeEnabled
)
440 pEditWin
->EnableMapMode();
441 aRealObjArea
= m_pClient
->GetEditWin()->LogicToPixel( aRealObjArea
);
442 if (!bMapModeEnabled
&& pEditWin
->IsMapModeEnabled())
443 pEditWin
->EnableMapMode(false);
447 aRealObjArea
= m_pClient
->GetEditWin()->LogicToPixel( aRealObjArea
);
450 return AWTRectangle( aRealObjArea
);
454 void SAL_CALL
SfxInPlaceClient_Impl::translateAccelerators( const uno::Sequence
< awt::KeyEvent
>& /*aKeys*/ )
456 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
457 throw uno::RuntimeException();
459 // TODO/MBA: keyboard accelerators
463 void SAL_CALL
SfxInPlaceClient_Impl::scrollObject( const awt::Size
& /*aOffset*/ )
465 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
466 throw uno::RuntimeException();
470 void SAL_CALL
SfxInPlaceClient_Impl::changedPlacement( const awt::Rectangle
& aPosRect
)
472 uno::Reference
< embed::XInplaceObject
> xInplace( m_xObject
, uno::UNO_QUERY_THROW
);
473 if ( !m_pClient
|| !m_pClient
->GetEditWin() || !m_pClient
->GetViewShell() )
474 throw uno::RuntimeException();
476 // check if the change is at least one pixel in size
477 awt::Rectangle aOldRect
= getPlacement();
478 tools::Rectangle aNewPixelRect
= VCLRectangle( aPosRect
);
479 tools::Rectangle aOldPixelRect
= VCLRectangle( aOldRect
);
480 if ( aOldPixelRect
== aNewPixelRect
)
481 // nothing has changed
484 // new scaled object area
485 tools::Rectangle aNewLogicRect
= m_pClient
->GetEditWin()->PixelToLogic( aNewPixelRect
);
487 // all the size changes in this method should happen without scaling
488 // SfxBooleanFlagGuard aGuard( m_bResizeNoScale, sal_True );
490 // allow container to apply restrictions on the requested new area;
491 // the container might change the object view during size calculation;
492 // currently only writer does it
493 m_pClient
->RequestNewObjectArea( aNewLogicRect
);
495 if ( aNewLogicRect
!= m_pClient
->GetScaledObjArea() )
497 // the calculation of the object area has not changed the object size
498 // it should be done here then
499 SfxBooleanFlagGuard
aGuard( m_bResizeNoScale
);
501 // new size of the object area without scaling
502 Size
aNewObjSize( long( aNewLogicRect
.GetWidth() / m_aScaleWidth
),
503 long( aNewLogicRect
.GetHeight() / m_aScaleHeight
) );
505 // now remove scaling from new placement and keep this a the new object area
506 aNewLogicRect
.SetSize( aNewObjSize
);
507 m_aObjArea
= aNewLogicRect
;
509 // let the window size be recalculated
513 // notify container view about changes
514 m_pClient
->ObjectAreaChanged();
517 // XComponentSupplier
519 uno::Reference
< util::XCloseable
> SAL_CALL
SfxInPlaceClient_Impl::getComponent()
521 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
522 throw uno::RuntimeException();
524 SfxObjectShell
* pDocShell
= m_pClient
->GetViewShell()->GetObjectShell();
526 throw uno::RuntimeException();
528 // all the components must implement XCloseable
529 uno::Reference
< util::XCloseable
> xComp( pDocShell
->GetModel(), uno::UNO_QUERY_THROW
);
536 uno::Reference
< awt::XWindow
> SAL_CALL
SfxInPlaceClient_Impl::getWindow()
538 if ( !m_pClient
|| !m_pClient
->GetEditWin() )
539 throw uno::RuntimeException();
541 uno::Reference
< awt::XWindow
> xWin( m_pClient
->GetEditWin()->GetComponentInterface(), uno::UNO_QUERY
);
546 // notification to the client implementation that either the object area or the scaling has been changed
547 // as a result the logical size of the window has changed also
548 void SfxInPlaceClient_Impl::SizeHasChanged()
550 if ( !m_pClient
|| !m_pClient
->GetViewShell() )
551 throw uno::RuntimeException();
555 && ( m_xObject
->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE
556 || m_xObject
->getCurrentState() == embed::EmbedStates::UI_ACTIVE
) )
558 // only possible in active states
559 uno::Reference
< embed::XInplaceObject
> xInplace( m_xObject
, uno::UNO_QUERY_THROW
);
561 if ( m_bResizeNoScale
)
563 // the resizing should be done without scaling
564 // set the correct size to the object to avoid the scaling
565 MapMode
aObjectMap( VCLUnoHelper::UnoEmbed2VCLMapUnit( m_xObject
->getMapUnit( m_nAspect
) ) );
566 MapMode
aClientMap( m_pClient
->GetEditWin()->GetMapMode().GetMapUnit() );
568 // convert to logical coordinates of the embedded object
569 Size aNewSize
= m_pClient
->GetEditWin()->LogicToLogic( m_aObjArea
.GetSize(), &aClientMap
, &aObjectMap
);
570 m_xObject
->setVisualAreaSize( m_nAspect
, awt::Size( aNewSize
.Width(), aNewSize
.Height() ) );
573 xInplace
->setObjectRectangles( getPlacement(), getClipRectangle() );
576 catch( uno::Exception
& )
578 // TODO/LATER: handle error
583 IMPL_LINK_NOARG(SfxInPlaceClient_Impl
, TimerHdl
, Timer
*, void)
585 if ( m_pClient
&& m_xObject
.is() )
587 m_pClient
->GetViewShell()->CheckIPClient_Impl(m_pClient
,
588 m_pClient
->GetViewShell()->GetObjectShell()->GetVisArea());
596 SfxInPlaceClient::SfxInPlaceClient( SfxViewShell
* pViewShell
, vcl::Window
*pDraw
, sal_Int64 nAspect
) :
597 m_xImp( new SfxInPlaceClient_Impl
),
598 m_pViewSh( pViewShell
),
601 m_xImp
->m_pClient
= this;
602 m_xImp
->m_nAspect
= nAspect
;
603 m_xImp
->m_aScaleWidth
= m_xImp
->m_aScaleHeight
= Fraction(1,1);
604 m_xImp
->m_xClient
= static_cast< embed::XEmbeddedClient
* >( m_xImp
.get() );
605 pViewShell
->NewIPClient_Impl(this);
606 m_xImp
->m_aTimer
.SetDebugName( "sfx::SfxInPlaceClient m_xImpl::m_aTimer" );
607 m_xImp
->m_aTimer
.SetTimeout( SFX_CLIENTACTIVATE_TIMEOUT
);
608 m_xImp
->m_aTimer
.SetInvokeHandler( LINK( m_xImp
.get(), SfxInPlaceClient_Impl
, TimerHdl
) );
612 SfxInPlaceClient::~SfxInPlaceClient()
614 m_pViewSh
->IPClientGone_Impl(this);
616 // deleting the client before storing the object means discarding all changes
617 m_xImp
->m_bStoreObject
= false;
620 m_xImp
->m_pClient
= nullptr;
622 // the next call will destroy m_xImp if no other reference to it exists
623 m_xImp
->m_xClient
.clear();
626 // the class is not intended to be used in multithreaded environment;
627 // if it will this disconnection and all the parts that use the m_pClient
628 // must be guarded with mutex
632 void SfxInPlaceClient::SetObjectState( sal_Int32 nState
)
634 if ( GetObject().is() )
636 if ( m_xImp
->m_nAspect
== embed::Aspects::MSOLE_ICON
637 && ( nState
== embed::EmbedStates::UI_ACTIVE
|| nState
== embed::EmbedStates::INPLACE_ACTIVE
) )
639 OSL_FAIL( "Iconified object should not be activated inplace!" );
645 GetObject()->changeState( nState
);
647 catch ( uno::Exception
& )
653 sal_Int64
SfxInPlaceClient::GetObjectMiscStatus() const
655 if ( GetObject().is() )
656 return GetObject()->getStatus( m_xImp
->m_nAspect
);
661 const uno::Reference
< embed::XEmbeddedObject
>& SfxInPlaceClient::GetObject() const
663 return m_xImp
->m_xObject
;
667 void SfxInPlaceClient::SetObject( const uno::Reference
< embed::XEmbeddedObject
>& rObject
)
669 if ( m_xImp
->m_xObject
.is() && rObject
!= m_xImp
->m_xObject
)
671 DBG_ASSERT( GetObject()->getClientSite() == m_xImp
->m_xClient
, "Wrong ClientSite!" );
672 if ( GetObject()->getClientSite() == m_xImp
->m_xClient
)
674 if ( GetObject()->getCurrentState() != embed::EmbedStates::LOADED
)
675 SetObjectState( embed::EmbedStates::RUNNING
);
676 m_xImp
->m_xObject
->removeEventListener( uno::Reference
< document::XEventListener
>( m_xImp
->m_xClient
, uno::UNO_QUERY
) );
677 m_xImp
->m_xObject
->removeStateChangeListener( uno::Reference
< embed::XStateChangeListener
>( m_xImp
->m_xClient
, uno::UNO_QUERY
) );
680 m_xImp
->m_xObject
->setClientSite( nullptr );
682 catch( uno::Exception
& )
684 OSL_FAIL( "Can not clean the client site!" );
689 if ( m_pViewSh
->GetViewFrame()->GetFrame().IsClosing_Impl() )
690 // sometimes applications reconnect clients on shutting down because it happens in their Paint methods
693 m_xImp
->m_xObject
= rObject
;
697 // as soon as an object was connected to a client it has to be checked whether the object wants
699 rObject
->addStateChangeListener( uno::Reference
< embed::XStateChangeListener
>( m_xImp
->m_xClient
, uno::UNO_QUERY
) );
700 rObject
->addEventListener( uno::Reference
< document::XEventListener
>( m_xImp
->m_xClient
, uno::UNO_QUERY
) );
704 rObject
->setClientSite( m_xImp
->m_xClient
);
706 catch( uno::Exception
& )
708 OSL_FAIL( "Can not set the client site!" );
711 m_xImp
->m_aTimer
.Start();
714 m_xImp
->m_aTimer
.Stop();
718 bool SfxInPlaceClient::SetObjArea( const tools::Rectangle
& rArea
)
720 if( rArea
!= m_xImp
->m_aObjArea
)
722 m_xImp
->m_aObjArea
= rArea
;
723 m_xImp
->SizeHasChanged();
733 const tools::Rectangle
& SfxInPlaceClient::GetObjArea() const
735 return m_xImp
->m_aObjArea
;
738 tools::Rectangle
SfxInPlaceClient::GetScaledObjArea() const
740 tools::Rectangle
aRealObjArea( m_xImp
->m_aObjArea
);
741 aRealObjArea
.SetSize( Size( long( aRealObjArea
.GetWidth() * m_xImp
->m_aScaleWidth
),
742 long( aRealObjArea
.GetHeight() * m_xImp
->m_aScaleHeight
) ) );
747 void SfxInPlaceClient::SetSizeScale( const Fraction
& rScaleWidth
, const Fraction
& rScaleHeight
)
749 if ( m_xImp
->m_aScaleWidth
!= rScaleWidth
|| m_xImp
->m_aScaleHeight
!= rScaleHeight
)
751 m_xImp
->m_aScaleWidth
= rScaleWidth
;
752 m_xImp
->m_aScaleHeight
= rScaleHeight
;
754 m_xImp
->SizeHasChanged();
756 // TODO/LATER: Invalidate seems to trigger (wrong) recalculations of the ObjArea, so it's better
757 // not to call it here, but maybe it sounds reasonable to do so.
763 void SfxInPlaceClient::SetObjAreaAndScale( const tools::Rectangle
& rArea
, const Fraction
& rScaleWidth
, const Fraction
& rScaleHeight
)
765 if( rArea
!= m_xImp
->m_aObjArea
|| m_xImp
->m_aScaleWidth
!= rScaleWidth
|| m_xImp
->m_aScaleHeight
!= rScaleHeight
)
767 m_xImp
->m_aObjArea
= rArea
;
768 m_xImp
->m_aScaleWidth
= rScaleWidth
;
769 m_xImp
->m_aScaleHeight
= rScaleHeight
;
771 m_xImp
->SizeHasChanged();
778 const Fraction
& SfxInPlaceClient::GetScaleWidth() const
780 return m_xImp
->m_aScaleWidth
;
784 const Fraction
& SfxInPlaceClient::GetScaleHeight() const
786 return m_xImp
->m_aScaleHeight
;
790 void SfxInPlaceClient::Invalidate()
792 // TODO/LATER: do we need both?
794 // the object area is provided in logical coordinates of the window but without scaling applied
795 tools::Rectangle
aRealObjArea( m_xImp
->m_aObjArea
);
796 aRealObjArea
.SetSize( Size( long( aRealObjArea
.GetWidth() * m_xImp
->m_aScaleWidth
),
797 long( aRealObjArea
.GetHeight() * m_xImp
->m_aScaleHeight
) ) );
798 m_pEditWin
->Invalidate( aRealObjArea
);
804 bool SfxInPlaceClient::IsObjectUIActive() const
807 return ( m_xImp
->m_xObject
.is() && ( m_xImp
->m_xObject
->getCurrentState() == embed::EmbedStates::UI_ACTIVE
) );
809 catch( uno::Exception
& )
816 bool SfxInPlaceClient::IsObjectInPlaceActive() const
821 m_xImp
->m_xObject
.is() &&
822 (m_xImp
->m_xObject
->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE
)
825 m_xImp
->m_xObject
.is() &&
826 (m_xImp
->m_xObject
->getCurrentState() == embed::EmbedStates::UI_ACTIVE
)
830 catch( uno::Exception
& )
837 SfxInPlaceClient
* SfxInPlaceClient::GetClient( SfxObjectShell
const * pDoc
, const css::uno::Reference
< css::embed::XEmbeddedObject
>& xObject
)
839 for ( SfxViewFrame
* pFrame
= SfxViewFrame::GetFirst(pDoc
); pFrame
; pFrame
=SfxViewFrame::GetNext(*pFrame
,pDoc
) )
841 if( pFrame
->GetViewShell() )
843 SfxInPlaceClient
* pClient
= pFrame
->GetViewShell()->FindIPClient( xObject
, nullptr );
852 sal_Int64
SfxInPlaceClient::GetAspect() const
854 return m_xImp
->m_nAspect
;
857 ErrCode
SfxInPlaceClient::DoVerb( long nVerb
)
859 vcl::Window
* pWin
= m_pViewSh
->GetWindow();
860 SfxErrorContext
aEc(ERRCTX_SO_DOVERB
, pWin
? pWin
->GetFrameWeld() : nullptr, RID_SO_ERRCTX
);
861 ErrCode nError
= ERRCODE_NONE
;
863 if ( m_xImp
->m_xObject
.is() )
865 bool bSaveCopyAs
= false;
866 if ( nVerb
== -8 ) // "Save Copy as..."
868 svt::EmbeddedObjectRef::TryRunningState( m_xImp
->m_xObject
);
869 // TODO/LATER: this special verb should disappear when outplace activation is completely available
870 uno::Reference
< frame::XModel
> xEmbModel( m_xImp
->m_xObject
->getComponent(), uno::UNO_QUERY
);
871 if ( xEmbModel
.is() )
877 SfxStoringHelper aHelper
;
878 uno::Sequence
< beans::PropertyValue
> aDispatchArgs( 1 );
879 aDispatchArgs
[0].Name
= "SaveTo";
880 aDispatchArgs
[0].Value
<<= true;
882 aHelper
.GUIStoreModel( xEmbModel
,
886 SignatureState::NOSIGNATURES
);
888 catch( const task::ErrorCodeIOException
& aErrorEx
)
890 nError
= ErrCode(aErrorEx
.ErrCode
);
892 catch( uno::Exception
& )
894 nError
= ERRCODE_IO_GENERAL
;
895 // TODO/LATER: better error handling
902 if ( m_xImp
->m_nAspect
== embed::Aspects::MSOLE_ICON
)
904 // the common persistence is supported by objects and links
906 uno::Reference
< embed::XEmbeddedOleObject
> xEmbeddedOleObject( m_xImp
->m_xObject
, uno::UNO_QUERY
);
908 if ( xEmbeddedOleObject
.is() && (nVerb
== embed::EmbedVerbs::MS_OLEVERB_PRIMARY
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_OPEN
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_SHOW
))
909 nVerb
= embed::EmbedVerbs::MS_OLEVERB_SHOW
;
910 else if ( nVerb
== embed::EmbedVerbs::MS_OLEVERB_PRIMARY
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_SHOW
)
911 nVerb
= embed::EmbedVerbs::MS_OLEVERB_OPEN
; // outplace activation
912 else if ( nVerb
== embed::EmbedVerbs::MS_OLEVERB_UIACTIVATE
913 || nVerb
== embed::EmbedVerbs::MS_OLEVERB_IPACTIVATE
)
914 nError
= ERRCODE_SO_GENERALERROR
;
919 // See comment for SfxInPlaceClient_Impl::getPlacement.
920 vcl::Window
* pEditWin
= GetEditWin();
921 bool bMapModeEnabled
= pEditWin
->IsMapModeEnabled();
922 if (comphelper::LibreOfficeKit::isActive() && !bMapModeEnabled
)
924 pEditWin
->EnableMapMode();
926 m_pViewSh
->GetViewFrame()->GetFrame().LockResize_Impl(true);
929 m_xImp
->m_xObject
->setClientSite( m_xImp
->m_xClient
);
931 m_xImp
->m_xObject
->doVerb( nVerb
);
933 catch ( embed::UnreachableStateException
& )
935 if (nVerb
== embed::EmbedVerbs::MS_OLEVERB_PRIMARY
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_OPEN
|| nVerb
== embed::EmbedVerbs::MS_OLEVERB_SHOW
)
937 // a workaround for the default verb, usually makes sense for alien objects
940 m_xImp
->m_xObject
->doVerb( -9 ); // open own view, a workaround verb that is not visible
942 if ( m_xImp
->m_xObject
->getCurrentState() == embed::EmbedStates::UI_ACTIVE
)
944 // the object was converted to OOo object
945 awt::Size aSize
= m_xImp
->m_xObject
->getVisualAreaSize( m_xImp
->m_nAspect
);
946 MapMode
aObjectMap( VCLUnoHelper::UnoEmbed2VCLMapUnit( m_xImp
->m_xObject
->getMapUnit( m_xImp
->m_nAspect
) ) );
947 MapMode
aClientMap( GetEditWin()->GetMapMode().GetMapUnit() );
948 Size aNewSize
= GetEditWin()->LogicToLogic( Size( aSize
.Width
, aSize
.Height
), &aObjectMap
, &aClientMap
);
950 tools::Rectangle aScaledArea
= GetScaledObjArea();
951 m_xImp
->m_aObjArea
.SetSize( aNewSize
);
952 m_xImp
->m_aScaleWidth
= Fraction( aScaledArea
.GetWidth(), aNewSize
.Width() );
953 m_xImp
->m_aScaleHeight
= Fraction( aScaledArea
.GetHeight(), aNewSize
.Height() );
956 catch (uno::Exception
const& e
)
958 SAL_WARN("embeddedobj", "SfxInPlaceClient::DoVerb: -9 fallback path: " << e
);
959 nError
= ERRCODE_SO_GENERALERROR
;
963 catch ( embed::StateChangeInProgressException
& )
965 // TODO/LATER: it would be nice to be able to provide the current target state outside
966 nError
= ERRCODE_SO_CANNOT_DOVERB_NOW
;
968 catch (uno::Exception
const& e
)
970 SAL_WARN("embeddedobj", "SfxInPlaceClient::DoVerb:"
971 " exception caught: " << e
);
972 nError
= ERRCODE_SO_GENERALERROR
;
973 //TODO/LATER: better error handling
976 if (comphelper::LibreOfficeKit::isActive() && !bMapModeEnabled
977 && pEditWin
->IsMapModeEnabled())
979 pEditWin
->EnableMapMode(false);
981 SfxViewFrame
* pFrame
= m_pViewSh
->GetViewFrame();
982 pFrame
->GetFrame().LockResize_Impl(false);
983 pFrame
->GetFrame().Resize();
989 ErrorHandler::HandleError( nError
);
994 void SfxInPlaceClient::VisAreaChanged()
996 uno::Reference
< embed::XInplaceObject
> xObj( m_xImp
->m_xObject
, uno::UNO_QUERY
);
997 uno::Reference
< embed::XInplaceClient
> xClient( m_xImp
->m_xClient
, uno::UNO_QUERY
);
998 if ( xObj
.is() && xClient
.is() )
999 m_xImp
->SizeHasChanged();
1002 void SfxInPlaceClient::ObjectAreaChanged()
1004 // dummy implementation
1007 void SfxInPlaceClient::RequestNewObjectArea( tools::Rectangle
& )
1009 // dummy implementation
1012 void SfxInPlaceClient::ViewChanged()
1014 // dummy implementation
1017 void SfxInPlaceClient::FormatChanged()
1019 // dummy implementation
1022 void SfxInPlaceClient::DeactivateObject()
1024 if ( GetObject().is() )
1028 m_xImp
->m_bUIActive
= false;
1029 bool bHasFocus
= false;
1030 uno::Reference
< frame::XModel
> xModel( m_xImp
->m_xObject
->getComponent(), uno::UNO_QUERY
);
1033 uno::Reference
< frame::XController
> xController
= xModel
->getCurrentController();
1034 if ( xController
.is() )
1036 VclPtr
<vcl::Window
> pWindow
= VCLUnoHelper::GetWindow( xController
->getFrame()->getContainerWindow() );
1037 bHasFocus
= pWindow
->HasChildPathFocus( true );
1041 m_pViewSh
->GetViewFrame()->GetFrame().LockResize_Impl(true);
1043 if ( (m_xImp
->m_xObject
->getStatus( m_xImp
->m_nAspect
) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE
) ||
1044 svt::EmbeddedObjectRef::IsGLChart(m_xImp
->m_xObject
) )
1046 m_xImp
->m_xObject
->changeState( embed::EmbedStates::INPLACE_ACTIVE
);
1048 m_pViewSh
->GetWindow()->GrabFocus();
1052 // the links should not stay in running state for long time because of locking
1053 uno::Reference
< embed::XLinkageSupport
> xLink( m_xImp
->m_xObject
, uno::UNO_QUERY
);
1054 if ( xLink
.is() && xLink
->isLink() )
1055 m_xImp
->m_xObject
->changeState( embed::EmbedStates::LOADED
);
1057 m_xImp
->m_xObject
->changeState( embed::EmbedStates::RUNNING
);
1060 SfxViewFrame
* pFrame
= m_pViewSh
->GetViewFrame();
1061 SfxViewFrame::SetViewFrame( pFrame
);
1062 pFrame
->GetFrame().LockResize_Impl(false);
1063 pFrame
->GetFrame().Resize();
1065 catch (css::uno::Exception
& )
1070 void SfxInPlaceClient::ResetObject()
1072 if ( GetObject().is() )
1076 m_xImp
->m_bUIActive
= false;
1077 if ( (m_xImp
->m_xObject
->getStatus( m_xImp
->m_nAspect
) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE
) ||
1078 svt::EmbeddedObjectRef::IsGLChart(m_xImp
->m_xObject
) )
1079 m_xImp
->m_xObject
->changeState( embed::EmbedStates::INPLACE_ACTIVE
);
1082 // the links should not stay in running state for long time because of locking
1083 uno::Reference
< embed::XLinkageSupport
> xLink( m_xImp
->m_xObject
, uno::UNO_QUERY
);
1084 if ( xLink
.is() && xLink
->isLink() )
1085 m_xImp
->m_xObject
->changeState( embed::EmbedStates::LOADED
);
1087 m_xImp
->m_xObject
->changeState( embed::EmbedStates::RUNNING
);
1090 catch (css::uno::Exception
& )
1095 bool SfxInPlaceClient::IsUIActive()
1097 return m_xImp
->m_bUIActive
;
1100 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */