diff options
Diffstat (limited to 'editeng/source/uno/unotext.cxx')
-rw-r--r-- | editeng/source/uno/unotext.cxx | 2561 |
1 files changed, 2561 insertions, 0 deletions
diff --git a/editeng/source/uno/unotext.cxx b/editeng/source/uno/unotext.cxx new file mode 100644 index 0000000000..f74d7f67c3 --- /dev/null +++ b/editeng/source/uno/unotext.cxx @@ -0,0 +1,2561 @@ +/* -*- 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 . + */ + +#include <vcl/svapp.hxx> +#include <com/sun/star/text/ControlCharacter.hpp> +#include <com/sun/star/text/XTextField.hpp> +#include <com/sun/star/text/TextRangeSelection.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/XNameContainer.hpp> + +#include <svl/itemset.hxx> +#include <svl/itempool.hxx> +#include <svl/eitem.hxx> +#include <tools/debug.hxx> + +#include <editeng/unoprnms.hxx> +#include <editeng/unotext.hxx> +#include <editeng/unoedsrc.hxx> +#include <editeng/unonrule.hxx> +#include <editeng/unofdesc.hxx> +#include <editeng/unofield.hxx> +#include <editeng/flditem.hxx> +#include <editeng/numitem.hxx> +#include <editeng/editeng.hxx> +#include <editeng/outliner.hxx> +#include <editeng/unoipset.hxx> +#include <editeng/colritem.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <editeng/unonames.hxx> + +#include <initializer_list> +#include <memory> +#include <string_view> + +using namespace ::cppu; +using namespace ::com::sun::star; + +namespace { + +ESelection toESelection(const text::TextRangeSelection& rSel) +{ + ESelection aESel; + aESel.nStartPara = rSel.Start.Paragraph; + aESel.nStartPos = rSel.Start.PositionInParagraph; + aESel.nEndPara = rSel.End.Paragraph; + aESel.nEndPos = rSel.End.PositionInParagraph; + return aESel; +} + +} + +#define QUERYINT( xint ) \ + if( rType == cppu::UnoType<xint>::get() ) \ + return uno::Any(uno::Reference< xint >(this)) + +const SvxItemPropertySet* ImplGetSvxUnoOutlinerTextCursorSvxPropertySet() +{ + static SvxItemPropertySet aTextCursorSvxPropertySet( ImplGetSvxUnoOutlinerTextCursorPropertyMap(), EditEngine::GetGlobalItemPool() ); + return &aTextCursorSvxPropertySet; +} + +std::span<const SfxItemPropertyMapEntry> ImplGetSvxTextPortionPropertyMap() +{ + // Propertymap for an Outliner Text + static const SfxItemPropertyMapEntry aSvxTextPortionPropertyMap[] = + { + SVX_UNOEDIT_CHAR_PROPERTIES, + SVX_UNOEDIT_FONT_PROPERTIES, + SVX_UNOEDIT_OUTLINER_PROPERTIES, + SVX_UNOEDIT_PARA_PROPERTIES, + { u"TextField"_ustr, EE_FEATURE_FIELD, cppu::UnoType<text::XTextField>::get(), beans::PropertyAttribute::READONLY, 0 }, + { u"TextPortionType"_ustr, WID_PORTIONTYPE, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 }, + { u"TextUserDefinedAttributes"_ustr, EE_CHAR_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0}, + { u"ParaUserDefinedAttributes"_ustr, EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0}, + }; + return aSvxTextPortionPropertyMap; +} +const SvxItemPropertySet* ImplGetSvxTextPortionSvxPropertySet() +{ + static SvxItemPropertySet aSvxTextPortionPropertySet( ImplGetSvxTextPortionPropertyMap(), EditEngine::GetGlobalItemPool() ); + return &aSvxTextPortionPropertySet; +} + +static const SfxItemPropertySet* ImplGetSvxTextPortionSfxPropertySet() +{ + static SfxItemPropertySet aSvxTextPortionSfxPropertySet( ImplGetSvxTextPortionPropertyMap() ); + return &aSvxTextPortionSfxPropertySet; +} + +std::span<const SfxItemPropertyMapEntry> ImplGetSvxUnoOutlinerTextCursorPropertyMap() +{ + // Propertymap for an Outliner Text + static const SfxItemPropertyMapEntry aSvxUnoOutlinerTextCursorPropertyMap[] = + { + SVX_UNOEDIT_CHAR_PROPERTIES, + SVX_UNOEDIT_FONT_PROPERTIES, + SVX_UNOEDIT_OUTLINER_PROPERTIES, + SVX_UNOEDIT_PARA_PROPERTIES, + { u"TextUserDefinedAttributes"_ustr, EE_CHAR_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0}, + { u"ParaUserDefinedAttributes"_ustr, EE_PARA_XMLATTRIBS, cppu::UnoType<css::container::XNameContainer>::get(), 0, 0}, + }; + + return aSvxUnoOutlinerTextCursorPropertyMap; +} +static const SfxItemPropertySet* ImplGetSvxUnoOutlinerTextCursorSfxPropertySet() +{ + static SfxItemPropertySet aTextCursorSfxPropertySet( ImplGetSvxUnoOutlinerTextCursorPropertyMap() ); + return &aTextCursorSfxPropertySet; +} + + +// helper for Item/Property conversion + + +void GetSelection( struct ESelection& rSel, SvxTextForwarder const * pForwarder ) noexcept +{ + DBG_ASSERT( pForwarder, "I need a valid SvxTextForwarder!" ); + if( pForwarder ) + { + sal_Int32 nParaCount = pForwarder->GetParagraphCount(); + if(nParaCount>0) + nParaCount--; + + rSel = ESelection( 0,0, nParaCount, pForwarder->GetTextLen( nParaCount )); + } +} + +void CheckSelection( struct ESelection& rSel, SvxTextForwarder const * pForwarder ) noexcept +{ + DBG_ASSERT( pForwarder, "I need a valid SvxTextForwarder!" ); + if( !pForwarder ) + return; + + if( rSel.nStartPara == EE_PARA_MAX_COUNT ) + { + ::GetSelection( rSel, pForwarder ); + } + else + { + ESelection aMaxSelection; + GetSelection( aMaxSelection, pForwarder ); + + // check start position + if( rSel.nStartPara < aMaxSelection.nStartPara ) + { + rSel.nStartPara = aMaxSelection.nStartPara; + rSel.nStartPos = aMaxSelection.nStartPos; + } + else if( rSel.nStartPara > aMaxSelection.nEndPara ) + { + rSel.nStartPara = aMaxSelection.nEndPara; + rSel.nStartPos = aMaxSelection.nEndPos; + } + else if( rSel.nStartPos > pForwarder->GetTextLen( rSel.nStartPara ) ) + { + rSel.nStartPos = pForwarder->GetTextLen( rSel.nStartPara ); + } + + // check end position + if( rSel.nEndPara < aMaxSelection.nStartPara ) + { + rSel.nEndPara = aMaxSelection.nStartPara; + rSel.nEndPos = aMaxSelection.nStartPos; + } + else if( rSel.nEndPara > aMaxSelection.nEndPara ) + { + rSel.nEndPara = aMaxSelection.nEndPara; + rSel.nEndPos = aMaxSelection.nEndPos; + } + else if( rSel.nEndPos > pForwarder->GetTextLen( rSel.nEndPara ) ) + { + rSel.nEndPos = pForwarder->GetTextLen( rSel.nEndPara ); + } + } +} + +static void CheckSelection( struct ESelection& rSel, SvxEditSource *pEdit ) noexcept +{ + if (!pEdit) + return; + CheckSelection( rSel, pEdit->GetTextForwarder() ); +} + + + + +UNO3_GETIMPLEMENTATION_IMPL( SvxUnoTextRangeBase ); + +SvxUnoTextRangeBase::SvxUnoTextRangeBase(const SvxItemPropertySet* _pSet) + : mpPropSet(_pSet) +{ +} + +SvxUnoTextRangeBase::SvxUnoTextRangeBase(const SvxEditSource* pSource, const SvxItemPropertySet* _pSet) +: mpPropSet(_pSet) +{ + SolarMutexGuard aGuard; + + DBG_ASSERT(pSource,"SvxUnoTextRangeBase: I need a valid SvxEditSource!"); + + mpEditSource = pSource->Clone(); + if (mpEditSource != nullptr) + { + ESelection aSelection; + ::GetSelection( aSelection, mpEditSource->GetTextForwarder() ); + SetSelection( aSelection ); + + mpEditSource->addRange( this ); + } +} + +SvxUnoTextRangeBase::SvxUnoTextRangeBase(const SvxUnoTextRangeBase& rRange) +: text::XTextRange() +, beans::XPropertySet() +, beans::XMultiPropertySet() +, beans::XMultiPropertyStates() +, beans::XPropertyState() +, lang::XServiceInfo() +, text::XTextRangeCompare() +, lang::XUnoTunnel() +, osl::DebugBase<SvxUnoTextRangeBase>() +, mpPropSet(rRange.getPropertySet()) +{ + SolarMutexGuard aGuard; + + if (rRange.mpEditSource) + mpEditSource = rRange.mpEditSource->Clone(); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + maSelection = rRange.maSelection; + CheckSelection( maSelection, pForwarder ); + } + + if( mpEditSource ) + mpEditSource->addRange( this ); +} + +SvxUnoTextRangeBase::~SvxUnoTextRangeBase() noexcept +{ + if( mpEditSource ) + mpEditSource->removeRange( this ); +} + +void SvxUnoTextRangeBase::SetEditSource( SvxEditSource* pSource ) noexcept +{ + DBG_ASSERT(pSource,"SvxUnoTextRangeBase: I need a valid SvxEditSource!"); + DBG_ASSERT(mpEditSource==nullptr,"SvxUnoTextRangeBase::SetEditSource called while SvxEditSource already set" ); + + mpEditSource.reset( pSource ); + + maSelection.nStartPara = EE_PARA_MAX_COUNT; + + if( mpEditSource ) + mpEditSource->addRange( this ); +} + +/** puts a field item with a copy of the given FieldData into the itemset + corresponding with this range */ +void SvxUnoTextRangeBase::attachField( std::unique_ptr<SvxFieldData> pData ) noexcept +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + SvxFieldItem aField( std::move(pData), EE_FEATURE_FIELD ); + pForwarder->QuickInsertField( std::move(aField), maSelection ); + } +} + +void SvxUnoTextRangeBase::SetSelection( const ESelection& rSelection ) noexcept +{ + SolarMutexGuard aGuard; + + maSelection = rSelection; + CheckSelection( maSelection, mpEditSource.get() ); +} + +// Interface XTextRange ( XText ) + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextRangeBase::getStart() +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XTextRange > xRange; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + CheckSelection( maSelection, pForwarder ); + + SvxUnoTextBase* pText = comphelper::getFromUnoTunnel<SvxUnoTextBase>( getText() ); + + if(pText == nullptr) + throw uno::RuntimeException(); + + rtl::Reference<SvxUnoTextRange> pRange = new SvxUnoTextRange( *pText ); + xRange = pRange; + + ESelection aNewSel = maSelection; + aNewSel.nEndPara = aNewSel.nStartPara; + aNewSel.nEndPos = aNewSel.nStartPos; + pRange->SetSelection( aNewSel ); + } + + return xRange; +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextRangeBase::getEnd() +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XTextRange > xRet; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + CheckSelection( maSelection, pForwarder ); + + SvxUnoTextBase* pText = comphelper::getFromUnoTunnel<SvxUnoTextBase>( getText() ); + + if(pText == nullptr) + throw uno::RuntimeException(); + + rtl::Reference<SvxUnoTextRange> pNew = new SvxUnoTextRange( *pText ); + xRet = pNew; + + ESelection aNewSel = maSelection; + aNewSel.nStartPara = aNewSel.nEndPara; + aNewSel.nStartPos = aNewSel.nEndPos; + pNew->SetSelection( aNewSel ); + } + return xRet; +} + +OUString SAL_CALL SvxUnoTextRangeBase::getString() +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + CheckSelection( maSelection, pForwarder ); + + return pForwarder->GetText( maSelection ); + } + else + { + return OUString(); + } +} + +void SAL_CALL SvxUnoTextRangeBase::setString(const OUString& aString) +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( !pForwarder ) + return; + + CheckSelection( maSelection, pForwarder ); + + OUString aConverted(convertLineEnd(aString, LINEEND_LF)); // Simply count the number of line endings + + pForwarder->QuickInsertText( aConverted, maSelection ); + mpEditSource->UpdateData(); + + // Adapt selection + //! It would be easier if the EditEngine would return the selection + //! on QuickInsertText... + CollapseToStart(); + + sal_Int32 nLen = aConverted.getLength(); + if (nLen) + GoRight( nLen, true ); +} + +// Interface beans::XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL SvxUnoTextRangeBase::getPropertySetInfo() +{ + return mpPropSet->getPropertySetInfo(); +} + +void SAL_CALL SvxUnoTextRangeBase::setPropertyValue(const OUString& PropertyName, const uno::Any& aValue) +{ + if (PropertyName == UNO_TR_PROP_SELECTION) + { + text::TextRangeSelection aSel = aValue.get<text::TextRangeSelection>(); + SetSelection(toESelection(aSel)); + + return; + } + + _setPropertyValue( PropertyName, aValue ); +} + +void SvxUnoTextRangeBase::_setPropertyValue( const OUString& PropertyName, const uno::Any& aValue, sal_Int32 nPara ) +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + CheckSelection( maSelection, pForwarder ); + + const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName ); + if ( pMap ) + { + ESelection aSel( GetSelection() ); + bool bParaAttrib = (pMap->nWID >= EE_PARA_START) && ( pMap->nWID <= EE_PARA_END ); + + if (pMap->nWID == WID_PARASTYLENAME) + { + OUString aStyle = aValue.get<OUString>(); + + sal_Int32 nEndPara; + + if( nPara == -1 ) + { + nPara = aSel.nStartPara; + nEndPara = aSel.nEndPara; + } + else + { + // only one paragraph + nEndPara = nPara; + } + + while( nPara <= nEndPara ) + { + pForwarder->SetStyleSheet(nPara, aStyle); + nPara++; + } + } + else if ( nPara == -1 && !bParaAttrib ) + { + SfxItemSet aOldSet( pForwarder->GetAttribs( aSel ) ); + // we have a selection and no para attribute + SfxItemSet aNewSet( *aOldSet.GetPool(), aOldSet.GetRanges() ); + + setPropertyValue( pMap, aValue, maSelection, aOldSet, aNewSet ); + + + pForwarder->QuickSetAttribs( aNewSet, GetSelection() ); + } + else + { + sal_Int32 nEndPara; + + if( nPara == -1 ) + { + nPara = aSel.nStartPara; + nEndPara = aSel.nEndPara; + } + else + { + // only one paragraph + nEndPara = nPara; + } + + while( nPara <= nEndPara ) + { + // we have a paragraph + SfxItemSet aSet( pForwarder->GetParaAttribs( nPara ) ); + setPropertyValue( pMap, aValue, maSelection, aSet, aSet ); + pForwarder->SetParaAttribs( nPara, aSet ); + nPara++; + } + } + + GetEditSource()->UpdateData(); + return; + } + } + + throw beans::UnknownPropertyException(PropertyName); +} + +void SvxUnoTextRangeBase::setPropertyValue( const SfxItemPropertyMapEntry* pMap, const uno::Any& rValue, const ESelection& rSelection, const SfxItemSet& rOldSet, SfxItemSet& rNewSet ) +{ + if(!SetPropertyValueHelper( pMap, rValue, rNewSet, &rSelection, GetEditSource() )) + { + // For parts of composite items with multiple properties (eg background) + // must be taken from the document before the old item. + rNewSet.Put(rOldSet.Get(pMap->nWID)); // Old Item in new Set + SvxItemPropertySet::setPropertyValue(pMap, rValue, rNewSet, false ); + } +} + +bool SvxUnoTextRangeBase::SetPropertyValueHelper( const SfxItemPropertyMapEntry* pMap, const uno::Any& aValue, SfxItemSet& rNewSet, const ESelection* pSelection /* = NULL */, SvxEditSource* pEditSource /* = NULL*/ ) +{ + switch( pMap->nWID ) + { + case WID_FONTDESC: + { + awt::FontDescriptor aDesc; + if(aValue >>= aDesc) + { + SvxUnoFontDescriptor::FillItemSet( aDesc, rNewSet ); + return true; + } + } + break; + + case EE_PARA_NUMBULLET: + { + uno::Reference< container::XIndexReplace > xRule; + return !aValue.hasValue() || ((aValue >>= xRule) && !xRule.is()); + } + + case EE_PARA_OUTLLEVEL: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : nullptr; + if(pForwarder && pSelection) + { + sal_Int16 nLevel = sal_Int16(); + if( aValue >>= nLevel ) + { + // #101004# Call interface method instead of unsafe cast + if(! pForwarder->SetDepth( pSelection->nStartPara, nLevel ) ) + throw lang::IllegalArgumentException(); + + // If valid, then not yet finished. Also needs to be added to paragraph props. + return nLevel < -1 || nLevel > 9; + } + } + } + break; + case WID_NUMBERINGSTARTVALUE: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : nullptr; + if(pForwarder && pSelection) + { + sal_Int16 nStartValue = -1; + if( aValue >>= nStartValue ) + { + pForwarder->SetNumberingStartValue( pSelection->nStartPara, nStartValue ); + return true; + } + } + } + break; + case WID_PARAISNUMBERINGRESTART: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : nullptr; + if(pForwarder && pSelection) + { + bool bParaIsNumberingRestart = false; + if( aValue >>= bParaIsNumberingRestart ) + { + pForwarder->SetParaIsNumberingRestart( pSelection->nStartPara, bParaIsNumberingRestart ); + return true; + } + } + } + break; + case EE_PARA_BULLETSTATE: + { + bool bBullet = true; + if( aValue >>= bBullet ) + { + SfxBoolItem aItem( EE_PARA_BULLETSTATE, bBullet ); + rNewSet.Put(aItem); + return true; + } + } + break; + + default: + return false; + } + + throw lang::IllegalArgumentException(); +} + +uno::Any SAL_CALL SvxUnoTextRangeBase::getPropertyValue(const OUString& PropertyName) +{ + if (PropertyName == UNO_TR_PROP_SELECTION) + { + const ESelection& rSel = GetSelection(); + text::TextRangeSelection aSel; + aSel.Start.Paragraph = rSel.nStartPara; + aSel.Start.PositionInParagraph = rSel.nStartPos; + aSel.End.Paragraph = rSel.nEndPara; + aSel.End.PositionInParagraph = rSel.nEndPos; + return uno::Any(aSel); + } + + return _getPropertyValue( PropertyName ); +} + +uno::Any SvxUnoTextRangeBase::_getPropertyValue(const OUString& PropertyName, sal_Int32 nPara ) +{ + SolarMutexGuard aGuard; + + uno::Any aAny; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry(PropertyName ); + if( pMap ) + { + std::optional<SfxItemSet> oAttribs; + if( nPara != -1 ) + oAttribs.emplace(pForwarder->GetParaAttribs( nPara ).CloneAsValue()); + else + oAttribs.emplace(pForwarder->GetAttribs( GetSelection() ).CloneAsValue()); + + // Replace Dontcare with Default, so that one always has a mirror + oAttribs->ClearInvalidItems(); + + getPropertyValue( pMap, aAny, *oAttribs ); + + return aAny; + } + } + + throw beans::UnknownPropertyException(PropertyName); +} + +void SvxUnoTextRangeBase::getPropertyValue( const SfxItemPropertyMapEntry* pMap, uno::Any& rAny, const SfxItemSet& rSet ) +{ + switch( pMap->nWID ) + { + case EE_FEATURE_FIELD: + if ( rSet.GetItemState( EE_FEATURE_FIELD, false ) == SfxItemState::SET ) + { + const SvxFieldItem* pItem = rSet.GetItem<SvxFieldItem>( EE_FEATURE_FIELD ); + const SvxFieldData* pData = pItem->GetField(); + uno::Reference< text::XTextRange > xAnchor( this ); + + // get presentation string for field + std::optional<Color> pTColor; + std::optional<Color> pFColor; + std::optional<FontLineStyle> pFldLineStyle; + + SvxTextForwarder* pForwarder = mpEditSource->GetTextForwarder(); + OUString aPresentation( pForwarder->CalcFieldValue( SvxFieldItem(*pData, EE_FEATURE_FIELD), maSelection.nStartPara, maSelection.nStartPos, pTColor, pFColor, pFldLineStyle ) ); + + uno::Reference< text::XTextField > xField( new SvxUnoTextField( xAnchor, aPresentation, pData ) ); + rAny <<= xField; + } + break; + + case WID_PORTIONTYPE: + if ( rSet.GetItemState( EE_FEATURE_FIELD, false ) == SfxItemState::SET ) + { + rAny <<= OUString("TextField"); + } + else + { + rAny <<= OUString("Text"); + } + break; + + case WID_PARASTYLENAME: + { + rAny <<= GetEditSource()->GetTextForwarder()->GetStyleSheet(maSelection.nStartPara); + } + break; + + default: + if(!GetPropertyValueHelper( *const_cast<SfxItemSet*>(&rSet), pMap, rAny, &maSelection, GetEditSource() )) + rAny = SvxItemPropertySet::getPropertyValue(pMap, rSet, true, false ); + } +} + +bool SvxUnoTextRangeBase::GetPropertyValueHelper( SfxItemSet const & rSet, const SfxItemPropertyMapEntry* pMap, uno::Any& aAny, const ESelection* pSelection /* = NULL */, SvxEditSource* pEditSource /* = NULL */ ) +{ + switch( pMap->nWID ) + { + case WID_FONTDESC: + { + awt::FontDescriptor aDesc; + SvxUnoFontDescriptor::FillFromItemSet( rSet, aDesc ); + aAny <<= aDesc; + } + break; + + case EE_PARA_NUMBULLET: + { + SfxItemState eState = rSet.GetItemState( EE_PARA_NUMBULLET ); + if( eState != SfxItemState::SET && eState != SfxItemState::DEFAULT) + throw uno::RuntimeException(); + + const SvxNumBulletItem* pBulletItem = rSet.GetItem( EE_PARA_NUMBULLET ); + + if( pBulletItem == nullptr ) + throw uno::RuntimeException(); + + aAny <<= SvxCreateNumRule( pBulletItem->GetNumRule() ); + } + break; + + case EE_PARA_OUTLLEVEL: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : nullptr; + if(pForwarder && pSelection) + { + sal_Int16 nLevel = pForwarder->GetDepth( pSelection->nStartPara ); + if( nLevel >= 0 ) + aAny <<= nLevel; + } + } + break; + case WID_NUMBERINGSTARTVALUE: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : nullptr; + if(pForwarder && pSelection) + aAny <<= pForwarder->GetNumberingStartValue( pSelection->nStartPara ); + } + break; + case WID_PARAISNUMBERINGRESTART: + { + SvxTextForwarder* pForwarder = pEditSource? pEditSource->GetTextForwarder() : nullptr; + if(pForwarder && pSelection) + aAny <<= pForwarder->IsParaIsNumberingRestart( pSelection->nStartPara ); + } + break; + + case EE_PARA_BULLETSTATE: + { + bool bState = false; + SfxItemState eState = rSet.GetItemState( EE_PARA_BULLETSTATE ); + if( eState == SfxItemState::SET || eState == SfxItemState::DEFAULT ) + { + const SfxBoolItem* pItem = rSet.GetItem<SfxBoolItem>( EE_PARA_BULLETSTATE ); + bState = pItem->GetValue(); + } + + aAny <<= bState; + } + break; + default: + + return false; + } + + return true; +} + +// is not (yet) supported +void SAL_CALL SvxUnoTextRangeBase::addPropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) {} +void SAL_CALL SvxUnoTextRangeBase::removePropertyChangeListener( const OUString& , const uno::Reference< beans::XPropertyChangeListener >& ) {} +void SAL_CALL SvxUnoTextRangeBase::addVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) {} +void SAL_CALL SvxUnoTextRangeBase::removeVetoableChangeListener( const OUString& , const uno::Reference< beans::XVetoableChangeListener >& ) {} + +// XMultiPropertySet +void SAL_CALL SvxUnoTextRangeBase::setPropertyValues( const uno::Sequence< OUString >& aPropertyNames, const uno::Sequence< uno::Any >& aValues ) +{ + _setPropertyValues( aPropertyNames, aValues ); +} + +void SvxUnoTextRangeBase::_setPropertyValues( const uno::Sequence< OUString >& aPropertyNames, const uno::Sequence< uno::Any >& aValues, sal_Int32 nPara ) +{ + if (aPropertyNames.getLength() != aValues.getLength()) + throw lang::IllegalArgumentException("lengths do not match", + static_cast<css::beans::XPropertySet*>(this), -1); + + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( !pForwarder ) + return; + + CheckSelection( maSelection, pForwarder ); + + ESelection aSel( GetSelection() ); + + const OUString* pPropertyNames = aPropertyNames.getConstArray(); + const uno::Any* pValues = aValues.getConstArray(); + sal_Int32 nCount = aPropertyNames.getLength(); + + sal_Int32 nEndPara = nPara; + sal_Int32 nTempPara = nPara; + + if( nTempPara == -1 ) + { + nTempPara = aSel.nStartPara; + nEndPara = aSel.nEndPara; + } + + std::optional<SfxItemSet> pOldAttrSet; + std::optional<SfxItemSet> pNewAttrSet; + + std::optional<SfxItemSet> pOldParaSet; + std::optional<SfxItemSet> pNewParaSet; + + std::optional<OUString> aStyleName; + + for( ; nCount; nCount--, pPropertyNames++, pValues++ ) + { + const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry( *pPropertyNames ); + + if( pMap ) + { + bool bParaAttrib = (pMap->nWID >= EE_PARA_START) && ( pMap->nWID <= EE_PARA_END ); + + if (pMap->nWID == WID_PARASTYLENAME) + { + aStyleName.emplace((*pValues).get<OUString>()); + } + else if( (nPara == -1) && !bParaAttrib ) + { + if( !pNewAttrSet ) + { + pOldAttrSet.emplace( pForwarder->GetAttribs( aSel ) ); + pNewAttrSet.emplace( *pOldAttrSet->GetPool(), pOldAttrSet->GetRanges() ); + } + + setPropertyValue( pMap, *pValues, GetSelection(), *pOldAttrSet, *pNewAttrSet ); + + if( pMap->nWID >= EE_ITEMS_START && pMap->nWID <= EE_ITEMS_END ) + { + const SfxPoolItem* pItem; + if( pNewAttrSet->GetItemState( pMap->nWID, true, &pItem ) == SfxItemState::SET ) + { + pOldAttrSet->Put( *pItem ); + } + } + } + else + { + if( !pNewParaSet ) + { + const SfxItemSet & rSet = pForwarder->GetParaAttribs( nTempPara ); + pOldParaSet.emplace( rSet ); + pNewParaSet.emplace( *pOldParaSet->GetPool(), pOldParaSet->GetRanges() ); + } + + setPropertyValue( pMap, *pValues, GetSelection(), *pOldParaSet, *pNewParaSet ); + + if( pMap->nWID >= EE_ITEMS_START && pMap->nWID <= EE_ITEMS_END ) + { + const SfxPoolItem* pItem; + if( pNewParaSet->GetItemState( pMap->nWID, true, &pItem ) == SfxItemState::SET ) + { + pOldParaSet->Put( *pItem ); + } + } + + } + } + } + + bool bNeedsUpdate = false; + + if( pNewParaSet || aStyleName ) + { + if( pNewParaSet->Count() ) + { + while( nTempPara <= nEndPara ) + { + SfxItemSet aSet( pForwarder->GetParaAttribs( nTempPara ) ); + aSet.Put( *pNewParaSet ); + pForwarder->SetParaAttribs( nTempPara, aSet ); + if (aStyleName) + pForwarder->SetStyleSheet(nTempPara, *aStyleName); + nTempPara++; + } + bNeedsUpdate = true; + } + + pNewParaSet.reset(); + pOldParaSet.reset(); + } + + if( pNewAttrSet ) + { + if( pNewAttrSet->Count() ) + { + pForwarder->QuickSetAttribs( *pNewAttrSet, GetSelection() ); + bNeedsUpdate = true; + } + pNewAttrSet.reset(); + pOldAttrSet.reset(); + } + + if( bNeedsUpdate ) + GetEditSource()->UpdateData(); +} + +uno::Sequence< uno::Any > SAL_CALL SvxUnoTextRangeBase::getPropertyValues( const uno::Sequence< OUString >& aPropertyNames ) +{ + return _getPropertyValues( aPropertyNames ); +} + +uno::Sequence< uno::Any > SvxUnoTextRangeBase::_getPropertyValues( const uno::Sequence< OUString >& aPropertyNames, sal_Int32 nPara ) +{ + SolarMutexGuard aGuard; + + sal_Int32 nCount = aPropertyNames.getLength(); + + + uno::Sequence< uno::Any > aValues( nCount ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + std::optional<SfxItemSet> oAttribs; + if( nPara != -1 ) + oAttribs.emplace(pForwarder->GetParaAttribs( nPara ).CloneAsValue()); + else + oAttribs.emplace(pForwarder->GetAttribs( GetSelection() ).CloneAsValue() ); + + oAttribs->ClearInvalidItems(); + + const OUString* pPropertyNames = aPropertyNames.getConstArray(); + uno::Any* pValues = aValues.getArray(); + + for( ; nCount; nCount--, pPropertyNames++, pValues++ ) + { + const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry( *pPropertyNames ); + if( pMap ) + { + getPropertyValue( pMap, *pValues, *oAttribs ); + } + } + } + + return aValues; +} + +void SAL_CALL SvxUnoTextRangeBase::addPropertiesChangeListener( const uno::Sequence< OUString >& , const uno::Reference< beans::XPropertiesChangeListener >& ) +{ +} + +void SAL_CALL SvxUnoTextRangeBase::removePropertiesChangeListener( const uno::Reference< beans::XPropertiesChangeListener >& ) +{ +} + +void SAL_CALL SvxUnoTextRangeBase::firePropertiesChangeEvent( const uno::Sequence< OUString >& , const uno::Reference< beans::XPropertiesChangeListener >& ) +{ +} + +// beans::XPropertyState +beans::PropertyState SAL_CALL SvxUnoTextRangeBase::getPropertyState( const OUString& PropertyName ) +{ + return _getPropertyState( PropertyName ); +} + +const sal_uInt16 aSvxUnoFontDescriptorWhichMap[] = { EE_CHAR_FONTINFO, EE_CHAR_FONTHEIGHT, EE_CHAR_ITALIC, + EE_CHAR_UNDERLINE, EE_CHAR_WEIGHT, EE_CHAR_STRIKEOUT, EE_CHAR_CASEMAP, + EE_CHAR_WLM, 0 }; + +beans::PropertyState SvxUnoTextRangeBase::_getPropertyState(const SfxItemPropertyMapEntry* pMap, sal_Int32 nPara) +{ + if ( pMap ) + { + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + SfxItemState eItemState(SfxItemState::DEFAULT); + bool bItemStateSet(false); + + switch( pMap->nWID ) + { + case WID_FONTDESC: + { + const sal_uInt16* pWhichId = aSvxUnoFontDescriptorWhichMap; + while( *pWhichId ) + { + const SfxItemState eTempItemState(nPara != -1 + ? pForwarder->GetItemState( nPara, *pWhichId ) + : pForwarder->GetItemState( GetSelection(), *pWhichId )); + + switch( eTempItemState ) + { + case SfxItemState::DISABLED: + case SfxItemState::DONTCARE: + eItemState = SfxItemState::DONTCARE; + bItemStateSet = true; + break; + + case SfxItemState::DEFAULT: + if( !bItemStateSet ) + { + eItemState = SfxItemState::DEFAULT; + bItemStateSet = true; + } + break; + + case SfxItemState::SET: + if( !bItemStateSet ) + { + eItemState = SfxItemState::SET; + bItemStateSet = true; + } + break; + default: + throw beans::UnknownPropertyException(); + } + + pWhichId++; + } + } + break; + + case WID_NUMBERINGSTARTVALUE: + case WID_PARAISNUMBERINGRESTART: + case WID_PARASTYLENAME: + eItemState = SfxItemState::SET; + bItemStateSet = true; + break; + + default: + if(0 != pMap->nWID) + { + if( nPara != -1 ) + eItemState = pForwarder->GetItemState( nPara, pMap->nWID ); + else + eItemState = pForwarder->GetItemState( GetSelection(), pMap->nWID ); + + bItemStateSet = true; + } + break; + } + + if(bItemStateSet) + { + switch( eItemState ) + { + case SfxItemState::DONTCARE: + case SfxItemState::DISABLED: + return beans::PropertyState_AMBIGUOUS_VALUE; + case SfxItemState::SET: + return beans::PropertyState_DIRECT_VALUE; + case SfxItemState::DEFAULT: + return beans::PropertyState_DEFAULT_VALUE; + default: break; + } + } + } + } + throw beans::UnknownPropertyException(); +} + +beans::PropertyState SvxUnoTextRangeBase::_getPropertyState(std::u16string_view PropertyName, sal_Int32 nPara /* = -1 */) +{ + SolarMutexGuard aGuard; + + return _getPropertyState( mpPropSet->getPropertyMapEntry( PropertyName ), nPara); +} + +uno::Sequence< beans::PropertyState > SAL_CALL SvxUnoTextRangeBase::getPropertyStates( const uno::Sequence< OUString >& aPropertyName ) +{ + return _getPropertyStates( aPropertyName ); +} + +uno::Sequence< beans::PropertyState > SvxUnoTextRangeBase::_getPropertyStates(const uno::Sequence< OUString >& PropertyName, sal_Int32 nPara /* = -1 */) +{ + uno::Sequence< beans::PropertyState > aRet( PropertyName.getLength() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + std::optional<SfxItemSet> pSet; + if( nPara != -1 ) + { + pSet.emplace( pForwarder->GetParaAttribs( nPara ) ); + } + else + { + ESelection aSel( GetSelection() ); + CheckSelection( aSel, pForwarder ); + pSet.emplace( pForwarder->GetAttribs( aSel, EditEngineAttribs::OnlyHard ) ); + } + + beans::PropertyState* pState = aRet.getArray(); + for( const OUString& rName : PropertyName ) + { + const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry( rName ); + if( !_getOnePropertyStates(*pSet, pMap, *pState++) ) + { + throw beans::UnknownPropertyException(rName); + } + } + } + + return aRet; +} + +bool SvxUnoTextRangeBase::_getOnePropertyStates(const SfxItemSet& rSet, const SfxItemPropertyMapEntry* pMap, beans::PropertyState& rState) +{ + if (!pMap) + return true; + SfxItemState eItemState = SfxItemState::DEFAULT; + bool bItemStateSet(false); + + bool bUnknownPropertyFound = false; + switch( pMap->nWID ) + { + case WID_FONTDESC: + { + const sal_uInt16* pWhichId = aSvxUnoFontDescriptorWhichMap; + while( *pWhichId ) + { + const SfxItemState eTempItemState(rSet.GetItemState( *pWhichId )); + + switch( eTempItemState ) + { + case SfxItemState::DISABLED: + case SfxItemState::DONTCARE: + eItemState = SfxItemState::DONTCARE; + bItemStateSet = true; + break; + + case SfxItemState::DEFAULT: + if( !bItemStateSet ) + { + eItemState = SfxItemState::DEFAULT; + bItemStateSet = true; + } + break; + + case SfxItemState::SET: + if( !bItemStateSet ) + { + eItemState = SfxItemState::SET; + bItemStateSet = true; + } + break; + default: + bUnknownPropertyFound = true; + break; + } + + pWhichId++; + } + } + break; + + case WID_NUMBERINGSTARTVALUE: + case WID_PARAISNUMBERINGRESTART: + case WID_PARASTYLENAME: + eItemState = SfxItemState::SET; + bItemStateSet = true; + break; + + default: + if(0 != pMap->nWID) + { + eItemState = rSet.GetItemState( pMap->nWID, false ); + bItemStateSet = true; + } + break; + } + + if( bUnknownPropertyFound ) + return false; + + if(bItemStateSet) + { + if (pMap->nWID == EE_CHAR_COLOR) + { + // Theme & effects can be DEFAULT_VALUE, even if the same pool item has a color + // which is a DIRECT_VALUE. + const SvxColorItem* pColor = rSet.GetItem<SvxColorItem>(EE_CHAR_COLOR); + if (!pColor) + { + SAL_WARN("editeng", "Missing EE_CHAR_COLOR SvxColorItem"); + return false; + } + switch (pMap->nMemberId) + { + case MID_COLOR_THEME_INDEX: + if (!pColor->getComplexColor().isValidThemeType()) + { + eItemState = SfxItemState::DEFAULT; + } + break; + case MID_COLOR_LUM_MOD: + { + sal_Int16 nLumMod = 10000; + for (auto const& rTransform : pColor->getComplexColor().getTransformations()) + { + if (rTransform.meType == model::TransformationType::LumMod) + nLumMod = rTransform.mnValue; + } + if (nLumMod == 10000) + { + eItemState = SfxItemState::DEFAULT; + } + break; + } + case MID_COLOR_LUM_OFF: + { + sal_Int16 nLumOff = 0; + for (auto const& rTransform : pColor->getComplexColor().getTransformations()) + { + if (rTransform.meType == model::TransformationType::LumOff) + nLumOff = rTransform.mnValue; + } + if (nLumOff == 0) + { + eItemState = SfxItemState::DEFAULT; + } + break; + } + case MID_COMPLEX_COLOR: + if (pColor->getComplexColor().getType() == model::ColorType::Unused) + { + eItemState = SfxItemState::DEFAULT; + } + break; + } + } + + switch( eItemState ) + { + case SfxItemState::SET: + rState = beans::PropertyState_DIRECT_VALUE; + break; + case SfxItemState::DEFAULT: + rState = beans::PropertyState_DEFAULT_VALUE; + break; +// case SfxItemState::DONTCARE: +// case SfxItemState::DISABLED: + default: + rState = beans::PropertyState_AMBIGUOUS_VALUE; + } + } + else + { + rState = beans::PropertyState_AMBIGUOUS_VALUE; + } + return true; +} + +void SAL_CALL SvxUnoTextRangeBase::setPropertyToDefault( const OUString& PropertyName ) +{ + _setPropertyToDefault( PropertyName ); +} + +void SvxUnoTextRangeBase::_setPropertyToDefault(const OUString& PropertyName, sal_Int32 nPara /* = -1 */) +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + + if( pForwarder ) + { + const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry( PropertyName ); + if ( pMap ) + { + CheckSelection( maSelection, mpEditSource->GetTextForwarder() ); + _setPropertyToDefault( pForwarder, pMap, nPara ); + return; + } + } + + throw beans::UnknownPropertyException(PropertyName); +} + +void SvxUnoTextRangeBase::_setPropertyToDefault(SvxTextForwarder* pForwarder, const SfxItemPropertyMapEntry* pMap, sal_Int32 nPara ) +{ + do + { + SfxItemSet aSet(*pForwarder->GetPool()); + + if( pMap->nWID == WID_FONTDESC ) + { + SvxUnoFontDescriptor::setPropertyToDefault( aSet ); + } + else if( pMap->nWID == WID_NUMBERINGSTARTVALUE ) + { + pForwarder->SetNumberingStartValue( maSelection.nStartPara, -1 ); + } + else if( pMap->nWID == WID_PARAISNUMBERINGRESTART ) + { + pForwarder->SetParaIsNumberingRestart( maSelection.nStartPara, false ); + } + else + { + aSet.InvalidateItem( pMap->nWID ); + } + + if(nPara != -1) + pForwarder->SetParaAttribs( nPara, aSet ); + else + pForwarder->QuickSetAttribs( aSet, GetSelection() ); + + GetEditSource()->UpdateData(); + + return; + } + while(false); +} + +uno::Any SAL_CALL SvxUnoTextRangeBase::getPropertyDefault( const OUString& aPropertyName ) +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( pForwarder ) + { + const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMapEntry( aPropertyName ); + if( pMap ) + { + SfxItemPool* pPool = pForwarder->GetPool(); + + switch( pMap->nWID ) + { + case WID_FONTDESC: + return SvxUnoFontDescriptor::getPropertyDefault( pPool ); + + case EE_PARA_OUTLLEVEL: + { + uno::Any aAny; + return aAny; + } + + case WID_NUMBERINGSTARTVALUE: + return uno::Any( sal_Int16(-1) ); + + case WID_PARAISNUMBERINGRESTART: + return uno::Any( false ); + + default: + { + // Get Default from ItemPool + if(SfxItemPool::IsWhich(pMap->nWID)) + { + SfxItemSet aSet( *pPool, pMap->nWID, pMap->nWID ); + aSet.Put(pPool->GetDefaultItem(pMap->nWID)); + return SvxItemPropertySet::getPropertyValue(pMap, aSet, true, false ); + } + } + } + } + } + throw beans::UnknownPropertyException(aPropertyName); +} + +// beans::XMultiPropertyStates +void SAL_CALL SvxUnoTextRangeBase::setAllPropertiesToDefault() +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + + if( pForwarder ) + { + for (const SfxItemPropertyMapEntry* entry : mpPropSet->getPropertyMap().getPropertyEntries()) + { + _setPropertyToDefault( pForwarder, entry, -1 ); + } + } +} + +void SAL_CALL SvxUnoTextRangeBase::setPropertiesToDefault( const uno::Sequence< OUString >& aPropertyNames ) +{ + for( const OUString& rName : aPropertyNames ) + { + setPropertyToDefault( rName ); + } +} + +uno::Sequence< uno::Any > SAL_CALL SvxUnoTextRangeBase::getPropertyDefaults( const uno::Sequence< OUString >& aPropertyNames ) +{ + uno::Sequence< uno::Any > ret( aPropertyNames.getLength() ); + uno::Any* pDefaults = ret.getArray(); + + for( const OUString& rName : aPropertyNames ) + { + *pDefaults++ = getPropertyDefault( rName ); + } + + return ret; +} + +// internal +void SvxUnoTextRangeBase::CollapseToStart() noexcept +{ + CheckSelection( maSelection, mpEditSource.get() ); + + maSelection.nEndPara = maSelection.nStartPara; + maSelection.nEndPos = maSelection.nStartPos; +} + +void SvxUnoTextRangeBase::CollapseToEnd() noexcept +{ + CheckSelection( maSelection, mpEditSource.get() ); + + maSelection.nStartPara = maSelection.nEndPara; + maSelection.nStartPos = maSelection.nEndPos; +} + +bool SvxUnoTextRangeBase::IsCollapsed() noexcept +{ + CheckSelection( maSelection, mpEditSource.get() ); + + return ( maSelection.nStartPara == maSelection.nEndPara && + maSelection.nStartPos == maSelection.nEndPos ); +} + +bool SvxUnoTextRangeBase::GoLeft(sal_Int32 nCount, bool Expand) noexcept +{ + CheckSelection( maSelection, mpEditSource.get() ); + + // #75098# use end position, as in Writer (start is anchor, end is cursor) + sal_Int32 nNewPos = maSelection.nEndPos; + sal_Int32 nNewPar = maSelection.nEndPara; + + bool bOk = true; + SvxTextForwarder* pForwarder = nullptr; + while ( nCount > nNewPos && bOk ) + { + if ( nNewPar == 0 ) + bOk = false; + else + { + if ( !pForwarder ) + pForwarder = mpEditSource->GetTextForwarder(); // first here, it is necessary... + + --nNewPar; + nCount -= nNewPos + 1; + nNewPos = pForwarder->GetTextLen( nNewPar ); + } + } + + if ( bOk ) + { + nNewPos = nNewPos - nCount; + maSelection.nStartPara = nNewPar; + maSelection.nStartPos = nNewPos; + } + + if (!Expand) + CollapseToStart(); + + return bOk; +} + +bool SvxUnoTextRangeBase::GoRight(sal_Int32 nCount, bool Expand) noexcept +{ + if (!mpEditSource) + return false; + SvxTextForwarder* pForwarder = mpEditSource->GetTextForwarder(); + if( !pForwarder ) + return false; + + CheckSelection( maSelection, pForwarder ); + + sal_Int32 nNewPos = maSelection.nEndPos + nCount; + sal_Int32 nNewPar = maSelection.nEndPara; + + bool bOk = true; + sal_Int32 nParCount = pForwarder->GetParagraphCount(); + sal_Int32 nThisLen = pForwarder->GetTextLen( nNewPar ); + while ( nNewPos > nThisLen && bOk ) + { + if ( nNewPar + 1 >= nParCount ) + bOk = false; + else + { + nNewPos -= nThisLen+1; + ++nNewPar; + nThisLen = pForwarder->GetTextLen( nNewPar ); + } + } + + if (bOk) + { + maSelection.nEndPara = nNewPar; + maSelection.nEndPos = nNewPos; + } + + if (!Expand) + CollapseToEnd(); + + return bOk; +} + +void SvxUnoTextRangeBase::GotoStart(bool Expand) noexcept +{ + maSelection.nStartPara = 0; + maSelection.nStartPos = 0; + + if (!Expand) + CollapseToStart(); +} + +void SvxUnoTextRangeBase::GotoEnd(bool Expand) noexcept +{ + CheckSelection( maSelection, mpEditSource.get() ); + + SvxTextForwarder* pForwarder = mpEditSource ? mpEditSource->GetTextForwarder() : nullptr; + if( !pForwarder ) + return; + + sal_Int32 nPar = pForwarder->GetParagraphCount(); + if (nPar) + --nPar; + + maSelection.nEndPara = nPar; + maSelection.nEndPos = pForwarder->GetTextLen( nPar ); + + if (!Expand) + CollapseToEnd(); +} + +// lang::XServiceInfo +sal_Bool SAL_CALL SvxUnoTextRangeBase::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextRangeBase::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +uno::Sequence< OUString > SvxUnoTextRangeBase::getSupportedServiceNames_Static() +{ + return { "com.sun.star.style.CharacterProperties", + "com.sun.star.style.CharacterPropertiesComplex", + "com.sun.star.style.CharacterPropertiesAsian" }; +} + +// XTextRangeCompare +sal_Int16 SAL_CALL SvxUnoTextRangeBase::compareRegionStarts( const uno::Reference< text::XTextRange >& xR1, const uno::Reference< text::XTextRange >& xR2 ) +{ + SvxUnoTextRangeBase* pR1 = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( xR1 ); + SvxUnoTextRangeBase* pR2 = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( xR2 ); + + if( (pR1 == nullptr) || (pR2 == nullptr) ) + throw lang::IllegalArgumentException(); + + const ESelection& r1 = pR1->maSelection; + const ESelection& r2 = pR2->maSelection; + + if( r1.nStartPara == r2.nStartPara ) + { + if( r1.nStartPos == r2.nStartPos ) + return 0; + else + return r1.nStartPos < r2.nStartPos ? 1 : -1; + } + else + { + return r1.nStartPara < r2.nStartPara ? 1 : -1; + } +} + +sal_Int16 SAL_CALL SvxUnoTextRangeBase::compareRegionEnds( const uno::Reference< text::XTextRange >& xR1, const uno::Reference< text::XTextRange >& xR2 ) +{ + SvxUnoTextRangeBase* pR1 = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( xR1 ); + SvxUnoTextRangeBase* pR2 = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( xR2 ); + + if( (pR1 == nullptr) || (pR2 == nullptr) ) + throw lang::IllegalArgumentException(); + + const ESelection& r1 = pR1->maSelection; + const ESelection& r2 = pR2->maSelection; + + if( r1.nEndPara == r2.nEndPara ) + { + if( r1.nEndPos == r2.nEndPos ) + return 0; + else + return r1.nEndPos < r2.nEndPos ? 1 : -1; + } + else + { + return r1.nEndPara < r2.nEndPara ? 1 : -1; + } +} + +SvxUnoTextRange::SvxUnoTextRange(const SvxUnoTextBase& rParent, bool bPortion /* = false */) +:SvxUnoTextRangeBase( rParent.GetEditSource(), bPortion ? ImplGetSvxTextPortionSvxPropertySet() : rParent.getPropertySet() ), + mbPortion( bPortion ) +{ + xParentText = static_cast<text::XText*>(const_cast<SvxUnoTextBase *>(&rParent)); +} + +SvxUnoTextRange::~SvxUnoTextRange() noexcept +{ +} + +uno::Any SAL_CALL SvxUnoTextRange::queryAggregation( const uno::Type & rType ) +{ + QUERYINT( text::XTextRange ); + else if( rType == cppu::UnoType<beans::XMultiPropertyStates>::get()) + return uno::Any(uno::Reference< beans::XMultiPropertyStates >(this)); + else if( rType == cppu::UnoType<beans::XPropertySet>::get()) + return uno::Any(uno::Reference< beans::XPropertySet >(this)); + else QUERYINT( beans::XPropertyState ); + else QUERYINT( text::XTextRangeCompare ); + else if( rType == cppu::UnoType<beans::XMultiPropertySet>::get()) + return uno::Any(uno::Reference< beans::XMultiPropertySet >(this)); + else QUERYINT( lang::XServiceInfo ); + else QUERYINT( lang::XTypeProvider ); + else QUERYINT( lang::XUnoTunnel ); + else + return OWeakAggObject::queryAggregation( rType ); +} + +uno::Any SAL_CALL SvxUnoTextRange::queryInterface( const uno::Type & rType ) +{ + return OWeakAggObject::queryInterface(rType); +} + +void SAL_CALL SvxUnoTextRange::acquire() + noexcept +{ + OWeakAggObject::acquire(); +} + +void SAL_CALL SvxUnoTextRange::release() + noexcept +{ + OWeakAggObject::release(); +} + +// XTypeProvider + +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextRange::getTypes() +{ + static const uno::Sequence< uno::Type > TYPES { + cppu::UnoType<text::XTextRange>::get(), + cppu::UnoType<beans::XPropertySet>::get(), + cppu::UnoType<beans::XMultiPropertySet>::get(), + cppu::UnoType<beans::XMultiPropertyStates>::get(), + cppu::UnoType<beans::XPropertyState>::get(), + cppu::UnoType<lang::XServiceInfo>::get(), + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<lang::XUnoTunnel>::get(), + cppu::UnoType<text::XTextRangeCompare>::get() }; + return TYPES; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextRange::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// XTextRange +uno::Reference< text::XText > SAL_CALL SvxUnoTextRange::getText() +{ + return xParentText; +} + +// lang::XServiceInfo +OUString SAL_CALL SvxUnoTextRange::getImplementationName() +{ + return "SvxUnoTextRange"; +} + + + + +SvxUnoTextBase::SvxUnoTextBase(const SvxItemPropertySet* _pSet) + : SvxUnoTextRangeBase(_pSet) +{ +} + +SvxUnoTextBase::SvxUnoTextBase(const SvxEditSource* pSource, const SvxItemPropertySet* _pSet, uno::Reference < text::XText > const & xParent) + : SvxUnoTextRangeBase(pSource, _pSet) +{ + xParentText = xParent; + ESelection aSelection; + ::GetSelection( aSelection, GetEditSource()->GetTextForwarder() ); + SetSelection( aSelection ); +} + +SvxUnoTextBase::SvxUnoTextBase(const SvxUnoTextBase& rText) +: SvxUnoTextRangeBase( rText ) +, text::XTextAppend() +, text::XTextCopy() +, container::XEnumerationAccess() +, text::XTextRangeMover() +, lang::XTypeProvider() +{ + xParentText = rText.xParentText; +} + +SvxUnoTextBase::~SvxUnoTextBase() noexcept +{ +} + +// XInterface +uno::Any SAL_CALL SvxUnoTextBase::queryAggregation( const uno::Type & rType ) +{ + QUERYINT( text::XText ); + QUERYINT( text::XSimpleText ); + if( rType == cppu::UnoType<text::XTextRange>::get()) + return uno::Any(uno::Reference< text::XTextRange >(static_cast<text::XText*>(this))); + QUERYINT(container::XEnumerationAccess ); + QUERYINT( container::XElementAccess ); + QUERYINT( beans::XMultiPropertyStates ); + QUERYINT( beans::XPropertySet ); + QUERYINT( beans::XMultiPropertySet ); + QUERYINT( beans::XPropertyState ); + QUERYINT( text::XTextRangeCompare ); + QUERYINT( lang::XServiceInfo ); + QUERYINT( text::XTextRangeMover ); + QUERYINT( text::XTextCopy ); + QUERYINT( text::XTextAppend ); + QUERYINT( text::XParagraphAppend ); + QUERYINT( text::XTextPortionAppend ); + QUERYINT( lang::XTypeProvider ); + QUERYINT( lang::XUnoTunnel ); + + return uno::Any(); +} + +// XTypeProvider + +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextBase::getTypes() +{ + static const uno::Sequence< uno::Type > TYPES { + cppu::UnoType<text::XText>::get(), + cppu::UnoType<container::XEnumerationAccess>::get(), + cppu::UnoType<beans::XPropertySet>::get(), + cppu::UnoType<beans::XMultiPropertySet>::get(), + cppu::UnoType<beans::XMultiPropertyStates>::get(), + cppu::UnoType<beans::XPropertyState>::get(), + cppu::UnoType<text::XTextRangeMover>::get(), + cppu::UnoType<text::XTextAppend>::get(), + cppu::UnoType<text::XTextCopy>::get(), + cppu::UnoType<text::XParagraphAppend>::get(), + cppu::UnoType<text::XTextPortionAppend>::get(), + cppu::UnoType<lang::XServiceInfo>::get(), + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<lang::XUnoTunnel>::get(), + cppu::UnoType<text::XTextRangeCompare>::get() }; + return TYPES; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextBase::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Reference< text::XTextCursor > SvxUnoTextBase::createTextCursorBySelection( const ESelection& rSel ) +{ + rtl::Reference<SvxUnoTextCursor> pCursor = new SvxUnoTextCursor( *this ); + pCursor->SetSelection( rSel ); + return pCursor; +} + +// XSimpleText + +uno::Reference< text::XTextCursor > SAL_CALL SvxUnoTextBase::createTextCursor() +{ + SolarMutexGuard aGuard; + return new SvxUnoTextCursor( *this ); +} + +uno::Reference< text::XTextCursor > SAL_CALL SvxUnoTextBase::createTextCursorByRange( const uno::Reference< text::XTextRange >& aTextPosition ) +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XTextCursor > xCursor; + + if( aTextPosition.is() ) + { + SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( aTextPosition ); + if(pRange) + xCursor = createTextCursorBySelection( pRange->GetSelection() ); + } + + return xCursor; +} + +void SAL_CALL SvxUnoTextBase::insertString( const uno::Reference< text::XTextRange >& xRange, const OUString& aString, sal_Bool bAbsorb ) +{ + SolarMutexGuard aGuard; + + if( !xRange.is() ) + return; + + SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRange>( xRange ); + if(!pRange) + return; + + // setString on SvxUnoTextRangeBase instead of itself QuickInsertText + // and UpdateData, so that the selection will be adjusted to + // SvxUnoTextRangeBase. Actually all cursor objects of this Text must + // to be statement to be adapted! + + if (!bAbsorb) // do not replace -> append on tail + pRange->CollapseToEnd(); + + pRange->setString( aString ); + + pRange->CollapseToEnd(); + + if (GetEditSource()) + { + ESelection aSelection; + ::GetSelection( aSelection, GetEditSource()->GetTextForwarder() ); + SetSelection( aSelection ); + } +} + +void SAL_CALL SvxUnoTextBase::insertControlCharacter( const uno::Reference< text::XTextRange >& xRange, sal_Int16 nControlCharacter, sal_Bool bAbsorb ) +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = GetEditSource() ? GetEditSource()->GetTextForwarder() : nullptr; + + if( !pForwarder ) + return; + + ESelection aSelection; + ::GetSelection( aSelection, pForwarder ); + SetSelection( aSelection ); + + switch( nControlCharacter ) + { + case text::ControlCharacter::PARAGRAPH_BREAK: + { + insertString( xRange, "\x0D", bAbsorb ); + + return; + } + case text::ControlCharacter::LINE_BREAK: + { + SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRange>( xRange ); + if(pRange) + { + ESelection aRange = pRange->GetSelection(); + + if( bAbsorb ) + { + pForwarder->QuickInsertText( "", aRange ); + + aRange.nEndPos = aRange.nStartPos; + aRange.nEndPara = aRange.nStartPara; + } + else + { + aRange.nStartPara = aRange.nEndPara; + aRange.nStartPos = aRange.nEndPos; + } + + pForwarder->QuickInsertLineBreak( aRange ); + GetEditSource()->UpdateData(); + + aRange.nEndPos += 1; + if( !bAbsorb ) + aRange.nStartPos += 1; + + pRange->SetSelection( aRange ); + } + return; + } + case text::ControlCharacter::APPEND_PARAGRAPH: + { + SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRange>( xRange ); + if(pRange) + { + ESelection aRange = pRange->GetSelection(); +// ESelection aOldSelection = aRange; + + aRange.nStartPos = pForwarder->GetTextLen( aRange.nStartPara ); + + aRange.nEndPara = aRange.nStartPara; + aRange.nEndPos = aRange.nStartPos; + + pRange->SetSelection( aRange ); + static constexpr OUStringLiteral CR = u"\x0D"; + pRange->setString( CR ); + + aRange.nStartPos = 0; + aRange.nStartPara += 1; + aRange.nEndPos = 0; + aRange.nEndPara += 1; + + pRange->SetSelection( aRange ); + + return; + } + [[fallthrough]]; + } + default: + throw lang::IllegalArgumentException(); + } +} + +// XText +void SAL_CALL SvxUnoTextBase::insertTextContent( const uno::Reference< text::XTextRange >& xRange, const uno::Reference< text::XTextContent >& xContent, sal_Bool bAbsorb ) +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = GetEditSource() ? GetEditSource()->GetTextForwarder() : nullptr; + if (!pForwarder) + return; + + uno::Reference<beans::XPropertySet> xPropSet(xRange, uno::UNO_QUERY); + if (!xPropSet.is()) + throw lang::IllegalArgumentException(); + + uno::Any aAny = xPropSet->getPropertyValue(UNO_TR_PROP_SELECTION); + text::TextRangeSelection aSel = aAny.get<text::TextRangeSelection>(); + if (!bAbsorb) + aSel.Start = aSel.End; + + std::unique_ptr<SvxFieldData> pFieldData(SvxFieldData::Create(xContent)); + if (!pFieldData) + throw lang::IllegalArgumentException(); + + SvxFieldItem aField( *pFieldData, EE_FEATURE_FIELD ); + pForwarder->QuickInsertField(aField, toESelection(aSel)); + GetEditSource()->UpdateData(); + + uno::Reference<beans::XPropertySet> xPropSetContent(xContent, uno::UNO_QUERY); + if (!xPropSetContent.is()) + throw lang::IllegalArgumentException(); + + xPropSetContent->setPropertyValue(UNO_TC_PROP_ANCHOR, uno::Any(xRange)); + + aSel.End.PositionInParagraph += 1; + aSel.Start.PositionInParagraph = aSel.End.PositionInParagraph; + xPropSet->setPropertyValue(UNO_TR_PROP_SELECTION, uno::Any(aSel)); +} + +void SAL_CALL SvxUnoTextBase::removeTextContent( const uno::Reference< text::XTextContent >& ) +{ +} + +// XTextRange + +uno::Reference< text::XText > SAL_CALL SvxUnoTextBase::getText() +{ + SolarMutexGuard aGuard; + + if (GetEditSource()) + { + ESelection aSelection; + ::GetSelection( aSelection, GetEditSource()->GetTextForwarder() ); + SetSelection( aSelection ); + } + + return static_cast<text::XText*>(this); +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::getStart() +{ + return SvxUnoTextRangeBase::getStart(); +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::getEnd() +{ + return SvxUnoTextRangeBase::getEnd(); +} + +OUString SAL_CALL SvxUnoTextBase::getString() +{ + return SvxUnoTextRangeBase::getString(); +} + +void SAL_CALL SvxUnoTextBase::setString( const OUString& aString ) +{ + SvxUnoTextRangeBase::setString(aString); +} + + +// XEnumerationAccess +uno::Reference< container::XEnumeration > SAL_CALL SvxUnoTextBase::createEnumeration() +{ + SolarMutexGuard aGuard; + + if (!GetEditSource()) + return uno::Reference< container::XEnumeration >(); + + if( maSelection == ESelection(0,0,0,0) || maSelection == ESelection(EE_PARA_MAX_COUNT,0,0,0) ) + { + ESelection aSelection; + ::GetSelection( aSelection, GetEditSource()->GetTextForwarder() ); + return new SvxUnoTextContentEnumeration(*this, aSelection); + } + else + { + return new SvxUnoTextContentEnumeration(*this, maSelection); + } +} + +// XElementAccess ( container::XEnumerationAccess ) +uno::Type SAL_CALL SvxUnoTextBase::getElementType( ) +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SvxUnoTextBase::hasElements( ) +{ + SolarMutexGuard aGuard; + + if(GetEditSource()) + { + SvxTextForwarder* pForwarder = GetEditSource()->GetTextForwarder(); + if(pForwarder) + return pForwarder->GetParagraphCount() != 0; + } + + return false; +} + +// text::XTextRangeMover +void SAL_CALL SvxUnoTextBase::moveTextRange( const uno::Reference< text::XTextRange >&, sal_Int16 ) +{ +} + +/// @throws lang::IllegalArgumentException +/// @throws beans::UnknownPropertyException +/// @throws uno::RuntimeException +static void SvxPropertyValuesToItemSet( + SfxItemSet &rItemSet, + const uno::Sequence< beans::PropertyValue >& rPropertyValues, + const SfxItemPropertySet *pPropSet, + SvxTextForwarder *pForwarder, + sal_Int32 nPara) +{ + for (const beans::PropertyValue& rProp : rPropertyValues) + { + const SfxItemPropertyMapEntry *pEntry = pPropSet->getPropertyMap().getByName( rProp.Name ); + if (!pEntry) + throw beans::UnknownPropertyException( "Unknown property: " + rProp.Name ); + // Note: there is no need to take special care of the properties + // TextField (EE_FEATURE_FIELD) and + // TextPortionType (WID_PORTIONTYPE) + // since they are read-only and thus are already taken care of below. + + if (pEntry->nFlags & beans::PropertyAttribute::READONLY) + // should be PropertyVetoException which is not yet defined for the new import API's functions + throw uno::RuntimeException("Property is read-only: " + rProp.Name ); + //throw PropertyVetoException ("Property is read-only: " + rProp.Name ); + + if (pEntry->nWID == WID_FONTDESC) + { + awt::FontDescriptor aDesc; + if (rProp.Value >>= aDesc) + SvxUnoFontDescriptor::FillItemSet( aDesc, rItemSet ); + } + else if (pEntry->nWID == WID_NUMBERINGSTARTVALUE ) + { + if( pForwarder ) + { + sal_Int16 nStartValue = -1; + if( !(rProp.Value >>= nStartValue) ) + throw lang::IllegalArgumentException(); + + pForwarder->SetNumberingStartValue( nPara, nStartValue ); + } + } + else if (pEntry->nWID == WID_PARAISNUMBERINGRESTART ) + { + if( pForwarder ) + { + bool bParaIsNumberingRestart = false; + if( !(rProp.Value >>= bParaIsNumberingRestart) ) + throw lang::IllegalArgumentException(); + + pForwarder->SetParaIsNumberingRestart( nPara, bParaIsNumberingRestart ); + } + } + else + pPropSet->setPropertyValue( rProp.Name, rProp.Value, rItemSet ); + } +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::finishParagraphInsert( + const uno::Sequence< beans::PropertyValue >& /*rCharAndParaProps*/, + const uno::Reference< text::XTextRange >& /*rTextRange*/ ) +{ + uno::Reference< text::XTextRange > xRet; + return xRet; +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::finishParagraph( + const uno::Sequence< beans::PropertyValue >& rCharAndParaProps ) +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XTextRange > xRet; + SvxEditSource *pEditSource = GetEditSource(); + SvxTextForwarder *pTextForwarder = pEditSource ? pEditSource->GetTextForwarder() : nullptr; + if (pTextForwarder) + { + sal_Int32 nParaCount = pTextForwarder->GetParagraphCount(); + DBG_ASSERT( nParaCount > 0, "paragraph count is 0 or negative" ); + pTextForwarder->AppendParagraph(); + + // set properties for the previously last paragraph + sal_Int32 nPara = nParaCount - 1; + ESelection aSel( nPara, 0, nPara, 0 ); + SfxItemSet aItemSet( *pTextForwarder->GetEmptyItemSetPtr() ); + SvxPropertyValuesToItemSet( aItemSet, rCharAndParaProps, + ImplGetSvxUnoOutlinerTextCursorSfxPropertySet(), pTextForwarder, nPara ); + pTextForwarder->QuickSetAttribs( aItemSet, aSel ); + pEditSource->UpdateData(); + rtl::Reference<SvxUnoTextRange> pRange = new SvxUnoTextRange( *this ); + xRet = pRange; + pRange->SetSelection( aSel ); + } + return xRet; +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::insertTextPortion( + const OUString& rText, + const uno::Sequence< beans::PropertyValue >& rCharAndParaProps, + const uno::Reference< text::XTextRange>& rTextRange ) +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XTextRange > xRet; + + if (!rTextRange.is()) + return xRet; + + SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRange>(rTextRange); + if (!pRange) + return xRet; + + SvxEditSource *pEditSource = GetEditSource(); + SvxTextForwarder *pTextForwarder = pEditSource ? pEditSource->GetTextForwarder() : nullptr; + + if (pTextForwarder) + { + pRange->setString(rText); + + ESelection aSelection(pRange->GetSelection()); + + pTextForwarder->RemoveAttribs(aSelection); + pEditSource->UpdateData(); + + SfxItemSet aItemSet( *pTextForwarder->GetEmptyItemSetPtr() ); + SvxPropertyValuesToItemSet( aItemSet, rCharAndParaProps, + ImplGetSvxTextPortionSfxPropertySet(), pTextForwarder, aSelection.nStartPara ); + pTextForwarder->QuickSetAttribs( aItemSet, aSelection); + rtl::Reference<SvxUnoTextRange> pNewRange = new SvxUnoTextRange( *this ); + xRet = pNewRange; + pNewRange->SetSelection(aSelection); + for( const beans::PropertyValue& rProp : rCharAndParaProps ) + pNewRange->setPropertyValue( rProp.Name, rProp.Value ); + } + return xRet; +} + +// css::text::XTextPortionAppend (new import API) +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextBase::appendTextPortion( + const OUString& rText, + const uno::Sequence< beans::PropertyValue >& rCharAndParaProps ) +{ + SolarMutexGuard aGuard; + + SvxEditSource *pEditSource = GetEditSource(); + SvxTextForwarder *pTextForwarder = pEditSource ? pEditSource->GetTextForwarder() : nullptr; + uno::Reference< text::XTextRange > xRet; + if (pTextForwarder) + { + sal_Int32 nParaCount = pTextForwarder->GetParagraphCount(); + DBG_ASSERT( nParaCount > 0, "paragraph count is 0 or negative" ); + sal_Int32 nPara = nParaCount - 1; + SfxItemSet aSet( pTextForwarder->GetParaAttribs( nPara ) ); + sal_Int32 nStart = pTextForwarder->AppendTextPortion( nPara, rText, aSet ); + pEditSource->UpdateData(); + sal_Int32 nEnd = pTextForwarder->GetTextLen( nPara ); + + // set properties for the new text portion + ESelection aSel( nPara, nStart, nPara, nEnd ); + pTextForwarder->RemoveAttribs( aSel ); + pEditSource->UpdateData(); + + SfxItemSet aItemSet( *pTextForwarder->GetEmptyItemSetPtr() ); + SvxPropertyValuesToItemSet( aItemSet, rCharAndParaProps, + ImplGetSvxTextPortionSfxPropertySet(), pTextForwarder, nPara ); + pTextForwarder->QuickSetAttribs( aItemSet, aSel ); + rtl::Reference<SvxUnoTextRange> pRange = new SvxUnoTextRange( *this ); + xRet = pRange; + pRange->SetSelection( aSel ); + for( const beans::PropertyValue& rProp : rCharAndParaProps ) + pRange->setPropertyValue( rProp.Name, rProp.Value ); + } + return xRet; +} + +void SvxUnoTextBase::copyText( + const uno::Reference< text::XTextCopy >& xSource ) +{ + SolarMutexGuard aGuard; + uno::Reference< lang::XUnoTunnel > xUT( xSource, uno::UNO_QUERY ); + SvxEditSource *pEditSource = GetEditSource(); + SvxTextForwarder *pTextForwarder = pEditSource ? pEditSource->GetTextForwarder() : nullptr; + if( !pTextForwarder ) + return; + if (auto pSource = comphelper::getFromUnoTunnel<SvxUnoTextBase>(xUT)) + { + SvxEditSource *pSourceEditSource = pSource->GetEditSource(); + SvxTextForwarder *pSourceTextForwarder = pSourceEditSource ? pSourceEditSource->GetTextForwarder() : nullptr; + if( pSourceTextForwarder ) + { + pTextForwarder->CopyText( *pSourceTextForwarder ); + pEditSource->UpdateData(); + } + } + else + { + uno::Reference< text::XText > xSourceText( xSource, uno::UNO_QUERY ); + if( xSourceText.is() ) + { + setString( xSourceText->getString() ); + } + } +} + +// lang::XServiceInfo +OUString SAL_CALL SvxUnoTextBase::getImplementationName() +{ + return "SvxUnoTextBase"; +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextBase::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_Static(); +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextBase::getSupportedServiceNames_Static( ) +{ + return comphelper::concatSequences( + SvxUnoTextRangeBase::getSupportedServiceNames_Static(), + std::initializer_list<std::u16string_view>{ u"com.sun.star.text.Text" }); +} + +const uno::Sequence< sal_Int8 > & SvxUnoTextBase::getUnoTunnelId() noexcept +{ + static const comphelper::UnoIdInit theSvxUnoTextBaseUnoTunnelId; + return theSvxUnoTextBaseUnoTunnelId.getSeq(); +} + +sal_Int64 SAL_CALL SvxUnoTextBase::getSomething( const uno::Sequence< sal_Int8 >& rId ) +{ + return comphelper::getSomethingImpl( + rId, this, comphelper::FallbackToGetSomethingOf<SvxUnoTextRangeBase>{}); +} + +SvxUnoText::SvxUnoText( const SvxItemPropertySet* _pSet ) noexcept +: SvxUnoTextBase( _pSet ) +{ +} + +SvxUnoText::SvxUnoText( const SvxEditSource* pSource, const SvxItemPropertySet* _pSet, uno::Reference < text::XText > const & xParent ) noexcept +: SvxUnoTextBase( pSource, _pSet, xParent ) +{ +} + +SvxUnoText::SvxUnoText( const SvxUnoText& rText ) noexcept +: SvxUnoTextBase( rText ) +, cppu::OWeakAggObject() +{ +} + +SvxUnoText::~SvxUnoText() noexcept +{ +} + +// uno::XInterface +uno::Any SAL_CALL SvxUnoText::queryAggregation( const uno::Type & rType ) +{ + uno::Any aAny( SvxUnoTextBase::queryAggregation( rType ) ); + if( !aAny.hasValue() ) + aAny = OWeakAggObject::queryAggregation( rType ); + + return aAny; +} + +uno::Any SAL_CALL SvxUnoText::queryInterface( const uno::Type & rType ) +{ + return OWeakAggObject::queryInterface( rType ); +} + +void SAL_CALL SvxUnoText::acquire() noexcept +{ + OWeakAggObject::acquire(); +} + +void SAL_CALL SvxUnoText::release() noexcept +{ + OWeakAggObject::release(); +} + +// lang::XTypeProvider +uno::Sequence< uno::Type > SAL_CALL SvxUnoText::getTypes( ) +{ + return SvxUnoTextBase::getTypes(); +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoText::getImplementationId( ) +{ + return css::uno::Sequence<sal_Int8>(); +} + +const uno::Sequence< sal_Int8 > & SvxUnoText::getUnoTunnelId() noexcept +{ + static const comphelper::UnoIdInit theSvxUnoTextUnoTunnelId; + return theSvxUnoTextUnoTunnelId.getSeq(); +} + +sal_Int64 SAL_CALL SvxUnoText::getSomething( const uno::Sequence< sal_Int8 >& rId ) +{ + return comphelper::getSomethingImpl(rId, this, + comphelper::FallbackToGetSomethingOf<SvxUnoTextBase>{}); +} + + +SvxDummyTextSource::~SvxDummyTextSource() +{ +}; + +std::unique_ptr<SvxEditSource> SvxDummyTextSource::Clone() const +{ + return std::unique_ptr<SvxEditSource>(new SvxDummyTextSource); +} + +SvxTextForwarder* SvxDummyTextSource::GetTextForwarder() +{ + return this; +} + +void SvxDummyTextSource::UpdateData() +{ +} + +sal_Int32 SvxDummyTextSource::GetParagraphCount() const +{ + return 0; +} + +sal_Int32 SvxDummyTextSource::GetTextLen( sal_Int32 ) const +{ + return 0; +} + +OUString SvxDummyTextSource::GetText( const ESelection& ) const +{ + return OUString(); +} + +SfxItemSet SvxDummyTextSource::GetAttribs( const ESelection&, EditEngineAttribs ) const +{ + // Very dangerous: The former implementation used a SfxItemPool created on the + // fly which of course was deleted again ASAP. Thus, the returned SfxItemSet was using + // a deleted Pool by design. + return SfxItemSet(EditEngine::GetGlobalItemPool()); +} + +SfxItemSet SvxDummyTextSource::GetParaAttribs( sal_Int32 ) const +{ + return GetAttribs(ESelection()); +} + +void SvxDummyTextSource::SetParaAttribs( sal_Int32, const SfxItemSet& ) +{ +} + +void SvxDummyTextSource::RemoveAttribs( const ESelection& ) +{ +} + +void SvxDummyTextSource::GetPortions( sal_Int32, std::vector<sal_Int32>& ) const +{ +} + +OUString SvxDummyTextSource::GetStyleSheet(sal_Int32) const +{ + return OUString(); +} + +void SvxDummyTextSource::SetStyleSheet(sal_Int32, const OUString&) +{ +} + +SfxItemState SvxDummyTextSource::GetItemState( const ESelection&, sal_uInt16 ) const +{ + return SfxItemState::UNKNOWN; +} + +SfxItemState SvxDummyTextSource::GetItemState( sal_Int32, sal_uInt16 ) const +{ + return SfxItemState::UNKNOWN; +} + +SfxItemPool* SvxDummyTextSource::GetPool() const +{ + return nullptr; +} + +void SvxDummyTextSource::QuickInsertText( const OUString&, const ESelection& ) +{ +} + +void SvxDummyTextSource::QuickInsertField( const SvxFieldItem&, const ESelection& ) +{ +} + +void SvxDummyTextSource::QuickSetAttribs( const SfxItemSet&, const ESelection& ) +{ +} + +void SvxDummyTextSource::QuickInsertLineBreak( const ESelection& ) +{ +}; + +OUString SvxDummyTextSource::CalcFieldValue( const SvxFieldItem&, sal_Int32, sal_Int32, std::optional<Color>&, std::optional<Color>&, std::optional<FontLineStyle>& ) +{ + return OUString(); +} + +void SvxDummyTextSource::FieldClicked( const SvxFieldItem& ) +{ +} + +bool SvxDummyTextSource::IsValid() const +{ + return false; +} + +LanguageType SvxDummyTextSource::GetLanguage( sal_Int32, sal_Int32 ) const +{ + return LANGUAGE_DONTKNOW; +} + +sal_Int32 SvxDummyTextSource::GetFieldCount( sal_Int32 ) const +{ + return 0; +} + +EFieldInfo SvxDummyTextSource::GetFieldInfo( sal_Int32, sal_uInt16 ) const +{ + return EFieldInfo(); +} + +EBulletInfo SvxDummyTextSource::GetBulletInfo( sal_Int32 ) const +{ + return EBulletInfo(); +} + +tools::Rectangle SvxDummyTextSource::GetCharBounds( sal_Int32, sal_Int32 ) const +{ + return tools::Rectangle(); +} + +tools::Rectangle SvxDummyTextSource::GetParaBounds( sal_Int32 ) const +{ + return tools::Rectangle(); +} + +MapMode SvxDummyTextSource::GetMapMode() const +{ + return MapMode(); +} + +OutputDevice* SvxDummyTextSource::GetRefDevice() const +{ + return nullptr; +} + +bool SvxDummyTextSource::GetIndexAtPoint( const Point&, sal_Int32&, sal_Int32& ) const +{ + return false; +} + +bool SvxDummyTextSource::GetWordIndices( sal_Int32, sal_Int32, sal_Int32&, sal_Int32& ) const +{ + return false; +} + +bool SvxDummyTextSource::GetAttributeRun( sal_Int32&, sal_Int32&, sal_Int32, sal_Int32, bool ) const +{ + return false; +} + +sal_Int32 SvxDummyTextSource::GetLineCount( sal_Int32 ) const +{ + return 0; +} + +sal_Int32 SvxDummyTextSource::GetLineLen( sal_Int32, sal_Int32 ) const +{ + return 0; +} + +void SvxDummyTextSource::GetLineBoundaries( /*out*/sal_Int32 &rStart, /*out*/sal_Int32 &rEnd, sal_Int32 /*nParagraph*/, sal_Int32 /*nLine*/ ) const +{ + rStart = rEnd = 0; +} + +sal_Int32 SvxDummyTextSource::GetLineNumberAtIndex( sal_Int32 /*nPara*/, sal_Int32 /*nIndex*/ ) const +{ + return 0; +} + +bool SvxDummyTextSource::QuickFormatDoc( bool ) +{ + return false; +} + +sal_Int16 SvxDummyTextSource::GetDepth( sal_Int32 ) const +{ + return -1; +} + +bool SvxDummyTextSource::SetDepth( sal_Int32, sal_Int16 nNewDepth ) +{ + return nNewDepth == 0; +} + +bool SvxDummyTextSource::Delete( const ESelection& ) +{ + return false; +} + +bool SvxDummyTextSource::InsertText( const OUString&, const ESelection& ) +{ + return false; +} + +const SfxItemSet * SvxDummyTextSource::GetEmptyItemSetPtr() +{ + return nullptr; +} + +void SvxDummyTextSource::AppendParagraph() +{ +} + +sal_Int32 SvxDummyTextSource::AppendTextPortion( sal_Int32, const OUString &, const SfxItemSet & ) +{ + return 0; +} + +void SvxDummyTextSource::CopyText(const SvxTextForwarder& ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |