Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / sfx2 / source / view / ipclient.cxx
blobfbba1febc5c18f8093844308a1701bd22c9b7cb6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/XWindowPeer.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>
47 #include <sfx2/ipclient.hxx>
48 #include <sfx2/viewsh.hxx>
49 #include <sfx2/viewfrm.hxx>
50 #include <sfx2/objsh.hxx>
51 #include <guisaveas.hxx>
52 #include <cppuhelper/implbase.hxx>
53 #include <svtools/ehdl.hxx>
55 #include <vcl/timer.hxx>
56 #include <vcl/window.hxx>
57 #include <toolkit/helper/vclunohelper.hxx>
58 #include <toolkit/helper/convert.hxx>
59 #include <tools/debug.hxx>
60 #include <tools/diagnose_ex.h>
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 <cppuhelper/exc_hlp.hxx>
68 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
70 #define SFX_CLIENTACTIVATE_TIMEOUT 100
72 using namespace com::sun::star;
74 namespace {
76 // SfxEmbedResizeGuard
77 class SfxBooleanFlagGuard
79 bool& m_rFlag;
80 public:
81 explicit SfxBooleanFlagGuard(bool& bFlag)
82 : m_rFlag( bFlag )
84 m_rFlag = true;
87 ~SfxBooleanFlagGuard()
89 m_rFlag = false;
95 // SfxInPlaceClient_Impl
98 class SfxInPlaceClient_Impl : public ::cppu::WeakImplHelper< embed::XEmbeddedClient,
99 embed::XInplaceClient,
100 document::XEventListener,
101 embed::XStateChangeListener,
102 embed::XWindowSupplier >
104 public:
105 Timer m_aTimer; // activation timeout, starts after object connection
106 tools::Rectangle m_aObjArea; // area of object in coordinate system of the container (without scaling)
107 Fraction m_aScaleWidth; // scaling that was applied to the object when it was not active
108 Fraction m_aScaleHeight;
109 SfxInPlaceClient* m_pClient;
110 sal_Int64 m_nAspect; // ViewAspect that is assigned from the container
111 bool m_bStoreObject;
112 bool m_bUIActive; // set and cleared when notification for UI (de)activation is sent
113 bool m_bResizeNoScale;
115 uno::Reference < embed::XEmbeddedObject > m_xObject;
118 SfxInPlaceClient_Impl()
119 : m_pClient( nullptr )
120 , m_nAspect( 0 )
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;
130 // XEmbeddedClient
131 virtual void SAL_CALL saveObject() override;
132 virtual void SAL_CALL visibilityChanged( sal_Bool bVisible ) override;
134 // XInplaceClient
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;
151 // XWindowSupplier
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 if ( comphelper::LibreOfficeKit::isActive() )
193 if ( SfxViewShell* pViewShell = m_pClient->GetViewShell() )
194 pViewShell->libreOfficeKitViewCallback( LOK_CALLBACK_GRAPHIC_SELECTION, "INPLACE" );
197 m_pClient->FormatChanged(); // for Writer when format of the object is changed with the area
198 m_pClient->ViewChanged();
199 m_pClient->Invalidate();
203 void SAL_CALL SfxInPlaceClient_Impl::disposing( const css::lang::EventObject& /*aEvent*/ )
205 delete m_pClient;
206 m_pClient = nullptr;
209 // XEmbeddedClient
211 uno::Reference < frame::XFrame > const & SfxInPlaceClient_Impl::GetFrame() const
213 if ( !m_pClient )
214 throw uno::RuntimeException();
215 return m_pClient->GetViewShell()->GetViewFrame()->GetFrame().GetFrameInterface();
218 void SAL_CALL SfxInPlaceClient_Impl::saveObject()
220 if ( !m_bStoreObject )
221 // client wants to discard the object (usually it means the container document is closed while an object is active
222 // and the user didn't request saving the changes
223 return;
225 // the common persistence is supported by objects and links
226 uno::Reference< embed::XCommonEmbedPersist > xPersist( m_xObject, uno::UNO_QUERY_THROW );
228 uno::Reference< frame::XFrame > xFrame;
229 uno::Reference< task::XStatusIndicator > xStatusIndicator;
230 uno::Reference< frame::XModel > xModel( m_xObject->getComponent(), uno::UNO_QUERY );
231 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
233 if ( xModel.is() )
235 uno::Reference< frame::XController > xController = xModel->getCurrentController();
236 if ( xController.is() )
237 xFrame = xController->getFrame();
240 if ( xFrame.is() )
242 // set non-reschedule progress to prevent problems when asynchronous calls are made
243 // during storing of the embedded object
244 uno::Reference< task::XStatusIndicatorFactory > xStatusIndicatorFactory =
245 task::StatusIndicatorFactory::createWithFrame( xContext, xFrame, true/*DisableReschedule*/, false/*AllowParentShow*/ );
247 uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
248 if ( xPropSet.is() )
252 xStatusIndicator = xStatusIndicatorFactory->createStatusIndicator();
253 xPropSet->setPropertyValue( "IndicatorInterception" , uno::makeAny( xStatusIndicator ));
255 catch ( const uno::RuntimeException& )
257 throw;
259 catch ( uno::Exception& )
267 xPersist->storeOwn();
268 m_xObject->update();
270 catch ( uno::Exception& )
272 //TODO/LATER: what should happen if object can't be saved?!
275 // reset status indicator interception after storing
278 uno::Reference< beans::XPropertySet > xPropSet( xFrame, uno::UNO_QUERY );
279 if ( xPropSet.is() )
281 xStatusIndicator.clear();
282 xPropSet->setPropertyValue( "IndicatorInterception" , uno::makeAny( xStatusIndicator ));
285 catch ( const uno::RuntimeException& )
287 throw;
289 catch ( uno::Exception& )
293 // the client can exist only in case there is a view shell
294 if ( !m_pClient || !m_pClient->GetViewShell() )
295 throw uno::RuntimeException();
297 SfxObjectShell* pDocShell = m_pClient->GetViewShell()->GetObjectShell();
298 if ( !pDocShell )
299 throw uno::RuntimeException();
301 pDocShell->SetModified();
303 //TODO/LATER: invalidation might be necessary when object was modified, but is not
304 //saved through this method
305 // m_pClient->Invalidate();
309 void SAL_CALL SfxInPlaceClient_Impl::visibilityChanged( sal_Bool bVisible )
311 SolarMutexGuard aGuard;
313 if ( !m_pClient || !m_pClient->GetViewShell() )
314 throw uno::RuntimeException();
316 m_pClient->GetViewShell()->OutplaceActivated( bVisible );
317 m_pClient->Invalidate();
321 // XInplaceClient
323 sal_Bool SAL_CALL SfxInPlaceClient_Impl::canInplaceActivate()
325 if ( !m_xObject.is() )
326 throw uno::RuntimeException();
328 // we don't want to switch directly from outplace to inplace mode
329 if ( m_xObject->getCurrentState() == embed::EmbedStates::ACTIVE || m_nAspect == embed::Aspects::MSOLE_ICON )
330 return false;
332 return true;
336 void SAL_CALL SfxInPlaceClient_Impl::activatingInplace()
338 if ( !m_pClient || !m_pClient->GetViewShell() )
339 throw uno::RuntimeException();
341 if ( comphelper::LibreOfficeKit::isActive() )
343 if ( SfxViewShell* pViewShell = m_pClient->GetViewShell() )
344 pViewShell->libreOfficeKitViewCallback( LOK_CALLBACK_GRAPHIC_SELECTION, "INPLACE" );
350 void SAL_CALL SfxInPlaceClient_Impl::activatingUI()
352 if ( !m_pClient || !m_pClient->GetViewShell() )
353 throw uno::RuntimeException();
355 m_pClient->GetViewShell()->ResetAllClients_Impl(m_pClient);
356 m_bUIActive = true;
357 m_pClient->GetViewShell()->UIActivating( m_pClient );
361 void SAL_CALL SfxInPlaceClient_Impl::deactivatedInplace()
363 if ( !m_pClient || !m_pClient->GetViewShell() )
364 throw uno::RuntimeException();
366 if ( comphelper::LibreOfficeKit::isActive() )
368 if ( SfxViewShell* pViewShell = m_pClient->GetViewShell() ) {
369 pViewShell->libreOfficeKitViewCallback( LOK_CALLBACK_GRAPHIC_SELECTION, "INPLACE EXIT" );
375 void SAL_CALL SfxInPlaceClient_Impl::deactivatedUI()
377 if ( !m_pClient || !m_pClient->GetViewShell() )
378 throw uno::RuntimeException();
380 m_pClient->GetViewShell()->UIDeactivated( m_pClient );
381 m_bUIActive = false;
385 uno::Reference< css::frame::XLayoutManager > SAL_CALL SfxInPlaceClient_Impl::getLayoutManager()
387 uno::Reference < beans::XPropertySet > xFrame( GetFrame(), uno::UNO_QUERY_THROW );
389 uno::Reference< css::frame::XLayoutManager > xMan;
392 uno::Any aAny = xFrame->getPropertyValue( "LayoutManager" );
393 aAny >>= xMan;
395 catch ( uno::Exception& ex )
397 css::uno::Any anyEx = cppu::getCaughtException();
398 throw css::lang::WrappedTargetRuntimeException( ex.Message,
399 nullptr, anyEx );
402 return xMan;
406 uno::Reference< frame::XDispatchProvider > SAL_CALL SfxInPlaceClient_Impl::getInplaceDispatchProvider()
408 return uno::Reference < frame::XDispatchProvider >( GetFrame(), uno::UNO_QUERY_THROW );
412 awt::Rectangle SAL_CALL SfxInPlaceClient_Impl::getPlacement()
414 if ( !m_pClient || !m_pClient->GetViewShell() )
415 throw uno::RuntimeException();
417 // apply scaling to object area and convert to pixels
418 tools::Rectangle aRealObjArea( m_aObjArea );
419 aRealObjArea.SetSize( Size( tools::Long( aRealObjArea.GetWidth() * m_aScaleWidth),
420 tools::Long( aRealObjArea.GetHeight() * m_aScaleHeight) ) );
422 // In Writer and Impress the map mode is disabled. So when a chart is
423 // activated (for in place editing) we get the chart win size in 100th mm
424 // and any method that should return pixels returns 100th mm and the chart
425 // window map mode has a ~26.485 scale factor.
426 // All that does not fit with current implementation for handling chart
427 // editing in LOK.
428 if (comphelper::LibreOfficeKit::isActive())
430 vcl::Window* pEditWin = m_pClient->GetEditWin();
431 bool bMapModeEnabled = pEditWin->IsMapModeEnabled();
432 if (!bMapModeEnabled)
433 pEditWin->EnableMapMode();
434 aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
435 if (!bMapModeEnabled && pEditWin->IsMapModeEnabled())
436 pEditWin->EnableMapMode(false);
438 else
440 aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
443 return AWTRectangle( aRealObjArea );
447 awt::Rectangle SAL_CALL SfxInPlaceClient_Impl::getClipRectangle()
449 if ( !m_pClient || !m_pClient->GetViewShell() )
450 throw uno::RuntimeException();
452 // currently(?) same as placement
453 tools::Rectangle aRealObjArea( m_aObjArea );
454 aRealObjArea.SetSize( Size( tools::Long( aRealObjArea.GetWidth() * m_aScaleWidth),
455 tools::Long( aRealObjArea.GetHeight() * m_aScaleHeight) ) );
457 // See comment for SfxInPlaceClient_Impl::getPlacement.
458 if (comphelper::LibreOfficeKit::isActive())
460 vcl::Window* pEditWin = m_pClient->GetEditWin();
461 bool bMapModeEnabled = pEditWin->IsMapModeEnabled();
462 if (!bMapModeEnabled)
463 pEditWin->EnableMapMode();
464 aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
465 if (!bMapModeEnabled && pEditWin->IsMapModeEnabled())
466 pEditWin->EnableMapMode(false);
468 else
470 aRealObjArea = m_pClient->GetEditWin()->LogicToPixel( aRealObjArea );
473 return AWTRectangle( aRealObjArea );
477 void SAL_CALL SfxInPlaceClient_Impl::translateAccelerators( const uno::Sequence< awt::KeyEvent >& /*aKeys*/ )
479 if ( !m_pClient || !m_pClient->GetViewShell() )
480 throw uno::RuntimeException();
482 // TODO/MBA: keyboard accelerators
486 void SAL_CALL SfxInPlaceClient_Impl::scrollObject( const awt::Size& /*aOffset*/ )
488 if ( !m_pClient || !m_pClient->GetViewShell() )
489 throw uno::RuntimeException();
493 void SAL_CALL SfxInPlaceClient_Impl::changedPlacement( const awt::Rectangle& aPosRect )
495 uno::Reference< embed::XInplaceObject > xInplace( m_xObject, uno::UNO_QUERY_THROW );
496 if ( !m_pClient || !m_pClient->GetEditWin() || !m_pClient->GetViewShell() )
497 throw uno::RuntimeException();
499 // check if the change is at least one pixel in size
500 awt::Rectangle aOldRect = getPlacement();
501 tools::Rectangle aNewPixelRect = VCLRectangle( aPosRect );
502 tools::Rectangle aOldPixelRect = VCLRectangle( aOldRect );
503 if ( aOldPixelRect == aNewPixelRect )
504 // nothing has changed
505 return;
507 // new scaled object area
508 tools::Rectangle aNewLogicRect = m_pClient->GetEditWin()->PixelToLogic( aNewPixelRect );
510 // all the size changes in this method should happen without scaling
511 // SfxBooleanFlagGuard aGuard( m_bResizeNoScale, sal_True );
513 // allow container to apply restrictions on the requested new area;
514 // the container might change the object view during size calculation;
515 // currently only writer does it
516 m_pClient->RequestNewObjectArea( aNewLogicRect);
518 if ( aNewLogicRect != m_pClient->GetScaledObjArea() )
520 // the calculation of the object area has not changed the object size
521 // it should be done here then
522 SfxBooleanFlagGuard aGuard( m_bResizeNoScale );
524 // new size of the object area without scaling
525 Size aNewObjSize( tools::Long( aNewLogicRect.GetWidth() / m_aScaleWidth ),
526 tools::Long( aNewLogicRect.GetHeight() / m_aScaleHeight ) );
528 // now remove scaling from new placement and keep this at the new object area
529 aNewLogicRect.SetSize( aNewObjSize );
530 m_aObjArea = aNewLogicRect;
532 // let the window size be recalculated
533 SizeHasChanged();
536 // notify container view about changes
537 m_pClient->ObjectAreaChanged();
540 // XComponentSupplier
542 uno::Reference< util::XCloseable > SAL_CALL SfxInPlaceClient_Impl::getComponent()
544 if ( !m_pClient || !m_pClient->GetViewShell() )
545 throw uno::RuntimeException();
547 SfxObjectShell* pDocShell = m_pClient->GetViewShell()->GetObjectShell();
548 if ( !pDocShell )
549 throw uno::RuntimeException();
551 // all the components must implement XCloseable
552 uno::Reference< util::XCloseable > xComp( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
553 return xComp;
557 // XWindowSupplier
559 uno::Reference< awt::XWindow > SAL_CALL SfxInPlaceClient_Impl::getWindow()
561 if ( !m_pClient || !m_pClient->GetEditWin() )
562 throw uno::RuntimeException();
564 uno::Reference< awt::XWindow > xWin( m_pClient->GetEditWin()->GetComponentInterface(), uno::UNO_QUERY );
565 return xWin;
569 // notification to the client implementation that either the object area or the scaling has been changed
570 // as a result the logical size of the window has changed also
571 void SfxInPlaceClient_Impl::SizeHasChanged()
573 if ( !m_pClient || !m_pClient->GetViewShell() )
574 throw uno::RuntimeException();
576 try {
577 if ( m_xObject.is()
578 && ( m_xObject->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE
579 || m_xObject->getCurrentState() == embed::EmbedStates::UI_ACTIVE ) )
581 // only possible in active states
582 uno::Reference< embed::XInplaceObject > xInplace( m_xObject, uno::UNO_QUERY_THROW );
584 if ( m_bResizeNoScale )
586 // the resizing should be done without scaling
587 // set the correct size to the object to avoid the scaling
588 MapMode aObjectMap( VCLUnoHelper::UnoEmbed2VCLMapUnit( m_xObject->getMapUnit( m_nAspect ) ) );
589 MapMode aClientMap( m_pClient->GetEditWin()->GetMapMode().GetMapUnit() );
591 // convert to logical coordinates of the embedded object
592 Size aNewSize = m_pClient->GetEditWin()->LogicToLogic( m_aObjArea.GetSize(), &aClientMap, &aObjectMap );
593 m_xObject->setVisualAreaSize( m_nAspect, awt::Size( aNewSize.Width(), aNewSize.Height() ) );
596 xInplace->setObjectRectangles( getPlacement(), getClipRectangle() );
599 catch( uno::Exception& )
601 // TODO/LATER: handle error
606 IMPL_LINK_NOARG(SfxInPlaceClient_Impl, TimerHdl, Timer *, void)
608 if ( m_pClient && m_xObject.is() )
610 m_pClient->GetViewShell()->CheckIPClient_Impl(m_pClient,
611 m_pClient->GetViewShell()->GetObjectShell()->GetVisArea());
616 // SfxInPlaceClient
619 SfxInPlaceClient::SfxInPlaceClient( SfxViewShell* pViewShell, vcl::Window *pDraw, sal_Int64 nAspect ) :
620 m_xImp( new SfxInPlaceClient_Impl ),
621 m_pViewSh( pViewShell ),
622 m_pEditWin( pDraw )
624 m_xImp->m_pClient = this;
625 m_xImp->m_nAspect = nAspect;
626 m_xImp->m_aScaleWidth = m_xImp->m_aScaleHeight = Fraction(1,1);
627 pViewShell->NewIPClient_Impl(this);
628 m_xImp->m_aTimer.SetDebugName( "sfx::SfxInPlaceClient m_xImpl::m_aTimer" );
629 m_xImp->m_aTimer.SetTimeout( SFX_CLIENTACTIVATE_TIMEOUT );
630 m_xImp->m_aTimer.SetInvokeHandler( LINK( m_xImp.get(), SfxInPlaceClient_Impl, TimerHdl ) );
634 SfxInPlaceClient::~SfxInPlaceClient()
636 m_pViewSh->IPClientGone_Impl(this);
638 // deleting the client before storing the object means discarding all changes
639 m_xImp->m_bStoreObject = false;
640 SetObject(nullptr);
642 m_xImp->m_pClient = nullptr;
644 // the next call will destroy m_xImp if no other reference to it exists
645 m_xImp.clear();
647 // TODO/LATER:
648 // the class is not intended to be used in multithreaded environment;
649 // if it will this disconnection and all the parts that use the m_pClient
650 // must be guarded with mutex
654 void SfxInPlaceClient::SetObjectState( sal_Int32 nState )
656 if ( !GetObject().is() )
657 return;
659 if ( m_xImp->m_nAspect == embed::Aspects::MSOLE_ICON
660 && ( nState == embed::EmbedStates::UI_ACTIVE || nState == embed::EmbedStates::INPLACE_ACTIVE ) )
662 OSL_FAIL( "Iconified object should not be activated inplace!" );
663 return;
668 GetObject()->changeState( nState );
670 catch ( uno::Exception& )
675 sal_Int64 SfxInPlaceClient::GetObjectMiscStatus() const
677 if ( GetObject().is() )
678 return GetObject()->getStatus( m_xImp->m_nAspect );
679 return 0;
683 const uno::Reference < embed::XEmbeddedObject >& SfxInPlaceClient::GetObject() const
685 return m_xImp->m_xObject;
689 void SfxInPlaceClient::SetObject( const uno::Reference < embed::XEmbeddedObject >& rObject )
691 if ( m_xImp->m_xObject.is() && rObject != m_xImp->m_xObject )
693 DBG_ASSERT( GetObject()->getClientSite() == static_cast<cppu::OWeakObject*>(m_xImp.get()), "Wrong ClientSite!" );
694 if ( GetObject()->getClientSite() == static_cast<cppu::OWeakObject*>(m_xImp.get()) )
696 if ( GetObject()->getCurrentState() != embed::EmbedStates::LOADED )
697 SetObjectState( embed::EmbedStates::RUNNING );
698 m_xImp->m_xObject->removeEventListener( m_xImp.get() );
699 m_xImp->m_xObject->removeStateChangeListener( m_xImp.get() );
702 m_xImp->m_xObject->setClientSite( nullptr );
704 catch( uno::Exception& )
706 OSL_FAIL( "Can not clean the client site!" );
711 if ( m_pViewSh->GetViewFrame()->GetFrame().IsClosing_Impl() )
712 // sometimes applications reconnect clients on shutting down because it happens in their Paint methods
713 return;
715 m_xImp->m_xObject = rObject;
717 if ( rObject.is() )
719 // as soon as an object was connected to a client it has to be checked whether the object wants
720 // to be activated
721 rObject->addStateChangeListener( m_xImp.get() );
722 rObject->addEventListener( m_xImp.get() );
726 rObject->setClientSite( m_xImp.get() );
728 catch( uno::Exception& )
730 OSL_FAIL( "Can not set the client site!" );
733 m_xImp->m_aTimer.Start();
735 else
736 m_xImp->m_aTimer.Stop();
740 bool SfxInPlaceClient::SetObjArea( const tools::Rectangle& rArea )
742 if( rArea != m_xImp->m_aObjArea )
744 m_xImp->m_aObjArea = rArea;
745 m_xImp->SizeHasChanged();
747 Invalidate();
748 return true;
751 return false;
755 const tools::Rectangle& SfxInPlaceClient::GetObjArea() const
757 return m_xImp->m_aObjArea;
760 tools::Rectangle SfxInPlaceClient::GetScaledObjArea() const
762 tools::Rectangle aRealObjArea( m_xImp->m_aObjArea );
763 aRealObjArea.SetSize( Size( tools::Long( aRealObjArea.GetWidth() * m_xImp->m_aScaleWidth ),
764 tools::Long( aRealObjArea.GetHeight() * m_xImp->m_aScaleHeight ) ) );
765 return aRealObjArea;
769 void SfxInPlaceClient::SetSizeScale( const Fraction & rScaleWidth, const Fraction & rScaleHeight )
771 if ( m_xImp->m_aScaleWidth != rScaleWidth || m_xImp->m_aScaleHeight != rScaleHeight )
773 m_xImp->m_aScaleWidth = rScaleWidth;
774 m_xImp->m_aScaleHeight = rScaleHeight;
776 m_xImp->SizeHasChanged();
778 // TODO/LATER: Invalidate seems to trigger (wrong) recalculations of the ObjArea, so it's better
779 // not to call it here, but maybe it sounds reasonable to do so.
780 //Invalidate();
785 void SfxInPlaceClient::SetObjAreaAndScale( const tools::Rectangle& rArea, const Fraction& rScaleWidth, const Fraction& rScaleHeight )
787 if( rArea != m_xImp->m_aObjArea || m_xImp->m_aScaleWidth != rScaleWidth || m_xImp->m_aScaleHeight != rScaleHeight )
789 m_xImp->m_aObjArea = rArea;
790 m_xImp->m_aScaleWidth = rScaleWidth;
791 m_xImp->m_aScaleHeight = rScaleHeight;
793 m_xImp->SizeHasChanged();
795 Invalidate();
800 const Fraction& SfxInPlaceClient::GetScaleWidth() const
802 return m_xImp->m_aScaleWidth;
806 const Fraction& SfxInPlaceClient::GetScaleHeight() const
808 return m_xImp->m_aScaleHeight;
812 void SfxInPlaceClient::Invalidate()
814 // TODO/LATER: do we need both?
816 // the object area is provided in logical coordinates of the window but without scaling applied
817 tools::Rectangle aRealObjArea( m_xImp->m_aObjArea );
818 aRealObjArea.SetSize( Size( tools::Long( aRealObjArea.GetWidth() * m_xImp->m_aScaleWidth ),
819 tools::Long( aRealObjArea.GetHeight() * m_xImp->m_aScaleHeight ) ) );
820 m_pEditWin->Invalidate( aRealObjArea );
822 ViewChanged();
826 bool SfxInPlaceClient::IsObjectUIActive() const
828 try {
829 return ( m_xImp->m_xObject.is() && ( m_xImp->m_xObject->getCurrentState() == embed::EmbedStates::UI_ACTIVE ) );
831 catch( uno::Exception& )
834 return false;
838 bool SfxInPlaceClient::IsObjectInPlaceActive() const
840 try {
841 return(
843 m_xImp->m_xObject.is() &&
844 (m_xImp->m_xObject->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE)
845 ) ||
847 m_xImp->m_xObject.is() &&
848 (m_xImp->m_xObject->getCurrentState() == embed::EmbedStates::UI_ACTIVE)
852 catch( uno::Exception& )
855 return false;
859 SfxInPlaceClient* SfxInPlaceClient::GetClient( SfxObjectShell const * pDoc, const css::uno::Reference < css::embed::XEmbeddedObject >& xObject )
861 for ( SfxViewFrame* pFrame = SfxViewFrame::GetFirst(pDoc); pFrame; pFrame=SfxViewFrame::GetNext(*pFrame,pDoc) )
863 if( pFrame->GetViewShell() )
865 SfxInPlaceClient* pClient = pFrame->GetViewShell()->FindIPClient( xObject, nullptr );
866 if ( pClient )
867 return pClient;
871 return nullptr;
874 sal_Int64 SfxInPlaceClient::GetAspect() const
876 return m_xImp->m_nAspect;
879 ErrCode SfxInPlaceClient::DoVerb( tools::Long nVerb )
881 SfxErrorContext aEc(ERRCTX_SO_DOVERB, m_pViewSh->GetFrameWeld(), RID_SO_ERRCTX);
882 ErrCode nError = ERRCODE_NONE;
884 if ( m_xImp->m_xObject.is() )
886 bool bSaveCopyAs = false;
887 if ( nVerb == -8 ) // "Save Copy as..."
889 svt::EmbeddedObjectRef::TryRunningState( m_xImp->m_xObject );
890 // TODO/LATER: this special verb should disappear when outplace activation is completely available
891 uno::Reference< frame::XModel > xEmbModel( m_xImp->m_xObject->getComponent(), uno::UNO_QUERY );
892 if ( xEmbModel.is() )
894 bSaveCopyAs = true;
898 SfxStoringHelper aHelper;
899 uno::Sequence< beans::PropertyValue > aDispatchArgs( 1 );
900 aDispatchArgs[0].Name = "SaveTo";
901 aDispatchArgs[0].Value <<= true;
903 aHelper.GUIStoreModel( xEmbModel,
904 "SaveAs",
905 aDispatchArgs,
906 false,
907 SignatureState::NOSIGNATURES );
909 catch( const task::ErrorCodeIOException& aErrorEx )
911 nError = ErrCode(aErrorEx.ErrCode);
913 catch( uno::Exception& )
915 nError = ERRCODE_IO_GENERAL;
916 // TODO/LATER: better error handling
921 if ( !bSaveCopyAs )
923 if ( m_xImp->m_nAspect == embed::Aspects::MSOLE_ICON )
925 // the common persistence is supported by objects and links
927 uno::Reference< embed::XEmbeddedOleObject > xEmbeddedOleObject( m_xImp->m_xObject, uno::UNO_QUERY );
929 if ( xEmbeddedOleObject.is() && (nVerb == embed::EmbedVerbs::MS_OLEVERB_PRIMARY || nVerb == embed::EmbedVerbs::MS_OLEVERB_OPEN || nVerb == embed::EmbedVerbs::MS_OLEVERB_SHOW ))
930 nVerb = embed::EmbedVerbs::MS_OLEVERB_SHOW;
931 else if ( nVerb == embed::EmbedVerbs::MS_OLEVERB_PRIMARY || nVerb == embed::EmbedVerbs::MS_OLEVERB_SHOW )
932 nVerb = embed::EmbedVerbs::MS_OLEVERB_OPEN; // outplace activation
933 else if ( nVerb == embed::EmbedVerbs::MS_OLEVERB_UIACTIVATE
934 || nVerb == embed::EmbedVerbs::MS_OLEVERB_IPACTIVATE )
935 nError = ERRCODE_SO_GENERALERROR;
938 if ( !nError )
940 // See comment for SfxInPlaceClient_Impl::getPlacement.
941 vcl::Window* pEditWin = GetEditWin();
942 bool bMapModeEnabled = pEditWin->IsMapModeEnabled();
943 if (comphelper::LibreOfficeKit::isActive() && !bMapModeEnabled)
945 pEditWin->EnableMapMode();
947 m_pViewSh->GetViewFrame()->GetFrame().LockResize_Impl(true);
950 m_xImp->m_xObject->setClientSite( m_xImp.get() );
952 m_xImp->m_xObject->doVerb( nVerb );
954 catch ( embed::UnreachableStateException& )
956 if (nVerb == embed::EmbedVerbs::MS_OLEVERB_PRIMARY || nVerb == embed::EmbedVerbs::MS_OLEVERB_OPEN || nVerb == embed::EmbedVerbs::MS_OLEVERB_SHOW)
958 // a workaround for the default verb, usually makes sense for alien objects
961 m_xImp->m_xObject->doVerb( -9 ); // open own view, a workaround verb that is not visible
963 if ( m_xImp->m_xObject->getCurrentState() == embed::EmbedStates::UI_ACTIVE )
965 // the object was converted to OOo object
966 awt::Size aSize = m_xImp->m_xObject->getVisualAreaSize( m_xImp->m_nAspect );
967 MapMode aObjectMap( VCLUnoHelper::UnoEmbed2VCLMapUnit( m_xImp->m_xObject->getMapUnit( m_xImp->m_nAspect ) ) );
968 MapMode aClientMap( GetEditWin()->GetMapMode().GetMapUnit() );
969 Size aNewSize = GetEditWin()->LogicToLogic( Size( aSize.Width, aSize.Height ), &aObjectMap, &aClientMap );
971 tools::Rectangle aScaledArea = GetScaledObjArea();
972 m_xImp->m_aObjArea.SetSize( aNewSize );
973 m_xImp->m_aScaleWidth = Fraction( aScaledArea.GetWidth(), aNewSize.Width() );
974 m_xImp->m_aScaleHeight = Fraction( aScaledArea.GetHeight(), aNewSize.Height() );
977 catch (uno::Exception const&)
979 TOOLS_WARN_EXCEPTION("embeddedobj", "SfxInPlaceClient::DoVerb: -9 fallback path");
980 nError = ERRCODE_SO_GENERALERROR;
984 catch ( embed::StateChangeInProgressException& )
986 // TODO/LATER: it would be nice to be able to provide the current target state outside
987 nError = ERRCODE_SO_CANNOT_DOVERB_NOW;
989 catch (uno::Exception const&)
991 TOOLS_WARN_EXCEPTION("embeddedobj", "SfxInPlaceClient::DoVerb");
992 nError = ERRCODE_SO_GENERALERROR;
993 //TODO/LATER: better error handling
996 if (comphelper::LibreOfficeKit::isActive() && !bMapModeEnabled
997 && pEditWin->IsMapModeEnabled())
999 pEditWin->EnableMapMode(false);
1001 SfxViewFrame* pFrame = m_pViewSh->GetViewFrame();
1002 pFrame->GetFrame().LockResize_Impl(false);
1003 pFrame->GetFrame().Resize();
1008 if( nError )
1009 ErrorHandler::HandleError( nError );
1011 return nError;
1014 void SfxInPlaceClient::VisAreaChanged()
1016 uno::Reference < embed::XInplaceObject > xObj( m_xImp->m_xObject, uno::UNO_QUERY );
1017 if ( xObj.is() )
1018 m_xImp->SizeHasChanged();
1021 void SfxInPlaceClient::ObjectAreaChanged()
1023 // dummy implementation
1026 void SfxInPlaceClient::RequestNewObjectArea( tools::Rectangle& )
1028 // dummy implementation
1031 void SfxInPlaceClient::ViewChanged()
1033 // dummy implementation
1036 void SfxInPlaceClient::FormatChanged()
1038 // dummy implementation
1041 void SfxInPlaceClient::DeactivateObject()
1043 if ( !GetObject().is() )
1044 return;
1048 m_xImp->m_bUIActive = false;
1049 bool bHasFocus = false;
1050 uno::Reference< frame::XModel > xModel( m_xImp->m_xObject->getComponent(), uno::UNO_QUERY );
1051 if ( xModel.is() )
1053 uno::Reference< frame::XController > xController = xModel->getCurrentController();
1054 if ( xController.is() )
1056 VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xController->getFrame()->getContainerWindow() );
1057 bHasFocus = pWindow->HasChildPathFocus( true );
1061 m_pViewSh->GetViewFrame()->GetFrame().LockResize_Impl(true);
1063 if ( m_xImp->m_xObject->getStatus( m_xImp->m_nAspect ) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE )
1065 m_xImp->m_xObject->changeState( embed::EmbedStates::INPLACE_ACTIVE );
1066 if (bHasFocus)
1067 m_pViewSh->GetWindow()->GrabFocus();
1069 else
1071 // the links should not stay in running state for long time because of locking
1072 uno::Reference< embed::XLinkageSupport > xLink( m_xImp->m_xObject, uno::UNO_QUERY );
1073 if ( xLink.is() && xLink->isLink() )
1074 m_xImp->m_xObject->changeState( embed::EmbedStates::LOADED );
1075 else
1076 m_xImp->m_xObject->changeState( embed::EmbedStates::RUNNING );
1079 SfxViewFrame* pFrame = m_pViewSh->GetViewFrame();
1080 SfxViewFrame::SetViewFrame( pFrame );
1081 pFrame->GetFrame().LockResize_Impl(false);
1082 pFrame->GetFrame().Resize();
1084 catch (css::uno::Exception& )
1088 void SfxInPlaceClient::ResetObject()
1090 if ( !GetObject().is() )
1091 return;
1095 m_xImp->m_bUIActive = false;
1096 if ( m_xImp->m_xObject->getStatus( m_xImp->m_nAspect ) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE )
1097 m_xImp->m_xObject->changeState( embed::EmbedStates::INPLACE_ACTIVE );
1098 else
1100 // the links should not stay in running state for long time because of locking
1101 uno::Reference< embed::XLinkageSupport > xLink( m_xImp->m_xObject, uno::UNO_QUERY );
1102 if ( xLink.is() && xLink->isLink() )
1103 m_xImp->m_xObject->changeState( embed::EmbedStates::LOADED );
1104 else
1105 m_xImp->m_xObject->changeState( embed::EmbedStates::RUNNING );
1108 catch (css::uno::Exception& )
1112 bool SfxInPlaceClient::IsUIActive() const
1114 return m_xImp->m_bUIActive;
1117 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */