Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / sfx2 / source / view / ipclient.cxx
blob81d93b38f55bd1ba068ab9ea3685c573dd4bc983
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 <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
77 bool& m_rFlag;
78 bool m_bLifeValue;
79 public:
80 explicit SfxBooleanFlagGuard(bool& bFlag)
81 : m_rFlag( 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 >
103 public:
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
110 bool m_bStoreObject;
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 )
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 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 );
202 // XEmbeddedClient
204 uno::Reference < frame::XFrame > const & SfxInPlaceClient_Impl::GetFrame() const
206 if ( !m_pClient )
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
216 return;
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() );
226 if ( xModel.is() )
228 uno::Reference< frame::XController > xController = xModel->getCurrentController();
229 if ( xController.is() )
230 xFrame = xController->getFrame();
233 if ( xFrame.is() )
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 );
241 if ( xPropSet.is() )
245 xStatusIndicator = xStatusIndicatorFactory->createStatusIndicator();
246 xPropSet->setPropertyValue( "IndicatorInterception" , uno::makeAny( xStatusIndicator ));
248 catch ( const uno::RuntimeException& )
250 throw;
252 catch ( uno::Exception& )
260 xPersist->storeOwn();
261 m_xObject->update();
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 );
272 if ( xPropSet.is() )
274 xStatusIndicator.clear();
275 xPropSet->setPropertyValue( "IndicatorInterception" , uno::makeAny( xStatusIndicator ));
278 catch ( const uno::RuntimeException& )
280 throw;
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();
291 if ( !pDocShell )
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();
314 // XInplaceClient
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 )
323 return false;
325 return true;
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);
342 m_bUIActive = true;
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 );
360 m_bUIActive = false;
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" );
372 aAny >>= xMan;
374 catch ( uno::Exception& )
376 throw uno::RuntimeException();
379 return xMan;
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
404 // editing in LOK.
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);
415 else
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);
445 else
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
482 return;
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
510 SizeHasChanged();
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();
525 if ( !pDocShell )
526 throw uno::RuntimeException();
528 // all the components must implement XCloseable
529 uno::Reference< util::XCloseable > xComp( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
530 return xComp;
534 // XWindowSupplier
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 );
542 return xWin;
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();
553 try {
554 if ( m_xObject.is()
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());
593 // SfxInPlaceClient
596 SfxInPlaceClient::SfxInPlaceClient( SfxViewShell* pViewShell, vcl::Window *pDraw, sal_Int64 nAspect ) :
597 m_xImp( new SfxInPlaceClient_Impl ),
598 m_pViewSh( pViewShell ),
599 m_pEditWin( pDraw )
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;
618 SetObject(nullptr);
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();
625 // TODO/LATER:
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!" );
640 return;
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 );
657 return 0;
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
691 return;
693 m_xImp->m_xObject = rObject;
695 if ( rObject.is() )
697 // as soon as an object was connected to a client it has to be checked whether the object wants
698 // to be activated
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();
713 else
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();
725 Invalidate();
726 return true;
729 return false;
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 ) ) );
743 return aRealObjArea;
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.
758 //Invalidate();
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();
773 Invalidate();
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 );
800 ViewChanged();
804 bool SfxInPlaceClient::IsObjectUIActive() const
806 try {
807 return ( m_xImp->m_xObject.is() && ( m_xImp->m_xObject->getCurrentState() == embed::EmbedStates::UI_ACTIVE ) );
809 catch( uno::Exception& )
812 return false;
816 bool SfxInPlaceClient::IsObjectInPlaceActive() const
818 try {
819 return(
821 m_xImp->m_xObject.is() &&
822 (m_xImp->m_xObject->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE)
823 ) ||
825 m_xImp->m_xObject.is() &&
826 (m_xImp->m_xObject->getCurrentState() == embed::EmbedStates::UI_ACTIVE)
830 catch( uno::Exception& )
833 return false;
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 );
844 if ( pClient )
845 return pClient;
849 return 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() )
873 bSaveCopyAs = true;
877 SfxStoringHelper aHelper;
878 uno::Sequence< beans::PropertyValue > aDispatchArgs( 1 );
879 aDispatchArgs[0].Name = "SaveTo";
880 aDispatchArgs[0].Value <<= true;
882 aHelper.GUIStoreModel( xEmbModel,
883 "SaveAs",
884 aDispatchArgs,
885 false,
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
900 if ( !bSaveCopyAs )
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;
917 if ( !nError )
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();
988 if( nError )
989 ErrorHandler::HandleError( nError );
991 return 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 );
1031 if ( xModel.is() )
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 );
1047 if (bHasFocus)
1048 m_pViewSh->GetWindow()->GrabFocus();
1050 else
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 );
1056 else
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 );
1080 else
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 );
1086 else
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: */