/* -*- 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 .
*/
typedef ::std::map< OUString, sal_Int32 > MapString2Int; struct UnoControl_Data
{
MapString2Int aSuspendedPropertyNotifications; /// true if and only if our model has a property ResourceResolver bool bLocalizationSupport;
bool UnoControl::ImplCheckLocalize( OUString& _rPossiblyLocalizable )
{ if ( !mpData->bLocalizationSupport
|| ( _rPossiblyLocalizable.isEmpty() )
|| ( _rPossiblyLocalizable[0] != '&' ) // TODO: make this reasonable. At the moment, everything which by accident starts with a & is considered // localizable, which is probably wrong.
) returnfalse;
void UnoControl::ImplSetPeerProperty( const OUString& rPropName, const Any& rVal )
{ // since a change made in propertiesChange, we can't be sure that this is called with a valid getPeer(), // this assumption may be false in some (seldom) multi-threading scenarios (cause propertiesChange // releases our mutex before calling here in) // That's why this additional check
if ( !mxVclWindowPeer.is() ) return;
Any aConvertedValue( rVal );
if ( mpData->bLocalizationSupport )
{ // We now support a mapping for language dependent properties. This is the // central method to implement it. if( rPropName == "Text" ||
rPropName == "Label" ||
rPropName == "Title" ||
rPropName == "HelpText" ||
rPropName == "CurrencySymbol" ||
rPropName == "StringItemList" )
{
OUString aValue;
uno::Sequence< OUString > aSeqValue; if ( aConvertedValue >>= aValue )
{ if ( ImplCheckLocalize( aValue ) )
aConvertedValue <<= aValue;
} elseif ( aConvertedValue >>= aSeqValue )
{ for ( auto& rValue : asNonConstRange(aSeqValue) )
ImplCheckLocalize( rValue );
aConvertedValue <<= aSeqValue;
}
}
}
std::vector< PropertyValue > aPeerPropertiesToSet;
sal_Int32 nIndependentPos = 0; bool bResourceResolverSet( false ); // position where to insert the independent properties into aPeerPropertiesToSet, // dependent ones are inserted at the end of the vector
bool bNeedNewPeer = false; // some properties require a re-creation of the peer, 'cause they can't be changed on the fly
Reference< XControlModel > xOwnModel = getModel(); // our own model for comparison
Reference< XPropertySet > xPS( xOwnModel, UNO_QUERY );
Reference< XPropertySetInfo > xPSI = xPS->getPropertySetInfo();
OSL_ENSURE( xPSI.is(), "UnoControl::ImplModelPropertiesChanged: should have property set meta data!" );
if ( nPType && ( nLen > 1 ) && DoesDependOnOthers( nPType ) )
{ // Add properties with dependencies on other properties last // since they're dependent on properties added later (such as // VALUE dependency on VALUEMIN/MAX)
aPeerPropertiesToSet.emplace_back(rEvent.PropertyName, 0, rEvent.NewValue, PropertyState_DIRECT_VALUE);
} else
{ if ( bResourceResolverSet )
{ // The resource resolver property change should be one of the first ones. // All language dependent properties are dependent on this property. // As BASEPROPERTY_NATIVE_WIDGET_LOOK is not dependent on resource // resolver. We don't need to handle a special order for these two props.
aPeerPropertiesToSet.insert(
aPeerPropertiesToSet.begin(),
PropertyValue( rEvent.PropertyName, 0, rEvent.NewValue, PropertyState_DIRECT_VALUE ) );
++nIndependentPos;
} elseif ( nPType == BASEPROPERTY_NATIVE_WIDGET_LOOK )
{ // since *a lot* of other properties might be overruled by this one, we need // a special handling: // NativeWidgetLook needs to be set first: If it is set to ON, all other // properties describing the look (e.g. BackgroundColor) are ignored, anyway. // If it is switched OFF, then we need to do it first because else it will // overrule other look-related properties, and re-initialize them from system // defaults.
aPeerPropertiesToSet.insert(
aPeerPropertiesToSet.begin(),
PropertyValue( rEvent.PropertyName, 0, rEvent.NewValue, PropertyState_DIRECT_VALUE ) );
++nIndependentPos;
} else
{
aPeerPropertiesToSet.insert(aPeerPropertiesToSet.begin() + nIndependentPos,
PropertyValue(rEvent.PropertyName, 0, rEvent.NewValue, PropertyState_DIRECT_VALUE));
++nIndependentPos;
}
}
}
Reference< XWindow > xParent = getParentPeer();
Reference< XControl > xThis(this); // call createPeer via an interface got from queryInterface, so the aggregating class can intercept it
DBG_ASSERT( !bNeedNewPeer || xParent.is(), "Need new peer, but don't have a parent!");
// Check if we have to update language dependent properties if ( !bNeedNewPeer && bResourceResolverSet )
{ // Add language dependent properties into the peer property set. // Our resource resolver has been changed and we must be sure // that language dependent props use the new resolver.
for (constauto & rLangDepProp : aLanguageDependentProp)
{ bool bMustBeInserted( true ); for (const PropertyValue & i : aPeerPropertiesToSet)
{ if ( i.Name == rLangDepProp )
{
bMustBeInserted = false; break;
}
}
if ( bMustBeInserted )
{ // Add language dependent props at the end if ( xPSI.is() && xPSI->hasPropertyByName( rLangDepProp ) )
{
aPeerPropertiesToSet.emplace_back( rLangDepProp, 0, xPS->getPropertyValue( rLangDepProp ), PropertyState_DIRECT_VALUE );
}
}
}
}
aGuard.clear();
// clear the guard before creating a new peer - as usual, our peer implementations use the SolarMutex
if (bNeedNewPeer && xParent.is())
{
SolarMutexGuard aVclGuard; // and now this is the final withdrawal: // I have no other idea than locking the SolarMutex here... // I really hate the fact that VCL is not threadsafe...
// Doesn't work for Container!
getPeer()->dispose();
mxVclWindowPeer.clear();
mbRefreshingPeer = true;
Reference< XWindowPeer > xP( xParent, UNO_QUERY );
xThis->createPeer( Reference< XToolkit > (), xP );
mbRefreshingPeer = false;
aPeerPropertiesToSet.clear();
}
// lock the multiplexing of VCL events to our UNO listeners // this is for compatibility reasons: in OOo 1.0.x, changes which were done at the // model did not cause the listeners of the controls/peers to be called // Since the implementations for the listeners changed a lot towards 1.1, this // would not be the case anymore, if we would not do this listener-lock below // #i14703#
VCLXWindow* pPeer;
{
SolarMutexGuard g;
VclPtr<vcl::Window> pVclPeer = VCLUnoHelper::GetWindow( getPeer() );
pPeer = pVclPeer ? pVclPeer->GetWindowPeer() : nullptr;
}
VclListenerLock aNoVclEventMultiplexing( pPeer );
// setting peer properties may result in an attempt to acquire the solar mutex, 'cause the peers // usually don't have an own mutex but use the SolarMutex instead. // To prevent deadlocks resulting from this, we do this without our own mutex locked for (constauto& rProp : aPeerPropertiesToSet)
{
ImplSetPeerProperty( rProp.Name, rProp.Value );
}
}
void UnoControl::disposing( const EventObject& rEvt )
{
::osl::ClearableMutexGuard aGuard( GetMutex() ); // do not compare differing types in case of multiple inheritance
if ( maAccessibleContext.get() == rEvt.Source )
{ // just in case the context is disposed, but not released - ensure that we do not re-use it in the future
maAccessibleContext.clear();
} elseif( mxModel.get() == Reference< XControlModel >(rEvt.Source,UNO_QUERY).get() )
{ // #62337# if the model dies, it does not make sense for us to live ...
Reference< XControl > xThis = this;
// release the mutex guard (and work with copies of our members) // this is necessary as our peer may lock the SolarMutex (actually, all currently known peers do), so calling // into the peer with our own mutex locked may cause deadlocks // (We _really_ need peers which do not use the SolarMutex. It's really pissing me off that from time to // time deadlocks pop up because the low-level components like our peers use a mutex which usually // is locked at the top of the stack (it protects the global message looping). This is always dangerous, and // can not always be solved by tampering with other mutexes. // Unfortunately, the VCL used in the peers is not threadsafe, and by definition needs a locked SolarMutex.) // 82300 - 12/21/00 - FS
UnoControlComponentInfos aComponentInfos(maComponentInfos); bool bDesignMode(mbDesignMode);
// tdf#150886 if false use the same settings for widgets regardless of theme // for consistency of document across platforms and in pdf/print output // note: tdf#155029 do this before updateFromModel if (xInfo->hasPropertyByName(u"StandardTheme"_ustr))
{
aVal = xPSet->getPropertyValue(u"StandardTheme"_ustr); bool bUseStandardTheme = false;
aVal >>= bUseStandardTheme; if (bUseStandardTheme)
{
VclPtr<vcl::Window> pVclPeer = VCLUnoHelper::GetWindow(getPeer());
// KEEP IN SYNC WITH ControlCharacterDialog::translatePropertiesToItems
AllSettings aAllSettings = pVclPeer->GetSettings();
StyleSettings aStyleSettings = aAllSettings.GetStyleSettings();
aStyleSettings.SetStandardStyles();
aAllSettings.SetStyleSettings(aStyleSettings);
pVclPeer->SetSettings(aAllSettings);
}
}
// the updateFromModel is done without a locked mutex, too. // The reason is that the only thing this method does is firing property changes, and this in general has // to be done without locked mutexes (as every notification to external listeners). // 82300 - 12/21/00 - FS
updateFromModel();
// query for the XPropertiesChangeListener - our delegator is allowed to overwrite this interface
Reference< XPropertiesChangeListener > xListener;
queryInterface( cppu::UnoType<decltype(xListener)>::get() ) >>= xListener;
// dispose current AccessibleContext, if we have one - without Mutex lock // (changing the design mode implies having a new implementation for this context, // so the old one must be declared DEFUNC)
DisposeAccessibleContext(xAccessibleComp);
// adjust the visibility of our window if ( xWindow.is() )
xWindow->setVisible( !bOn );
Reference< XAccessibleContext > SAL_CALL UnoControl::getAccessibleContext( )
{ // creation of the context will certainly require the SolarMutex ...
SolarMutexGuard aSolarGuard;
::osl::MutexGuard aGuard( GetMutex() );
Reference< XAccessibleContext > xCurrentContext( maAccessibleContext.get(), UNO_QUERY ); if ( !xCurrentContext.is() )
{ if ( !mbDesignMode )
{ // in alive mode, use the accessible context of the window if (vcl::Window* pWindow = VCLUnoHelper::GetWindow(getPeer()))
{
Reference<XAccessible> xWinAcc = pWindow->GetAccessible(); if (xWinAcc.is())
xCurrentContext = xWinAcc->getAccessibleContext();
}
} else // in design mode, use a fallback
xCurrentContext = ::toolkit::OAccessibleControlContext::create( this );
// get notified when the context is disposed
Reference< XComponent > xContextComp( xCurrentContext, UNO_QUERY ); if ( xContextComp.is() )
xContextComp->addEventListener( this ); // In an ideal world, this is not necessary - there the object would be released as soon as it has been // disposed, and thus our weak reference would be empty, too. // But 'til this ideal world comes (means 'til we do never have any refcount/lifetime bugs anymore), we // need to listen for disposal and reset our weak reference then.
}
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.