/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
class SfxInPlaceClient_Impl : public ::cppu::WeakImplHelper< embed::XEmbeddedClient,
embed::XInplaceClient,
document::XEventListener,
embed::XStateChangeListener,
embed::XWindowSupplier >
{ public:
Timer m_aTimer { "sfx::SfxInPlaceClient m_xImpl::m_aTimer" }; // activation timeout, starts after object connection
tools::Rectangle m_aObjArea; // area of object in coordinate system of the container (without scaling)
Fraction m_aScaleWidth; // scaling that was applied to the object when it was not active
Fraction m_aScaleHeight;
SfxInPlaceClient* m_pClient;
sal_Int64 m_nAspect; // ViewAspect that is assigned from the container bool m_bStoreObject; bool m_bUIActive; // set and cleared when notification for UI (de)activation is sent bool m_bResizeNoScale; bool m_bNegativeX;
if ( m_pClient && aEvent.EventName == "OnVisAreaChanged" && m_nAspect != embed::Aspects::MSOLE_ICON )
{
m_pClient->FormatChanged(); // for Writer when format of the object is changed with the area
m_pClient->ViewChanged();
m_pClient->Invalidate();
}
}
void SAL_CALL SfxInPlaceClient_Impl::saveObject()
{ if (!m_bStoreObject || (m_pClient && m_pClient->IsProtected())) // client wants to discard the object (usually it means the container document is closed while an object is active // and the user didn't request saving the changes return;
// the common persistence is supported by objects and links
uno::Reference< embed::XCommonEmbedPersist > xPersist( m_xObject, uno::UNO_QUERY_THROW );
if ( xModel.is() )
{
uno::Reference< frame::XController > xController = xModel->getCurrentController(); if ( xController.is() )
xFrame = xController->getFrame();
}
if ( xFrame.is() )
{ // set non-reschedule progress to prevent problems when asynchronous calls are made // during storing of the embedded object
uno::Reference< task::XStatusIndicatorFactory > xStatusIndicatorFactory =
task::StatusIndicatorFactory::createWithFrame( xContext, xFrame, true/*DisableReschedule*/, false/*AllowParentShow*/ );
if ( !m_pClient || !m_pClient->GetViewShell() ) throw uno::RuntimeException();
m_pClient->GetViewShell()->OutplaceActivated( bVisible ); if (m_pClient) // it can change in the above code
m_pClient->Invalidate();
}
// XInplaceClient
sal_Bool SAL_CALL SfxInPlaceClient_Impl::canInplaceActivate()
{ if ( !m_xObject.is() ) throw uno::RuntimeException();
// we don't want to switch directly from outplace to inplace mode if ( m_xObject->getCurrentState() == embed::EmbedStates::ACTIVE || m_nAspect == embed::Aspects::MSOLE_ICON ) returnfalse;
// apply scaling to object area and convert to pixels
tools::Rectangle aRealObjArea( m_aObjArea );
aRealObjArea.SetSize( Size( tools::Long( aRealObjArea.GetWidth() * m_aScaleWidth),
tools::Long( aRealObjArea.GetHeight() * m_aScaleHeight) ) );
vcl::Window* pEditWin = m_pClient->GetEditWin(); // In Writer and Impress the map mode is disabled. So when a chart is // activated (for in place editing) we get the chart win size in 100th mm // and any method that should return pixels returns 100th mm and the chart // window map mode has a ~26.485 scale factor. // All that does not fit with current implementation for handling chart // editing in LOK. if (comphelper::LibreOfficeKit::isActive())
{ bool bMapModeEnabled = pEditWin->IsMapModeEnabled(); if (!bMapModeEnabled)
pEditWin->EnableMapMode();
aRealObjArea = pEditWin->LogicToPixel(aRealObjArea); if (!bMapModeEnabled && pEditWin->IsMapModeEnabled())
pEditWin->EnableMapMode(false);
} else
{
aRealObjArea = pEditWin->LogicToPixel(aRealObjArea);
}
// check if the change is at least one pixel in size
awt::Rectangle aOldRect = getPlacement();
tools::Rectangle aNewPixelRect = vcl::unohelper::ConvertToVCLRect(aPosRect);
tools::Rectangle aOldPixelRect = vcl::unohelper::ConvertToVCLRect(aOldRect); if ( aOldPixelRect == aNewPixelRect ) // nothing has changed return;
// new scaled object area
tools::Rectangle aNewLogicRect = m_pClient->GetEditWin()->PixelToLogic( aNewPixelRect );
// all the size changes in this method should happen without scaling // SfxBooleanFlagGuard aGuard( m_bResizeNoScale, sal_True );
// allow container to apply restrictions on the requested new area; // the container might change the object view during size calculation; // currently only writer does it
m_pClient->RequestNewObjectArea( aNewLogicRect);
if ( aNewLogicRect != m_pClient->GetScaledObjArea() )
{ // the calculation of the object area has not changed the object size // it should be done here then
SfxBooleanFlagGuard aGuard( m_bResizeNoScale );
// new size of the object area without scaling
Size aNewObjSize( tools::Long( aNewLogicRect.GetWidth() / m_aScaleWidth ),
tools::Long( aNewLogicRect.GetHeight() / m_aScaleHeight ) );
// now remove scaling from new placement and keep this at the new object area
aNewLogicRect.SetSize( aNewObjSize );
m_aObjArea = aNewLogicRect;
// let the window size be recalculated
SizeHasChanged();
}
// notify container view about changes
m_pClient->ObjectAreaChanged();
}
// notification to the client implementation that either the object area or the scaling has been changed // as a result the logical size of the window has changed also void SfxInPlaceClient_Impl::SizeHasChanged()
{ if ( !m_pClient || !m_pClient->GetViewShell() ) throw uno::RuntimeException();
try { if ( m_xObject.is()
&& ( m_xObject->getCurrentState() == embed::EmbedStates::INPLACE_ACTIVE
|| m_xObject->getCurrentState() == embed::EmbedStates::UI_ACTIVE ) )
{ // only possible in active states
uno::Reference< embed::XInplaceObject > xInplace( m_xObject, uno::UNO_QUERY_THROW );
if ( m_bResizeNoScale )
{ // the resizing should be done without scaling // set the correct size to the object to avoid the scaling
MapMode aObjectMap( VCLUnoHelper::UnoEmbed2VCLMapUnit( m_xObject->getMapUnit( m_nAspect ) ) );
MapMode aClientMap( m_pClient->GetEditWin()->GetMapMode().GetMapUnit() );
// convert to logical coordinates of the embedded object
Size aNewSize = m_pClient->GetEditWin()->LogicToLogic( m_aObjArea.GetSize(), &aClientMap, &aObjectMap );
m_xObject->setVisualAreaSize( m_nAspect, awt::Size( aNewSize.Width(), aNewSize.Height() ) );
}
// deleting the client before storing the object means discarding all changes
m_xImp->m_bStoreObject = false;
SetObject(nullptr);
m_xImp->m_pClient = nullptr;
// the next call will destroy m_xImp if no other reference to it exists
m_xImp.clear();
// TODO/LATER: // the class is not intended to be used in multithreaded environment; // if it will this disconnection and all the parts that use the m_pClient // must be guarded with mutex
}
if ( m_pViewSh->GetViewFrame().GetFrame().IsClosing_Impl() ) // sometimes applications reconnect clients on shutting down because it happens in their Paint methods return;
m_xImp->m_xObject = rObject;
if ( rObject.is() )
{ // as soon as an object was connected to a client it has to be checked whether the object wants // to be activated
rObject->addStateChangeListener( m_xImp );
rObject->addEventListener( m_xImp );
try
{
rObject->setClientSite( m_xImp );
} catch( uno::Exception& )
{
OSL_FAIL( "Can not set the client site!" );
}
// TODO/LATER: Invalidate seems to trigger (wrong) recalculations of the ObjArea, so it's better // not to call it here, but maybe it sounds reasonable to do so. //Invalidate();
}
}
void SfxInPlaceClient::Invalidate()
{ // TODO/LATER: do we need both?
// the object area is provided in logical coordinates of the window but without scaling applied
tools::Rectangle aRealObjArea( m_xImp->m_aObjArea );
aRealObjArea.SetSize( Size( tools::Long( aRealObjArea.GetWidth() * m_xImp->m_aScaleWidth ),
tools::Long( aRealObjArea.GetHeight() * m_xImp->m_aScaleHeight ) ) );
if ( !nError )
{ // See comment for SfxInPlaceClient_Impl::getPlacement.
vcl::Window* pEditWin = GetEditWin(); bool bMapModeEnabled = pEditWin->IsMapModeEnabled(); if (comphelper::LibreOfficeKit::isActive() && !bMapModeEnabled)
{
pEditWin->EnableMapMode();
}
m_pViewSh->GetViewFrame().GetFrame().LockResize_Impl(true); try
{
m_xImp->m_xObject->setClientSite( m_xImp );
m_xImp->m_xObject->doVerb( nVerb );
} catch ( embed::UnreachableStateException& e )
{ if (nVerb == embed::EmbedVerbs::MS_OLEVERB_PRIMARY || nVerb == embed::EmbedVerbs::MS_OLEVERB_OPEN || nVerb == embed::EmbedVerbs::MS_OLEVERB_SHOW)
{ // a workaround for the default verb, usually makes sense for alien objects try
{
m_xImp->m_xObject->doVerb( -9 ); // open own view, a workaround verb that is not visible
if ( m_xImp->m_xObject->getStatus( m_xImp->m_nAspect ) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE )
{
m_xImp->m_xObject->changeState( embed::EmbedStates::INPLACE_ACTIVE ); if (bHasFocus)
m_pViewSh->GetWindow()->GrabFocus();
} else
{ // the links should not stay in running state for long time because of locking
uno::Reference< embed::XLinkageSupport > xLink( m_xImp->m_xObject, uno::UNO_QUERY ); if ( xLink.is() && xLink->isLink() )
m_xImp->m_xObject->changeState( embed::EmbedStates::LOADED ); else
m_xImp->m_xObject->changeState( embed::EmbedStates::RUNNING );
}
void SfxInPlaceClient::ResetObject()
{ if ( !GetObject().is() ) return;
try
{
m_xImp->m_bUIActive = false; if ( m_xImp->m_xObject->getStatus( m_xImp->m_nAspect ) & embed::EmbedMisc::MS_EMBED_ACTIVATEWHENVISIBLE )
m_xImp->m_xObject->changeState( embed::EmbedStates::INPLACE_ACTIVE ); else
{ // the links should not stay in running state for long time because of locking
uno::Reference< embed::XLinkageSupport > xLink( m_xImp->m_xObject, uno::UNO_QUERY ); if ( xLink.is() && xLink->isLink() )
m_xImp->m_xObject->changeState( embed::EmbedStates::LOADED ); else
m_xImp->m_xObject->changeState( embed::EmbedStates::RUNNING );
}
} catch (css::uno::Exception& )
{}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.