diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /editeng/source/uno | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'editeng/source/uno')
-rw-r--r-- | editeng/source/uno/UnoForbiddenCharsTable.cxx | 132 | ||||
-rw-r--r-- | editeng/source/uno/unoedhlp.cxx | 250 | ||||
-rw-r--r-- | editeng/source/uno/unoedprx.cxx | 1209 | ||||
-rw-r--r-- | editeng/source/uno/unoedsrc.cxx | 77 | ||||
-rw-r--r-- | editeng/source/uno/unofdesc.cxx | 229 | ||||
-rw-r--r-- | editeng/source/uno/unofield.cxx | 941 | ||||
-rw-r--r-- | editeng/source/uno/unofored.cxx | 520 | ||||
-rw-r--r-- | editeng/source/uno/unofored_internal.hxx | 28 | ||||
-rw-r--r-- | editeng/source/uno/unoforou.cxx | 582 | ||||
-rw-r--r-- | editeng/source/uno/unoipset.cxx | 333 | ||||
-rw-r--r-- | editeng/source/uno/unonrule.cxx | 544 | ||||
-rw-r--r-- | editeng/source/uno/unopracc.cxx | 92 | ||||
-rw-r--r-- | editeng/source/uno/unotext.cxx | 2561 | ||||
-rw-r--r-- | editeng/source/uno/unotext2.cxx | 629 | ||||
-rw-r--r-- | editeng/source/uno/unoviwou.cxx | 128 |
15 files changed, 8255 insertions, 0 deletions
diff --git a/editeng/source/uno/UnoForbiddenCharsTable.cxx b/editeng/source/uno/UnoForbiddenCharsTable.cxx new file mode 100644 index 0000000000..5e77a9252f --- /dev/null +++ b/editeng/source/uno/UnoForbiddenCharsTable.cxx @@ -0,0 +1,132 @@ +/* -*- 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 <sal/config.h> + +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <editeng/UnoForbiddenCharsTable.hxx> +#include <editeng/forbiddencharacterstable.hxx> +#include <i18nlangtag/languagetag.hxx> +#include <utility> +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::i18n; +using namespace ::cppu; + +SvxUnoForbiddenCharsTable::SvxUnoForbiddenCharsTable(std::shared_ptr<SvxForbiddenCharactersTable> xForbiddenChars) + : mxForbiddenChars(std::move(xForbiddenChars)) +{ +} + +SvxUnoForbiddenCharsTable::~SvxUnoForbiddenCharsTable() +{ +} + +void SvxUnoForbiddenCharsTable::onChange() +{ +} + +ForbiddenCharacters SvxUnoForbiddenCharsTable::getForbiddenCharacters( const lang::Locale& rLocale ) +{ + SolarMutexGuard aGuard; + + if (!mxForbiddenChars) + throw RuntimeException("No Forbidden Characters present"); + + const LanguageType eLang = LanguageTag::convertToLanguageType( rLocale ); + const ForbiddenCharacters* pForbidden = mxForbiddenChars->GetForbiddenCharacters( eLang, false ); + if(!pForbidden) + throw NoSuchElementException(); + + return *pForbidden; +} + +sal_Bool SvxUnoForbiddenCharsTable::hasForbiddenCharacters( const lang::Locale& rLocale ) +{ + SolarMutexGuard aGuard; + + if (!mxForbiddenChars) + return false; + + const LanguageType eLang = LanguageTag::convertToLanguageType( rLocale ); + const ForbiddenCharacters* pForbidden = mxForbiddenChars->GetForbiddenCharacters( eLang, false ); + + return nullptr != pForbidden; +} + +void SvxUnoForbiddenCharsTable::setForbiddenCharacters(const lang::Locale& rLocale, const ForbiddenCharacters& rForbiddenCharacters ) +{ + SolarMutexGuard aGuard; + + if (!mxForbiddenChars) + throw RuntimeException("No Forbidden Characters present"); + + const LanguageType eLang = LanguageTag::convertToLanguageType( rLocale ); + mxForbiddenChars->SetForbiddenCharacters( eLang, rForbiddenCharacters ); + + onChange(); +} + +void SvxUnoForbiddenCharsTable::removeForbiddenCharacters( const lang::Locale& rLocale ) +{ + SolarMutexGuard aGuard; + + if (!mxForbiddenChars) + throw RuntimeException("No Forbidden Characters present"); + + const LanguageType eLang = LanguageTag::convertToLanguageType( rLocale ); + mxForbiddenChars->ClearForbiddenCharacters( eLang ); + + onChange(); +} + +// XSupportedLocales +Sequence< lang::Locale > SAL_CALL SvxUnoForbiddenCharsTable::getLocales() +{ + SolarMutexGuard aGuard; + + const sal_Int32 nCount = mxForbiddenChars ? mxForbiddenChars->GetMap().size() : 0; + + Sequence< lang::Locale > aLocales( nCount ); + if( nCount ) + { + lang::Locale* pLocales = aLocales.getArray(); + + for (auto const& elem : mxForbiddenChars->GetMap()) + { + const LanguageType nLanguage = elem.first; + *pLocales++ = LanguageTag( nLanguage ).getLocale(); + } + } + + return aLocales; +} + +sal_Bool SAL_CALL SvxUnoForbiddenCharsTable::hasLocale( const lang::Locale& aLocale ) +{ + SolarMutexGuard aGuard; + + return hasForbiddenCharacters( aLocale ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unoedhlp.cxx b/editeng/source/uno/unoedhlp.cxx new file mode 100644 index 0000000000..2a1b1e2bd5 --- /dev/null +++ b/editeng/source/uno/unoedhlp.cxx @@ -0,0 +1,250 @@ +/* -*- 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 <memory> +#include <editeng/unoedhlp.hxx> +#include <editeng/editdata.hxx> +#include <editeng/editeng.hxx> +#include <svl/itemset.hxx> + +#include <osl/diagnose.h> + + +SvxEditSourceHint::SvxEditSourceHint( SfxHintId _nId ) : + TextHint( _nId ), + mnStart( 0 ), + mnEnd( 0 ) +{ +} + +SvxEditSourceHint::SvxEditSourceHint( SfxHintId _nId, sal_Int32 nValue, sal_Int32 nStart, sal_Int32 nEnd ) : + TextHint( _nId, nValue ), + mnStart( nStart), + mnEnd( nEnd ) +{ +} + + +std::unique_ptr<SfxHint> SvxEditSourceHelper::EENotification2Hint( EENotify const * aNotify ) +{ + if( aNotify ) + { + switch( aNotify->eNotificationType ) + { + case EE_NOTIFY_TEXTMODIFIED: + return std::unique_ptr<SfxHint>( new TextHint( SfxHintId::TextModified, aNotify->nParagraph ) ); + + case EE_NOTIFY_PARAGRAPHINSERTED: + return std::unique_ptr<SfxHint>( new TextHint( SfxHintId::TextParaInserted, aNotify->nParagraph ) ); + + case EE_NOTIFY_PARAGRAPHREMOVED: + return std::unique_ptr<SfxHint>( new TextHint( SfxHintId::TextParaRemoved, aNotify->nParagraph ) ); + + case EE_NOTIFY_PARAGRAPHSMOVED: + return std::unique_ptr<SfxHint>( new SvxEditSourceHint( SfxHintId::EditSourceParasMoved, aNotify->nParagraph, aNotify->nParam1, aNotify->nParam2 ) ); + + case EE_NOTIFY_TextHeightChanged: + return std::unique_ptr<SfxHint>( new TextHint( SfxHintId::TextHeightChanged, aNotify->nParagraph ) ); + + case EE_NOTIFY_TEXTVIEWSCROLLED: + return std::unique_ptr<SfxHint>( new TextHint( SfxHintId::TextViewScrolled ) ); + + case EE_NOTIFY_TEXTVIEWSELECTIONCHANGED: + return std::unique_ptr<SfxHint>( new SvxEditSourceHint( SfxHintId::EditSourceSelectionChanged ) ); + + case EE_NOTIFY_PROCESSNOTIFICATIONS: + return std::unique_ptr<SfxHint>( new TextHint( SfxHintId::TextProcessNotifications )); + + case EE_NOTIFY_TEXTVIEWSELECTIONCHANGED_ENDD_PARA: + return std::unique_ptr<SfxHint>( new SvxEditSourceHintEndPara ); + default: + OSL_FAIL( "SvxEditSourceHelper::EENotification2Hint unknown notification" ); + break; + } + } + + return std::make_unique<SfxHint>( ); +} + +void SvxEditSourceHelper::GetAttributeRun( sal_Int32& nStartIndex, sal_Int32& nEndIndex, const EditEngine& rEE, sal_Int32 nPara, sal_Int32 nIndex, bool bInCell ) +{ + // IA2 CWS introduced bInCell, but also did many other changes here. + // Need to verify implementation with AT (IA2 and ATK) + // Old implementation at the end of the method for reference... + + //added dummy attributes for the default text + std::vector<EECharAttrib> aCharAttribs, aTempCharAttribs; + rEE.GetCharAttribs( nPara, aTempCharAttribs ); + + if (!aTempCharAttribs.empty()) + { + sal_Int32 nIndex2 = 0; + sal_Int32 nParaLen = rEE.GetTextLen(nPara); + for (size_t nAttr = 0; nAttr < aTempCharAttribs.size(); ++nAttr) + { + if (nIndex2 < aTempCharAttribs[nAttr].nStart) + { + EECharAttrib aEEAttr(nIndex2, aTempCharAttribs[nAttr].nStart); + aCharAttribs.insert(aCharAttribs.begin() + nAttr, aEEAttr); + } + nIndex2 = aTempCharAttribs[nAttr].nEnd; + aCharAttribs.push_back(aTempCharAttribs[nAttr]); + } + if ( nIndex2 != nParaLen ) + { + EECharAttrib aEEAttr(nIndex2, nParaLen); + aCharAttribs.push_back(aEEAttr); + } + } + // find closest index in front of nIndex + sal_Int32 nCurrIndex; + sal_Int32 nClosestStartIndex_s = 0, nClosestStartIndex_e = 0; + for (auto const& charAttrib : aCharAttribs) + { + nCurrIndex = charAttrib.nStart; + + if( nCurrIndex > nClosestStartIndex_s && + nCurrIndex <= nIndex) + { + nClosestStartIndex_s = nCurrIndex; + } + nCurrIndex = charAttrib.nEnd; + if ( nCurrIndex > nClosestStartIndex_e && + nCurrIndex < nIndex ) + { + nClosestStartIndex_e = nCurrIndex; + } + } + sal_Int32 nClosestStartIndex = std::max(nClosestStartIndex_s, nClosestStartIndex_e); + + // find closest index behind of nIndex + sal_Int32 nClosestEndIndex_s, nClosestEndIndex_e; + nClosestEndIndex_s = nClosestEndIndex_e = rEE.GetTextLen(nPara); + for (auto const& charAttrib : aCharAttribs) + { + nCurrIndex = charAttrib.nEnd; + + if( nCurrIndex > nIndex && + nCurrIndex < nClosestEndIndex_e ) + { + nClosestEndIndex_e = nCurrIndex; + } + nCurrIndex = charAttrib.nStart; + if ( nCurrIndex > nIndex && + nCurrIndex < nClosestEndIndex_s) + { + nClosestEndIndex_s = nCurrIndex; + } + } + sal_Int32 nClosestEndIndex = std::min(nClosestEndIndex_s, nClosestEndIndex_e); + + nStartIndex = nClosestStartIndex; + nEndIndex = nClosestEndIndex; + + if ( !bInCell ) + return; + + EPosition aStartPos( nPara, nStartIndex ), aEndPos( nPara, nEndIndex ); + sal_Int32 nParaCount = rEE.GetParagraphCount(); + sal_Int32 nCrrntParaLen = rEE.GetTextLen(nPara); + //need to find closest index in front of nIndex in the previous paragraphs + if ( aStartPos.nIndex == 0 ) + { + SfxItemSet aCrrntSet = rEE.GetAttribs( nPara, 0, 1, GetAttribsFlags::CHARATTRIBS ); + for ( sal_Int32 nParaIdx = nPara-1; nParaIdx >= 0; nParaIdx-- ) + { + sal_uInt32 nLen = rEE.GetTextLen(nParaIdx); + if ( nLen ) + { + sal_Int32 nStartIdx, nEndIdx; + GetAttributeRun( nStartIdx, nEndIdx, rEE, nParaIdx, nLen ); + SfxItemSet aSet = rEE.GetAttribs( nParaIdx, nLen-1, nLen, GetAttribsFlags::CHARATTRIBS ); + if ( aSet == aCrrntSet ) + { + aStartPos.nPara = nParaIdx; + aStartPos.nIndex = nStartIdx; + if ( aStartPos.nIndex != 0 ) + { + break; + } + } + } + } + } + //need find closest index behind nIndex in the following paragraphs + if ( aEndPos.nIndex == nCrrntParaLen ) + { + SfxItemSet aCrrntSet = rEE.GetAttribs( nPara, nCrrntParaLen-1, nCrrntParaLen, GetAttribsFlags::CHARATTRIBS ); + for ( sal_Int32 nParaIdx = nPara+1; nParaIdx < nParaCount; nParaIdx++ ) + { + sal_Int32 nLen = rEE.GetTextLen( nParaIdx ); + if ( nLen ) + { + sal_Int32 nStartIdx, nEndIdx; + GetAttributeRun( nStartIdx, nEndIdx, rEE, nParaIdx, 0 ); + SfxItemSet aSet = rEE.GetAttribs( nParaIdx, 0, 1, GetAttribsFlags::CHARATTRIBS ); + if ( aSet == aCrrntSet ) + { + aEndPos.nPara = nParaIdx; + aEndPos.nIndex = nEndIdx; + if ( aEndPos.nIndex != nLen ) + { + break; + } + } + } + } + } + nStartIndex = 0; + if ( aStartPos.nPara > 0 ) + { + for ( sal_Int32 i = 0; i < aStartPos.nPara; i++ ) + { + nStartIndex += rEE.GetTextLen(i)+1; + } + } + nStartIndex += aStartPos.nIndex; + nEndIndex = 0; + if ( aEndPos.nPara > 0 ) + { + for ( sal_Int32 i = 0; i < aEndPos.nPara; i++ ) + { + nEndIndex += rEE.GetTextLen(i)+1; + } + } + nEndIndex += aEndPos.nIndex; +} + +Point SvxEditSourceHelper::EEToUserSpace( const Point& rPoint, const Size& rEESize, bool bIsVertical ) +{ + return bIsVertical ? Point( -rPoint.Y() + rEESize.Height(), rPoint.X() ) : rPoint; +} + +Point SvxEditSourceHelper::UserSpaceToEE( const Point& rPoint, const Size& rEESize, bool bIsVertical ) +{ + return bIsVertical ? Point( rPoint.Y(), -rPoint.X() + rEESize.Height() ) : rPoint; +} + +tools::Rectangle SvxEditSourceHelper::EEToUserSpace( const tools::Rectangle& rRect, const Size& rEESize, bool bIsVertical ) +{ + return bIsVertical ? tools::Rectangle( EEToUserSpace(rRect.BottomLeft(), rEESize, bIsVertical), + EEToUserSpace(rRect.TopRight(), rEESize, bIsVertical) ) : rRect; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unoedprx.cxx b/editeng/source/uno/unoedprx.cxx new file mode 100644 index 0000000000..20d5df281b --- /dev/null +++ b/editeng/source/uno/unoedprx.cxx @@ -0,0 +1,1209 @@ +/* -*- 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 . + */ + + +// Global header + + +#include <utility> +#include <memory> +#include <vector> +#include <algorithm> +#include <osl/diagnose.h> +#include <svl/itemset.hxx> +#include <tools/debug.hxx> + + +// Project-local header + + +#include <editeng/unoedprx.hxx> +#include <editeng/editdata.hxx> +#include <editeng/editeng.hxx> +#include <AccessibleStringWrap.hxx> +#include <editeng/outliner.hxx> + +using namespace ::com::sun::star; + +namespace { + +class SvxAccessibleTextIndex +{ +public: + SvxAccessibleTextIndex() : + mnPara(0), + mnIndex(0), + mnEEIndex(0), + mnFieldOffset(0), + mnFieldLen(0), + mnBulletOffset(0), + mnBulletLen(0), + mbInField(false), + mbInBullet(false) {}; + + // Get/Set current paragraph + void SetParagraph( sal_Int32 nPara ) + { + mnPara = nPara; + } + sal_Int32 GetParagraph() const { return mnPara; } + + /** Set the index in the UAA semantic + + @param nIndex + The index from the UA API (fields and bullets are expanded) + + @param rTF + The text forwarder to use in the calculations + */ + void SetIndex( sal_Int32 nIndex, const SvxTextForwarder& rTF ); + void SetIndex( sal_Int32 nPara, sal_Int32 nIndex, const SvxTextForwarder& rTF ) { SetParagraph(nPara); SetIndex(nIndex, rTF); } + sal_Int32 GetIndex() const { return mnIndex; } + + /** Set the index in the edit engine semantic + + Update the object state to reflect the given index position in + EditEngine/Outliner index values + + @param nEEIndex + The index from the edit engine (fields span exactly one index increment) + + @param rTF + The text forwarder to use in the calculations + */ + void SetEEIndex( sal_Int32 nEEIndex, const SvxTextForwarder& rTF ); + void SetEEIndex( sal_Int32 nPara, sal_Int32 nEEIndex, const SvxTextForwarder& rTF ) { SetParagraph(nPara); SetEEIndex(nEEIndex, rTF); } + sal_Int32 GetEEIndex() const; + + void SetFieldOffset( sal_Int32 nOffset, sal_Int32 nLen ) { mnFieldOffset = nOffset; mnFieldLen = nLen; } + sal_Int32 GetFieldOffset() const { return mnFieldOffset; } + sal_Int32 GetFieldLen() const { return mnFieldLen; } + void AreInField() { mbInField = true; } + bool InField() const { return mbInField; } + + void SetBulletOffset( sal_Int32 nOffset, sal_Int32 nLen ) { mnBulletOffset = nOffset; mnBulletLen = nLen; } + sal_Int32 GetBulletOffset() const { return mnBulletOffset; } + sal_Int32 GetBulletLen() const { return mnBulletLen; } + bool InBullet() const { return mbInBullet; } + + /// returns false if the given range is non-editable (e.g. contains bullets or _parts_ of fields) + bool IsEditableRange( const SvxAccessibleTextIndex& rEnd ) const; + +private: + sal_Int32 mnPara; + sal_Int32 mnIndex; + sal_Int32 mnEEIndex; + sal_Int32 mnFieldOffset; + sal_Int32 mnFieldLen; + sal_Int32 mnBulletOffset; + sal_Int32 mnBulletLen; + bool mbInField; + bool mbInBullet; +}; + +} + +static ESelection MakeEESelection( const SvxAccessibleTextIndex& rStart, const SvxAccessibleTextIndex& rEnd ) +{ + // deal with field special case: to really get a field contained + // within a selection, the start index must be before or on the + // field, the end index after it. + + // The SvxAccessibleTextIndex.GetEEIndex method gives the index on + // the field, as long the input index is on the field. Thus, + // correction necessary for the end index + + // Therefore, for _ranges_, if part of the field is touched, all + // of the field must be selected + if( rStart.GetParagraph() <= rEnd.GetParagraph() || + (rStart.GetParagraph() == rEnd.GetParagraph() && + rStart.GetEEIndex() <= rEnd.GetEEIndex()) ) + { + if( rEnd.InField() && rEnd.GetFieldOffset() ) + return ESelection( rStart.GetParagraph(), rStart.GetEEIndex(), + rEnd.GetParagraph(), rEnd.GetEEIndex()+1 ); + } + else if( rStart.GetParagraph() > rEnd.GetParagraph() || + (rStart.GetParagraph() == rEnd.GetParagraph() && + rStart.GetEEIndex() > rEnd.GetEEIndex()) ) + { + if( rStart.InField() && rStart.GetFieldOffset() ) + return ESelection( rStart.GetParagraph(), rStart.GetEEIndex()+1, + rEnd.GetParagraph(), rEnd.GetEEIndex() ); + } + + return ESelection( rStart.GetParagraph(), rStart.GetEEIndex(), + rEnd.GetParagraph(), rEnd.GetEEIndex() ); +} + +static ESelection MakeEESelection( const SvxAccessibleTextIndex& rIndex ) +{ + return ESelection( rIndex.GetParagraph(), rIndex.GetEEIndex(), + rIndex.GetParagraph(), rIndex.GetEEIndex() + 1 ); +} + +sal_Int32 SvxAccessibleTextIndex::GetEEIndex() const +{ + DBG_ASSERT(mnEEIndex >= 0, + "SvxAccessibleTextIndex::GetEEIndex: index value overflow"); + + return mnEEIndex; +} + +void SvxAccessibleTextIndex::SetEEIndex( sal_Int32 nEEIndex, const SvxTextForwarder& rTF ) +{ + // reset + mnFieldOffset = 0; + mbInField = false; + mnFieldLen = 0; + mnBulletOffset = 0; + mbInBullet = false; + mnBulletLen = 0; + + // set known values + mnEEIndex = nEEIndex; + + // calculate unknowns + sal_Int32 nCurrField, nFieldCount = rTF.GetFieldCount( GetParagraph() ); + + mnIndex = nEEIndex; + + EBulletInfo aBulletInfo = rTF.GetBulletInfo( GetParagraph() ); + + // any text bullets? + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ) + { + mnIndex += aBulletInfo.aText.getLength(); + } + + for( nCurrField=0; nCurrField < nFieldCount; ++nCurrField ) + { + EFieldInfo aFieldInfo( rTF.GetFieldInfo( GetParagraph(), nCurrField ) ); + + if( aFieldInfo.aPosition.nIndex > nEEIndex ) + break; + + if( aFieldInfo.aPosition.nIndex == nEEIndex ) + { + AreInField(); + break; + } + + mnIndex += std::max(aFieldInfo.aCurrentText.getLength()-1, sal_Int32(0)); + } +} + +void SvxAccessibleTextIndex::SetIndex( sal_Int32 nIndex, const SvxTextForwarder& rTF ) +{ + // reset + mnFieldOffset = 0; + mbInField = false; + mnFieldLen = 0; + mnBulletOffset = 0; + mbInBullet = false; + mnBulletLen = 0; + + // set known values + mnIndex = nIndex; + + // calculate unknowns + sal_Int32 nCurrField, nFieldCount = rTF.GetFieldCount( GetParagraph() ); + + DBG_ASSERT(nIndex >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + mnEEIndex = nIndex; + + EBulletInfo aBulletInfo = rTF.GetBulletInfo( GetParagraph() ); + + // any text bullets? + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ) + { + sal_Int32 nBulletLen = aBulletInfo.aText.getLength(); + + if( nIndex < nBulletLen ) + { + mbInBullet = true; + SetBulletOffset( nIndex, nBulletLen ); + mnEEIndex = 0; + return; + } + + mnEEIndex = mnEEIndex - nBulletLen; + } + + for( nCurrField=0; nCurrField < nFieldCount; ++nCurrField ) + { + EFieldInfo aFieldInfo( rTF.GetFieldInfo( GetParagraph(), nCurrField ) ); + + // we're before a field + if( aFieldInfo.aPosition.nIndex > mnEEIndex ) + break; + + mnEEIndex -= std::max(aFieldInfo.aCurrentText.getLength()-1, sal_Int32(0)); + + // we're within a field + if( aFieldInfo.aPosition.nIndex >= mnEEIndex ) + { + AreInField(); + SetFieldOffset( std::max(aFieldInfo.aCurrentText.getLength()-1, sal_Int32(0)) - (aFieldInfo.aPosition.nIndex - mnEEIndex), + aFieldInfo.aCurrentText.getLength() ); + mnEEIndex = aFieldInfo.aPosition.nIndex ; + break; + } + } +} + +bool SvxAccessibleTextIndex::IsEditableRange( const SvxAccessibleTextIndex& rEnd ) const +{ + if( GetIndex() > rEnd.GetIndex() ) + return rEnd.IsEditableRange( *this ); + + if( InBullet() || rEnd.InBullet() ) + return false; + + if( InField() && GetFieldOffset() ) + return false; // within field + + if( rEnd.InField() && rEnd.GetFieldOffset() >= rEnd.GetFieldLen() - 1 ) + return false; // within field + + return true; +} + + +SvxEditSourceAdapter::SvxEditSourceAdapter() : mbEditSourceValid( false ) +{ +} + +SvxEditSourceAdapter::~SvxEditSourceAdapter() +{ +} + +std::unique_ptr<SvxEditSource> SvxEditSourceAdapter::Clone() const +{ + if( mbEditSourceValid && mpAdaptee ) + { + std::unique_ptr< SvxEditSource > pClonedAdaptee( mpAdaptee->Clone() ); + + if (pClonedAdaptee) + { + std::unique_ptr<SvxEditSourceAdapter> pClone(new SvxEditSourceAdapter()); + pClone->SetEditSource( std::move(pClonedAdaptee) ); + return std::unique_ptr< SvxEditSource >(pClone.release()); + } + } + + return nullptr; +} + +SvxAccessibleTextAdapter* SvxEditSourceAdapter::GetTextForwarderAdapter() +{ + if( mbEditSourceValid && mpAdaptee ) + { + SvxTextForwarder* pTextForwarder = mpAdaptee->GetTextForwarder(); + + if( pTextForwarder ) + { + maTextAdapter.SetForwarder(*pTextForwarder); + + return &maTextAdapter; + } + } + + return nullptr; +} + +SvxTextForwarder* SvxEditSourceAdapter::GetTextForwarder() +{ + return GetTextForwarderAdapter(); +} + +SvxViewForwarder* SvxEditSourceAdapter::GetViewForwarder() +{ + if( mbEditSourceValid && mpAdaptee ) + return mpAdaptee->GetViewForwarder(); + + return nullptr; +} + +SvxAccessibleTextEditViewAdapter* SvxEditSourceAdapter::GetEditViewForwarderAdapter( bool bCreate ) +{ + if( mbEditSourceValid && mpAdaptee ) + { + SvxEditViewForwarder* pEditViewForwarder = mpAdaptee->GetEditViewForwarder(bCreate); + + if( pEditViewForwarder ) + { + SvxAccessibleTextAdapter* pTextAdapter = GetTextForwarderAdapter(); + + if( pTextAdapter ) + { + maEditViewAdapter.SetForwarder(*pEditViewForwarder, *pTextAdapter); + + return &maEditViewAdapter; + } + } + } + + return nullptr; +} + +SvxEditViewForwarder* SvxEditSourceAdapter::GetEditViewForwarder( bool bCreate ) +{ + return GetEditViewForwarderAdapter( bCreate ); +} + +void SvxEditSourceAdapter::UpdateData() +{ + if( mbEditSourceValid && mpAdaptee ) + mpAdaptee->UpdateData(); +} + +SfxBroadcaster& SvxEditSourceAdapter::GetBroadcaster() const +{ + if( mbEditSourceValid && mpAdaptee ) + return mpAdaptee->GetBroadcaster(); + + return maDummyBroadcaster; +} + +void SvxEditSourceAdapter::SetEditSource( std::unique_ptr< SvxEditSource > && pAdaptee ) +{ + if (pAdaptee) + { + mpAdaptee = std::move(pAdaptee); + mbEditSourceValid = true; + } + else + { + // do a lazy delete (prevents us from deleting the broadcaster + // from within a broadcast in + // AccessibleTextHelper_Impl::Notify) + mbEditSourceValid = false; + } +} + +SvxAccessibleTextAdapter::SvxAccessibleTextAdapter() + : mpTextForwarder(nullptr) +{ +} + +SvxAccessibleTextAdapter::~SvxAccessibleTextAdapter() +{ +} + +sal_Int32 SvxAccessibleTextAdapter::GetParagraphCount() const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetParagraphCount(); +} + +sal_Int32 SvxAccessibleTextAdapter::GetTextLen( sal_Int32 nParagraph ) const +{ + SvxAccessibleTextIndex aIndex; + aIndex.SetEEIndex( nParagraph, mpTextForwarder->GetTextLen( nParagraph ), *this ); + + return aIndex.GetIndex(); +} + +OUString SvxAccessibleTextAdapter::GetText( const ESelection& rSel ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + // normalize selection + if( rSel.nStartPara > rSel.nEndPara || + (rSel.nStartPara == rSel.nEndPara && rSel.nStartPos > rSel.nEndPos) ) + { + std::swap( aStartIndex, aEndIndex ); + } + + OUString sStr = mpTextForwarder->GetText( MakeEESelection(aStartIndex, aEndIndex) ); + + // trim field text, if necessary + if( aStartIndex.InField() ) + { + DBG_ASSERT(aStartIndex.GetFieldOffset() >= 0, + "SvxAccessibleTextIndex::GetText: index value overflow"); + + sStr = sStr.copy( aStartIndex.GetFieldOffset() ); + } + if( aEndIndex.InField() && aEndIndex.GetFieldOffset() ) + { + DBG_ASSERT(sStr.getLength() - (aEndIndex.GetFieldLen() - aEndIndex.GetFieldOffset()) >= 0, + "SvxAccessibleTextIndex::GetText: index value overflow"); + + sStr = sStr.copy(0, sStr.getLength() - (aEndIndex.GetFieldLen() - aEndIndex.GetFieldOffset()) ); + } + + EBulletInfo aBulletInfo2 = GetBulletInfo( aEndIndex.GetParagraph() ); + + if( aEndIndex.InBullet() ) + { + // append trailing bullet + sStr += aBulletInfo2.aText; + + DBG_ASSERT(sStr.getLength() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset()) >= 0, + "SvxAccessibleTextIndex::GetText: index value overflow"); + + sStr = sStr.copy(0, sStr.getLength() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset()) ); + } + else if( aStartIndex.GetParagraph() != aEndIndex.GetParagraph() && + HaveTextBullet( aEndIndex.GetParagraph() ) ) + { + OUString sBullet = aBulletInfo2.aText; + + DBG_ASSERT(sBullet.getLength() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset()) >= 0, + "SvxAccessibleTextIndex::GetText: index value overflow"); + + sBullet = sBullet.copy(0, sBullet.getLength() - (aEndIndex.GetBulletLen() - aEndIndex.GetBulletOffset()) ); + + // insert bullet + sStr = sStr.replaceAt( GetTextLen(aStartIndex.GetParagraph()) - aStartIndex.GetIndex(), 0, sBullet ); + } + + return sStr; +} + +SfxItemSet SvxAccessibleTextAdapter::GetAttribs( const ESelection& rSel, EditEngineAttribs nOnlyHardAttrib ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + return mpTextForwarder->GetAttribs( MakeEESelection(aStartIndex, aEndIndex), nOnlyHardAttrib ); +} + +SfxItemSet SvxAccessibleTextAdapter::GetParaAttribs( sal_Int32 nPara ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetParaAttribs( nPara ); +} + +void SvxAccessibleTextAdapter::SetParaAttribs( sal_Int32 nPara, const SfxItemSet& rSet ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + mpTextForwarder->SetParaAttribs( nPara, rSet ); +} + +void SvxAccessibleTextAdapter::RemoveAttribs( const ESelection& ) +{ +} + +void SvxAccessibleTextAdapter::GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& rList ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + mpTextForwarder->GetPortions( nPara, rList ); +} + +OUString SvxAccessibleTextAdapter::GetStyleSheet(sal_Int32 nPara) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetStyleSheet(nPara); +} + +void SvxAccessibleTextAdapter::SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + mpTextForwarder->SetStyleSheet(nPara, rStyleName); +} + +SfxItemState SvxAccessibleTextAdapter::GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + return mpTextForwarder->GetItemState( MakeEESelection(aStartIndex, aEndIndex), + nWhich ); +} + +SfxItemState SvxAccessibleTextAdapter::GetItemState( sal_Int32 nPara, sal_uInt16 nWhich ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetItemState( nPara, nWhich ); +} + +void SvxAccessibleTextAdapter::QuickInsertText( const OUString& rText, const ESelection& rSel ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + mpTextForwarder->QuickInsertText( rText, + MakeEESelection(aStartIndex, aEndIndex) ); +} + +void SvxAccessibleTextAdapter::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + mpTextForwarder->QuickInsertField( rFld, + MakeEESelection(aStartIndex, aEndIndex) ); +} + +void SvxAccessibleTextAdapter::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + mpTextForwarder->QuickSetAttribs( rSet, + MakeEESelection(aStartIndex, aEndIndex) ); +} + +void SvxAccessibleTextAdapter::QuickInsertLineBreak( const ESelection& rSel ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + mpTextForwarder->QuickInsertLineBreak( MakeEESelection(aStartIndex, aEndIndex) ); +} + +SfxItemPool* SvxAccessibleTextAdapter::GetPool() const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetPool(); +} + +OUString SvxAccessibleTextAdapter::CalcFieldValue( const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos, std::optional<Color>& rpTxtColor, std::optional<Color>& rpFldColor, std::optional<FontLineStyle>& rpFldLineStyle ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->CalcFieldValue( rField, nPara, nPos, rpTxtColor, rpFldColor, rpFldLineStyle ); +} + +void SvxAccessibleTextAdapter::FieldClicked( const SvxFieldItem& rField ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + mpTextForwarder->FieldClicked( rField ); +} + +sal_Int32 SvxAccessibleTextAdapter::CalcEditEngineIndex( sal_Int32 nPara, sal_Int32 nLogicalIndex ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + aIndex.SetIndex(nPara, nLogicalIndex, *mpTextForwarder); + return aIndex.GetEEIndex(); +} + +bool SvxAccessibleTextAdapter::IsValid() const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + if( mpTextForwarder ) + return mpTextForwarder->IsValid(); + else + return false; +} + +LanguageType SvxAccessibleTextAdapter::GetLanguage( sal_Int32 nPara, sal_Int32 nPos ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + + aIndex.SetIndex( nPara, nPos, *this ); + + return mpTextForwarder->GetLanguage( nPara, aIndex.GetEEIndex() ); +} + +sal_Int32 SvxAccessibleTextAdapter::GetFieldCount( sal_Int32 nPara ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetFieldCount( nPara ); +} + +EFieldInfo SvxAccessibleTextAdapter::GetFieldInfo( sal_Int32 nPara, sal_uInt16 nField ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetFieldInfo( nPara, nField ); +} + +EBulletInfo SvxAccessibleTextAdapter::GetBulletInfo( sal_Int32 nPara ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetBulletInfo( nPara ); +} + +tools::Rectangle SvxAccessibleTextAdapter::GetCharBounds( sal_Int32 nPara, sal_Int32 nIndex ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + aIndex.SetIndex( nPara, nIndex, *this ); + + // preset if anything goes wrong below + // n-th char in GetParagraphIndex's paragraph + tools::Rectangle aRect = mpTextForwarder->GetCharBounds( nPara, aIndex.GetEEIndex() ); + + if( aIndex.InBullet() ) + { + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + OutputDevice* pOutDev = GetRefDevice(); + + DBG_ASSERT(pOutDev!=nullptr, "SvxAccessibleTextAdapter::GetCharBounds: No ref device"); + + // preset if anything goes wrong below + aRect = aBulletInfo.aBounds; // better than nothing + if( pOutDev ) + { + AccessibleStringWrap aStringWrap( *pOutDev, aBulletInfo.aFont, aBulletInfo.aText ); + + aStringWrap.GetCharacterBounds( aIndex.GetBulletOffset(), aRect ); + aRect.Move( aBulletInfo.aBounds.Left(), aBulletInfo.aBounds.Top() ); + } + } + else + { + // handle field content manually + if( aIndex.InField() ) + { + OutputDevice* pOutDev = GetRefDevice(); + + DBG_ASSERT(pOutDev!=nullptr, "SvxAccessibleTextAdapter::GetCharBounds: No ref device"); + + if( pOutDev ) + { + ESelection aSel = MakeEESelection( aIndex ); + + SvxFont aFont = EditEngine::CreateSvxFontFromItemSet( mpTextForwarder->GetAttribs( aSel ) ); + AccessibleStringWrap aStringWrap( *pOutDev, + aFont, + mpTextForwarder->GetText( aSel ) ); + + tools::Rectangle aStartRect = mpTextForwarder->GetCharBounds( nPara, aIndex.GetEEIndex() ); + + aStringWrap.GetCharacterBounds( aIndex.GetFieldOffset(), aRect ); + aRect.Move( aStartRect.Left(), aStartRect.Top() ); + } + } + } + + return aRect; +} + +tools::Rectangle SvxAccessibleTextAdapter::GetParaBounds( sal_Int32 nPara ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ) + { + // include bullet in para bounding box + tools::Rectangle aRect( mpTextForwarder->GetParaBounds( nPara ) ); + + aRect.Union( aBulletInfo.aBounds ); + + return aRect; + } + + return mpTextForwarder->GetParaBounds( nPara ); +} + +MapMode SvxAccessibleTextAdapter::GetMapMode() const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetMapMode(); +} + +OutputDevice* SvxAccessibleTextAdapter::GetRefDevice() const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetRefDevice(); +} + +bool SvxAccessibleTextAdapter::GetIndexAtPoint( const Point& rPoint, sal_Int32& nPara, sal_Int32& nIndex ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + if( !mpTextForwarder->GetIndexAtPoint( rPoint, nPara, nIndex ) ) + return false; + + SvxAccessibleTextIndex aIndex; + aIndex.SetEEIndex(nPara, nIndex, *this); + + DBG_ASSERT(aIndex.GetIndex() >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + nIndex = aIndex.GetIndex(); + + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + // any text bullets? + if( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ) + { + if( aBulletInfo.aBounds.Contains( rPoint) ) + { + OutputDevice* pOutDev = GetRefDevice(); + + DBG_ASSERT(pOutDev!=nullptr, "SvxAccessibleTextAdapter::GetIndexAtPoint: No ref device"); + + if( !pOutDev ) + return false; + + AccessibleStringWrap aStringWrap( *pOutDev, aBulletInfo.aFont, aBulletInfo.aText ); + + Point aPoint = rPoint; + aPoint.Move( -aBulletInfo.aBounds.Left(), -aBulletInfo.aBounds.Top() ); + + DBG_ASSERT(aStringWrap.GetIndexAtPoint( aPoint ) >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + nIndex = aStringWrap.GetIndexAtPoint( aPoint ); + return true; + } + } + + if( !aIndex.InField() ) + return true; + + OutputDevice* pOutDev = GetRefDevice(); + + DBG_ASSERT(pOutDev!=nullptr, "SvxAccessibleTextAdapter::GetIndexAtPoint: No ref device"); + + if( !pOutDev ) + return false; + + ESelection aSelection = MakeEESelection( aIndex ); + SvxFont aFont = EditEngine::CreateSvxFontFromItemSet( mpTextForwarder->GetAttribs( aSelection ) ); + AccessibleStringWrap aStringWrap( *pOutDev, + aFont, + mpTextForwarder->GetText( aSelection ) ); + + tools::Rectangle aRect = mpTextForwarder->GetCharBounds( nPara, aIndex.GetEEIndex() ); + Point aPoint = rPoint; + aPoint.Move( -aRect.Left(), -aRect.Top() ); + + DBG_ASSERT(aIndex.GetIndex() + aStringWrap.GetIndexAtPoint( rPoint ) >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + nIndex = (aIndex.GetIndex() + aStringWrap.GetIndexAtPoint( aPoint )); + return true; +} + +bool SvxAccessibleTextAdapter::GetWordIndices( sal_Int32 nPara, sal_Int32 nIndex, sal_Int32& nStart, sal_Int32& nEnd ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + aIndex.SetIndex(nPara, nIndex, *this); + nIndex = aIndex.GetEEIndex(); + + if( aIndex.InBullet() ) + { + DBG_ASSERT(aIndex.GetBulletLen() >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + // always treat bullet as separate word + nStart = 0; + nEnd = aIndex.GetBulletLen(); + + return true; + } + + if( aIndex.InField() ) + { + DBG_ASSERT(aIndex.GetIndex() - aIndex.GetFieldOffset() >= 0 && + nStart + aIndex.GetFieldLen() >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + // always treat field as separate word + // TODO: to circumvent this, _we_ would have to do the break iterator stuff! + nStart = aIndex.GetIndex() - aIndex.GetFieldOffset(); + nEnd = nStart + aIndex.GetFieldLen(); + + return true; + } + + if( !mpTextForwarder->GetWordIndices( nPara, nIndex, nStart, nEnd ) ) + return false; + + aIndex.SetEEIndex( nPara, nStart, *this ); + DBG_ASSERT(aIndex.GetIndex() >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + nStart = aIndex.GetIndex(); + + aIndex.SetEEIndex( nPara, nEnd, *this ); + DBG_ASSERT(aIndex.GetIndex() >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + nEnd = aIndex.GetIndex(); + + return true; +} + +bool SvxAccessibleTextAdapter::GetAttributeRun( sal_Int32& nStartIndex, sal_Int32& nEndIndex, sal_Int32 nPara, sal_Int32 nIndex, bool /* bInCell */ ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aIndex; + aIndex.SetIndex(nPara, nIndex, *this); + nIndex = aIndex.GetEEIndex(); + + if( aIndex.InBullet() ) + { + DBG_ASSERT(aIndex.GetBulletLen() >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + // always treat bullet as distinct attribute + nStartIndex = 0; + nEndIndex = aIndex.GetBulletLen(); + + return true; + } + + if( aIndex.InField() ) + { + DBG_ASSERT(aIndex.GetIndex() - aIndex.GetFieldOffset() >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + + // always treat field as distinct attribute + nStartIndex = aIndex.GetIndex() - aIndex.GetFieldOffset(); + nEndIndex = nStartIndex + aIndex.GetFieldLen(); + + return true; + } + + if( !mpTextForwarder->GetAttributeRun( nStartIndex, nEndIndex, nPara, nIndex ) ) + return false; + + aIndex.SetEEIndex( nPara, nStartIndex, *this ); + DBG_ASSERT(aIndex.GetIndex() >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + nStartIndex = aIndex.GetIndex(); + + aIndex.SetEEIndex( nPara, nEndIndex, *this ); + DBG_ASSERT(aIndex.GetIndex() >= 0, + "SvxAccessibleTextIndex::SetIndex: index value overflow"); + nEndIndex = aIndex.GetIndex(); + + return true; +} + +sal_Int32 SvxAccessibleTextAdapter::GetLineCount( sal_Int32 nPara ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetLineCount( nPara ); +} + +sal_Int32 SvxAccessibleTextAdapter::GetLineLen( sal_Int32 nPara, sal_Int32 nLine ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aEndIndex; + sal_Int32 nCurrLine; + sal_Int32 nCurrIndex, nLastIndex; + for( nCurrLine=0, nCurrIndex=0, nLastIndex=0; nCurrLine<=nLine; ++nCurrLine ) + { + nLastIndex = nCurrIndex; + nCurrIndex = + nCurrIndex + mpTextForwarder->GetLineLen( nPara, nCurrLine ); + } + + aEndIndex.SetEEIndex( nPara, nCurrIndex, *this ); + if( nLine > 0 ) + { + SvxAccessibleTextIndex aStartIndex; + aStartIndex.SetEEIndex( nPara, nLastIndex, *this ); + + return aEndIndex.GetIndex() - aStartIndex.GetIndex(); + } + else + return aEndIndex.GetIndex(); +} + +void SvxAccessibleTextAdapter::GetLineBoundaries( /*out*/sal_Int32 &rStart, /*out*/sal_Int32 &rEnd, sal_Int32 nParagraph, sal_Int32 nLine ) const +{ + mpTextForwarder->GetLineBoundaries( rStart, rEnd, nParagraph, nLine ); +} + +sal_Int32 SvxAccessibleTextAdapter::GetLineNumberAtIndex( sal_Int32 nPara, sal_Int32 nIndex ) const +{ + return mpTextForwarder->GetLineNumberAtIndex( nPara, nIndex ); +} + +bool SvxAccessibleTextAdapter::Delete( const ESelection& rSel ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + return mpTextForwarder->Delete( MakeEESelection(aStartIndex, aEndIndex ) ); +} + +bool SvxAccessibleTextAdapter::InsertText( const OUString& rStr, const ESelection& rSel ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + return mpTextForwarder->InsertText( rStr, MakeEESelection(aStartIndex, aEndIndex) ); +} + +bool SvxAccessibleTextAdapter::QuickFormatDoc( bool bFull ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->QuickFormatDoc( bFull ); +} + +sal_Int16 SvxAccessibleTextAdapter::GetDepth( sal_Int32 nPara ) const +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->GetDepth( nPara ); +} + +bool SvxAccessibleTextAdapter::SetDepth( sal_Int32 nPara, sal_Int16 nNewDepth ) +{ + assert(mpTextForwarder && "SvxAccessibleTextAdapter: no forwarder"); + + return mpTextForwarder->SetDepth( nPara, nNewDepth ); +} + +void SvxAccessibleTextAdapter::SetForwarder( SvxTextForwarder& rForwarder ) +{ + mpTextForwarder = &rForwarder; +} + +bool SvxAccessibleTextAdapter::HaveImageBullet( sal_Int32 nPara ) const +{ + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + return ( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType == SVX_NUM_BITMAP ); +} + +bool SvxAccessibleTextAdapter::HaveTextBullet( sal_Int32 nPara ) const +{ + EBulletInfo aBulletInfo = GetBulletInfo( nPara ); + + return ( aBulletInfo.nParagraph != EE_PARA_NOT_FOUND && + aBulletInfo.bVisible && + aBulletInfo.nType != SVX_NUM_BITMAP ); +} + +bool SvxAccessibleTextAdapter::IsEditable( const ESelection& rSel ) const +{ + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *this ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *this ); + + // normalize selection + if( rSel.nStartPara > rSel.nEndPara || + (rSel.nStartPara == rSel.nEndPara && rSel.nStartPos > rSel.nEndPos) ) + { + std::swap( aStartIndex, aEndIndex ); + } + + return aStartIndex.IsEditableRange( aEndIndex ); +} + +const SfxItemSet * SvxAccessibleTextAdapter::GetEmptyItemSetPtr() +{ + OSL_FAIL( "not implemented" ); + return nullptr; +} + +void SvxAccessibleTextAdapter::AppendParagraph() +{ + OSL_FAIL( "not implemented" ); +} + +sal_Int32 SvxAccessibleTextAdapter::AppendTextPortion( sal_Int32, const OUString &, const SfxItemSet & ) +{ + OSL_FAIL( "not implemented" ); + return 0; +} +void SvxAccessibleTextAdapter::CopyText(const SvxTextForwarder&) +{ + OSL_FAIL( "not implemented" ); +} + +SvxAccessibleTextEditViewAdapter::SvxAccessibleTextEditViewAdapter() + : mpViewForwarder(nullptr) + , mpTextForwarder(nullptr) +{ +} + +SvxAccessibleTextEditViewAdapter::~SvxAccessibleTextEditViewAdapter() +{ +} + +bool SvxAccessibleTextEditViewAdapter::IsValid() const +{ + DBG_ASSERT(mpViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + if( mpViewForwarder ) + return mpViewForwarder->IsValid(); + else + return false; +} + +Point SvxAccessibleTextEditViewAdapter::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + DBG_ASSERT(mpViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mpViewForwarder->LogicToPixel(rPoint, rMapMode); +} + +Point SvxAccessibleTextEditViewAdapter::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + DBG_ASSERT(mpViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mpViewForwarder->PixelToLogic(rPoint, rMapMode); +} + +bool SvxAccessibleTextEditViewAdapter::GetSelection( ESelection& rSel ) const +{ + DBG_ASSERT(mpViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + ESelection aSelection; + + if( !mpViewForwarder->GetSelection( aSelection ) ) + return false; + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetEEIndex( aSelection.nStartPara, aSelection.nStartPos, *mpTextForwarder ); + aEndIndex.SetEEIndex( aSelection.nEndPara, aSelection.nEndPos, *mpTextForwarder ); + + DBG_ASSERT(aStartIndex.GetIndex() >= 0 && + aEndIndex.GetIndex() >= 0, + "SvxAccessibleTextEditViewAdapter::GetSelection: index value overflow"); + + rSel = ESelection( aStartIndex.GetParagraph(), aStartIndex.GetIndex(), + aEndIndex.GetParagraph(), aEndIndex.GetIndex() ); + + return true; +} + +bool SvxAccessibleTextEditViewAdapter::SetSelection( const ESelection& rSel ) +{ + DBG_ASSERT(mpViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + SvxAccessibleTextIndex aStartIndex; + SvxAccessibleTextIndex aEndIndex; + + aStartIndex.SetIndex( rSel.nStartPara, rSel.nStartPos, *mpTextForwarder ); + aEndIndex.SetIndex( rSel.nEndPara, rSel.nEndPos, *mpTextForwarder ); + + return mpViewForwarder->SetSelection( MakeEESelection(aStartIndex, aEndIndex) ); +} + +bool SvxAccessibleTextEditViewAdapter::Copy() +{ + DBG_ASSERT(mpViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mpViewForwarder->Copy(); +} + +bool SvxAccessibleTextEditViewAdapter::Cut() +{ + DBG_ASSERT(mpViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mpViewForwarder->Cut(); +} + +bool SvxAccessibleTextEditViewAdapter::Paste() +{ + DBG_ASSERT(mpViewForwarder, "SvxAccessibleTextEditViewAdapter: no forwarder"); + + return mpViewForwarder->Paste(); +} + +void SvxAccessibleTextEditViewAdapter::SetForwarder( SvxEditViewForwarder& rForwarder, + SvxAccessibleTextAdapter& rTextForwarder ) +{ + mpViewForwarder = &rForwarder; + mpTextForwarder = &rTextForwarder; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unoedsrc.cxx b/editeng/source/uno/unoedsrc.cxx new file mode 100644 index 0000000000..1c827472d1 --- /dev/null +++ b/editeng/source/uno/unoedsrc.cxx @@ -0,0 +1,77 @@ +/* -*- 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 <svl/SfxBroadcaster.hxx> + +#include <editeng/unoedsrc.hxx> + +#include <osl/diagnose.h> + + +void SvxEditSource::addRange( SvxUnoTextRangeBase* ) +{ +} + + +void SvxEditSource::removeRange( SvxUnoTextRangeBase* ) +{ +} + + +const SvxUnoTextRangeBaseVec& SvxEditSource::getRanges() const +{ + static SvxUnoTextRangeBaseVec gList; + return gList; +} + + +SvxTextForwarder::~SvxTextForwarder() COVERITY_NOEXCEPT_FALSE +{ +} + + +SvxViewForwarder::~SvxViewForwarder() +{ +} + + +SvxEditSource::~SvxEditSource() +{ +} + +SvxViewForwarder* SvxEditSource::GetViewForwarder() +{ + return nullptr; +} + +SvxEditViewForwarder* SvxEditSource::GetEditViewForwarder( bool ) +{ + return nullptr; +} + +SfxBroadcaster& SvxEditSource::GetBroadcaster() const +{ + OSL_FAIL("SvxEditSource::GetBroadcaster called for implementation missing this feature!"); + + static SfxBroadcaster aBroadcaster; + + return aBroadcaster; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unofdesc.cxx b/editeng/source/uno/unofdesc.cxx new file mode 100644 index 0000000000..722ae7d7f9 --- /dev/null +++ b/editeng/source/uno/unofdesc.cxx @@ -0,0 +1,229 @@ +/* -*- 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 <editeng/eeitem.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/awt/FontDescriptor.hpp> + +#include <editeng/fontitem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <editeng/wrlmitem.hxx> +#include <editeng/memberids.h> +#include <svl/itempool.hxx> +#include <vcl/font.hxx> +#include <vcl/unohelp.hxx> +#include <tools/gen.hxx> + +#include <editeng/unofdesc.hxx> + +using namespace ::com::sun::star; + + +void SvxUnoFontDescriptor::ConvertToFont( const awt::FontDescriptor& rDesc, vcl::Font& rFont ) +{ + rFont.SetFamilyName( rDesc.Name ); + rFont.SetStyleName( rDesc.StyleName ); + rFont.SetFontSize( Size( rDesc.Width, rDesc.Height ) ); + rFont.SetFamily( static_cast<FontFamily>(rDesc.Family) ); + rFont.SetCharSet( static_cast<rtl_TextEncoding>(rDesc.CharSet) ); + rFont.SetPitch( static_cast<FontPitch>(rDesc.Pitch) ); + rFont.SetOrientation( Degree10(static_cast<sal_Int16>(rDesc.Orientation*10)) ); + rFont.SetKerning( rDesc.Kerning ? FontKerning::FontSpecific : FontKerning::NONE ); + rFont.SetWeight( vcl::unohelper::ConvertFontWeight(rDesc.Weight) ); + rFont.SetItalic( static_cast<FontItalic>(rDesc.Slant) ); + rFont.SetUnderline( static_cast<FontLineStyle>(rDesc.Underline) ); + rFont.SetStrikeout( static_cast<FontStrikeout>(rDesc.Strikeout) ); + rFont.SetWordLineMode( rDesc.WordLineMode ); +} + +void SvxUnoFontDescriptor::ConvertFromFont( const vcl::Font& rFont, awt::FontDescriptor& rDesc ) +{ + rDesc.Name = rFont.GetFamilyName(); + rDesc.StyleName = rFont.GetStyleName(); + rDesc.Width = sal::static_int_cast< sal_Int16 >(rFont.GetFontSize().Width()); + rDesc.Height = sal::static_int_cast< sal_Int16 >(rFont.GetFontSize().Height()); + rDesc.Family = sal::static_int_cast< sal_Int16 >(rFont.GetFamilyType()); + rDesc.CharSet = rFont.GetCharSet(); + rDesc.Pitch = sal::static_int_cast< sal_Int16 >(rFont.GetPitch()); + rDesc.Orientation = static_cast< float >(rFont.GetOrientation().get() / 10); + rDesc.Kerning = rFont.IsKerning(); + rDesc.Weight = vcl::unohelper::ConvertFontWeight( rFont.GetWeight() ); + rDesc.Slant = vcl::unohelper::ConvertFontSlant( rFont.GetItalic() ); + rDesc.Underline = sal::static_int_cast< sal_Int16 >(rFont.GetUnderline()); + rDesc.Strikeout = sal::static_int_cast< sal_Int16 >(rFont.GetStrikeout()); + rDesc.WordLineMode = rFont.IsWordLineMode(); +} + +void SvxUnoFontDescriptor::FillItemSet( const awt::FontDescriptor& rDesc, SfxItemSet& rSet ) +{ + uno::Any aTemp; + + { + SvxFontItem aFontItem( EE_CHAR_FONTINFO ); + aFontItem.SetFamilyName( rDesc.Name); + aFontItem.SetStyleName( rDesc.StyleName); + aFontItem.SetFamily( static_cast<FontFamily>(rDesc.Family)); + aFontItem.SetCharSet( rDesc.CharSet ); + aFontItem.SetPitch( static_cast<FontPitch>(rDesc.Pitch)); + rSet.Put(aFontItem); + } + + { + SvxFontHeightItem aFontHeightItem( 0, 100, EE_CHAR_FONTHEIGHT ); + aTemp <<= static_cast<float>(rDesc.Height); + static_cast<SfxPoolItem*>(&aFontHeightItem)->PutValue( aTemp, MID_FONTHEIGHT|CONVERT_TWIPS ); + rSet.Put(aFontHeightItem); + } + + { + SvxPostureItem aPostureItem( ITALIC_NONE, EE_CHAR_ITALIC ); + aTemp <<= rDesc.Slant; + static_cast<SfxPoolItem*>(&aPostureItem)->PutValue( aTemp, MID_POSTURE ); + rSet.Put(aPostureItem); + } + + { + SvxUnderlineItem aUnderlineItem( LINESTYLE_NONE, EE_CHAR_UNDERLINE ); + aTemp <<= rDesc.Underline; + static_cast<SfxPoolItem*>(&aUnderlineItem)->PutValue( aTemp, MID_TL_STYLE ); + rSet.Put( aUnderlineItem ); + } + + { + SvxWeightItem aWeightItem( WEIGHT_DONTKNOW, EE_CHAR_WEIGHT ); + aTemp <<= rDesc.Weight; + static_cast<SfxPoolItem*>(&aWeightItem)->PutValue( aTemp, MID_WEIGHT ); + rSet.Put( aWeightItem ); + } + + { + SvxCrossedOutItem aCrossedOutItem( STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ); + aTemp <<= rDesc.Strikeout; + static_cast<SfxPoolItem*>(&aCrossedOutItem)->PutValue( aTemp, MID_CROSS_OUT ); + rSet.Put( aCrossedOutItem ); + } + + { + SvxWordLineModeItem aWLMItem( rDesc.WordLineMode, EE_CHAR_WLM ); + rSet.Put( aWLMItem ); + } +} + +void SvxUnoFontDescriptor::FillFromItemSet( const SfxItemSet& rSet, awt::FontDescriptor& rDesc ) +{ + const SfxPoolItem* pItem = nullptr; + { + const SvxFontItem* pFontItem = &rSet.Get( EE_CHAR_FONTINFO ); + rDesc.Name = pFontItem->GetFamilyName(); + rDesc.StyleName = pFontItem->GetStyleName(); + rDesc.Family = sal::static_int_cast< sal_Int16 >( + pFontItem->GetFamily()); + rDesc.CharSet = pFontItem->GetCharSet(); + rDesc.Pitch = sal::static_int_cast< sal_Int16 >( + pFontItem->GetPitch()); + } + { + pItem = &rSet.Get( EE_CHAR_FONTHEIGHT ); + uno::Any aHeight; + if( pItem->QueryValue( aHeight, MID_FONTHEIGHT ) ) + aHeight >>= rDesc.Height; + } + { + pItem = &rSet.Get( EE_CHAR_ITALIC ); + uno::Any aFontSlant; + if(pItem->QueryValue( aFontSlant, MID_POSTURE )) + aFontSlant >>= rDesc.Slant; + } + { + pItem = &rSet.Get( EE_CHAR_UNDERLINE ); + uno::Any aUnderline; + if(pItem->QueryValue( aUnderline, MID_TL_STYLE )) + aUnderline >>= rDesc.Underline; + } + { + pItem = &rSet.Get( EE_CHAR_WEIGHT ); + uno::Any aWeight; + if(pItem->QueryValue( aWeight, MID_WEIGHT )) + aWeight >>= rDesc.Weight; + } + { + pItem = &rSet.Get( EE_CHAR_STRIKEOUT ); + uno::Any aStrikeOut; + if(pItem->QueryValue( aStrikeOut, MID_CROSS_OUT )) + aStrikeOut >>= rDesc.Strikeout; + } + { + const SvxWordLineModeItem* pWLMItem = &rSet.Get( EE_CHAR_WLM ); + rDesc.WordLineMode = pWLMItem->GetValue(); + } +} + +void SvxUnoFontDescriptor::setPropertyToDefault( SfxItemSet& rSet ) +{ + rSet.InvalidateItem( EE_CHAR_FONTINFO ); + rSet.InvalidateItem( EE_CHAR_FONTHEIGHT ); + rSet.InvalidateItem( EE_CHAR_ITALIC ); + rSet.InvalidateItem( EE_CHAR_UNDERLINE ); + rSet.InvalidateItem( EE_CHAR_WEIGHT ); + rSet.InvalidateItem( EE_CHAR_STRIKEOUT ); + rSet.InvalidateItem( EE_CHAR_WLM ); +} + +uno::Any SvxUnoFontDescriptor::getPropertyDefault( SfxItemPool* pPool ) +{ + SfxItemSetFixed< + EE_CHAR_FONTINFO, EE_CHAR_FONTHEIGHT, + EE_CHAR_WEIGHT, EE_CHAR_ITALIC, + EE_CHAR_WLM, EE_CHAR_WLM> aSet(*pPool); + + uno::Any aAny; + + if(!SfxItemPool::IsWhich(EE_CHAR_FONTINFO)|| + !SfxItemPool::IsWhich(EE_CHAR_FONTHEIGHT)|| + !SfxItemPool::IsWhich(EE_CHAR_ITALIC)|| + !SfxItemPool::IsWhich(EE_CHAR_UNDERLINE)|| + !SfxItemPool::IsWhich(EE_CHAR_WEIGHT)|| + !SfxItemPool::IsWhich(EE_CHAR_STRIKEOUT)|| + !SfxItemPool::IsWhich(EE_CHAR_WLM)) + return aAny; + + aSet.Put(pPool->GetDefaultItem(EE_CHAR_FONTINFO)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_FONTHEIGHT)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_ITALIC)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_UNDERLINE)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_WEIGHT)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_STRIKEOUT)); + aSet.Put(pPool->GetDefaultItem(EE_CHAR_WLM)); + + awt::FontDescriptor aDesc; + + FillFromItemSet( aSet, aDesc ); + + aAny <<= aDesc; + + return aAny; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unofield.cxx b/editeng/source/uno/unofield.cxx new file mode 100644 index 0000000000..6f2e84a957 --- /dev/null +++ b/editeng/source/uno/unofield.cxx @@ -0,0 +1,941 @@ +/* -*- 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 <sal/config.h> + +#include <string_view> + +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/text/FilenameDisplayFormat.hpp> +#include <o3tl/string_view.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <tools/debug.hxx> +#include <svl/itemprop.hxx> + +#include <editeng/flditem.hxx> +#include <editeng/CustomPropertyField.hxx> +#include <editeng/measfld.hxx> +#include <editeng/unofield.hxx> +#include <editeng/unotext.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <sal/log.hxx> + +#include <editeng/unonames.hxx> + +using namespace ::cppu; +using namespace ::com::sun::star; + +#define QUERYINT( xint ) \ + if( rType == cppu::UnoType<xint>::get() ) \ + aAny <<= uno::Reference< xint >(this) + + +#define WID_DATE 0 +#define WID_BOOL1 1 +#define WID_BOOL2 2 +#define WID_INT32 3 +#define WID_INT16 4 +#define WID_STRING1 5 +#define WID_STRING2 6 +#define WID_STRING3 7 + +class SvxUnoFieldData_Impl +{ +public: + bool mbBoolean1; + bool mbBoolean2; + sal_Int32 mnInt32; + sal_Int16 mnInt16; + OUString msString1; + OUString msString2; + OUString msString3; + util::DateTime maDateTime; + + OUString msPresentation; +}; + +static const SfxItemPropertySet* ImplGetFieldItemPropertySet( sal_Int32 mnId ) +{ + static const SfxItemPropertyMapEntry aExDateTimeFieldPropertyMap_Impl[] = + { + { UNO_TC_PROP_DATE_TIME, WID_DATE, ::cppu::UnoType<util::DateTime>::get(), 0, 0 }, + { UNO_TC_PROP_IS_FIXED, WID_BOOL1, cppu::UnoType<bool>::get(), 0, 0 }, + { UNO_TC_PROP_IS_DATE, WID_BOOL2, cppu::UnoType<bool>::get(), 0, 0 }, + { UNO_TC_PROP_NUMFORMAT, WID_INT32, ::cppu::UnoType<sal_Int32>::get(), 0, 0 }, + }; + static const SfxItemPropertySet aExDateTimeFieldPropertySet_Impl(aExDateTimeFieldPropertyMap_Impl); + + static const SfxItemPropertyMapEntry aDateTimeFieldPropertyMap_Impl[] = + { + { UNO_TC_PROP_IS_DATE, WID_BOOL2, cppu::UnoType<bool>::get(), 0, 0 }, + }; + static const SfxItemPropertySet aDateTimeFieldPropertySet_Impl(aDateTimeFieldPropertyMap_Impl); + + static const SfxItemPropertyMapEntry aUrlFieldPropertyMap_Impl[] = + { + { UNO_TC_PROP_URL_FORMAT, WID_INT16, ::cppu::UnoType<sal_Int16>::get(), 0, 0 }, + { UNO_TC_PROP_URL_REPRESENTATION, WID_STRING1, ::cppu::UnoType<OUString>::get(), 0, 0 }, + { UNO_TC_PROP_URL_TARGET, WID_STRING2, ::cppu::UnoType<OUString>::get(), 0, 0 }, + { UNO_TC_PROP_URL, WID_STRING3, ::cppu::UnoType<OUString>::get(), 0, 0 }, + }; + static const SfxItemPropertySet aUrlFieldPropertySet_Impl(aUrlFieldPropertyMap_Impl); + + static const SfxItemPropertySet aEmptyPropertySet_Impl({}); + + static const SfxItemPropertyMapEntry aExtFileFieldPropertyMap_Impl[] = + { + { UNO_TC_PROP_IS_FIXED, WID_BOOL1, cppu::UnoType<bool>::get(), 0, 0 }, + { UNO_TC_PROP_FILE_FORMAT, WID_INT16, ::cppu::UnoType<sal_Int16>::get(), 0, 0 }, + { UNO_TC_PROP_CURRENT_PRESENTATION, WID_STRING1, ::cppu::UnoType<OUString>::get(), 0, 0 }, + }; + static const SfxItemPropertySet aExtFileFieldPropertySet_Impl(aExtFileFieldPropertyMap_Impl); + + static const SfxItemPropertyMapEntry aAuthorFieldPropertyMap_Impl[] = + { + { UNO_TC_PROP_IS_FIXED, WID_BOOL1, cppu::UnoType<bool>::get(), 0, 0 }, + { UNO_TC_PROP_CURRENT_PRESENTATION, WID_STRING1,::cppu::UnoType<OUString>::get(), 0, 0 }, + { UNO_TC_PROP_AUTHOR_CONTENT, WID_STRING2,::cppu::UnoType<OUString>::get(), 0, 0 }, + { UNO_TC_PROP_AUTHOR_FORMAT, WID_INT16, ::cppu::UnoType<sal_Int16>::get(), 0, 0 }, + { UNO_TC_PROP_AUTHOR_FULLNAME, WID_BOOL2, cppu::UnoType<bool>::get(), 0, 0 }, + }; + static const SfxItemPropertySet aAuthorFieldPropertySet_Impl(aAuthorFieldPropertyMap_Impl); + + static const SfxItemPropertyMapEntry aMeasureFieldPropertyMap_Impl[] = + { + { UNO_TC_PROP_MEASURE_KIND, WID_INT16, ::cppu::UnoType<sal_Int16>::get(), 0, 0 }, + }; + static const SfxItemPropertySet aMeasureFieldPropertySet_Impl(aMeasureFieldPropertyMap_Impl); + + static const SfxItemPropertyMapEntry aDocInfoCustomFieldPropertyMap_Impl[] = + { + { UNO_TC_PROP_NAME, WID_STRING1, cppu::UnoType<OUString>::get(), 0, 0 }, + { UNO_TC_PROP_CURRENT_PRESENTATION, WID_STRING2, cppu::UnoType<OUString>::get(), 0, 0 }, + { UNO_TC_PROP_IS_FIXED, WID_BOOL1, cppu::UnoType<bool>::get(), 0, 0 }, + { UNO_TC_PROP_NUMFORMAT, WID_INT32, cppu::UnoType<sal_Int32>::get(), 0, 0 }, + { UNO_TC_PROP_IS_FIXED_LANGUAGE, WID_BOOL2, cppu::UnoType<bool>::get(), 0, 0 }, + }; + static const SfxItemPropertySet aDocInfoCustomFieldPropertySet_Impl(aDocInfoCustomFieldPropertyMap_Impl); + + switch( mnId ) + { + case text::textfield::Type::EXTENDED_TIME: + case text::textfield::Type::DATE: + return &aExDateTimeFieldPropertySet_Impl; + case text::textfield::Type::URL: + return &aUrlFieldPropertySet_Impl; + case text::textfield::Type::TIME: + return &aDateTimeFieldPropertySet_Impl; + case text::textfield::Type::EXTENDED_FILE: + return &aExtFileFieldPropertySet_Impl; + case text::textfield::Type::AUTHOR: + return &aAuthorFieldPropertySet_Impl; + case text::textfield::Type::MEASURE: + return &aMeasureFieldPropertySet_Impl; + case text::textfield::Type::DOCINFO_CUSTOM: + return &aDocInfoCustomFieldPropertySet_Impl; + default: + return &aEmptyPropertySet_Impl; + } +} + +/* conversion routines */ + +static sal_Int16 getFileNameDisplayFormat( SvxFileFormat nFormat ) +{ + switch( nFormat ) + { + case SvxFileFormat::NameAndExt: return text::FilenameDisplayFormat::NAME_AND_EXT; + case SvxFileFormat::PathFull: return text::FilenameDisplayFormat::FULL; + case SvxFileFormat::PathOnly: return text::FilenameDisplayFormat::PATH; +// case SvxFileFormat::NameOnly: + default: return text::FilenameDisplayFormat::NAME; + } +} + +static SvxFileFormat setFileNameDisplayFormat( sal_Int16 nFormat ) +{ + switch( nFormat ) + { + case text::FilenameDisplayFormat::FULL: return SvxFileFormat::PathFull; + case text::FilenameDisplayFormat::PATH: return SvxFileFormat::PathOnly; + case text::FilenameDisplayFormat::NAME: return SvxFileFormat::NameOnly; +// case text::FilenameDisplayFormat::NAME_AND_EXT: + default: + return SvxFileFormat::NameAndExt; + } +} + +static util::DateTime getDate( sal_Int32 nDate ) +{ + util::DateTime aDate; + + Date aTempDate( nDate ); + + aDate.Day = aTempDate.GetDay(); + aDate.Month = aTempDate.GetMonth(); + aDate.Year = aTempDate.GetYear(); + + return aDate; +} + +static Date setDate( util::DateTime const & rDate ) +{ + return Date( rDate.Day, rDate.Month, rDate.Year ); +} + +static util::DateTime getTime(sal_Int64 const nTime) +{ + util::DateTime aTime; + + tools::Time aTempTime( nTime ); + + aTime.NanoSeconds = aTempTime.GetNanoSec(); + aTime.Seconds = aTempTime.GetSec(); + aTime.Minutes = aTempTime.GetMin(); + aTime.Hours = aTempTime.GetHour(); + + return aTime; +} + +static tools::Time setTime( util::DateTime const & rDate ) +{ + return tools::Time( rDate ); +} + + + +SvxUnoTextField::SvxUnoTextField( sal_Int32 nServiceId ) noexcept +: OComponentHelper( m_aMutex ) +, mpPropSet(nullptr) +, mnServiceId(nServiceId) +, mpImpl( new SvxUnoFieldData_Impl ) +{ + mpPropSet = ImplGetFieldItemPropertySet(mnServiceId); + + mpImpl->maDateTime.NanoSeconds = 0; + mpImpl->maDateTime.Seconds = 0; + mpImpl->maDateTime.Minutes = 0; + mpImpl->maDateTime.Hours = 0; + mpImpl->maDateTime.Day = 0; + mpImpl->maDateTime.Month = 0; + mpImpl->maDateTime.Year = 0; + mpImpl->maDateTime.IsUTC = false; + + switch( nServiceId ) + { + case text::textfield::Type::DATE: + mpImpl->mbBoolean2 = true; + mpImpl->mnInt32 = static_cast<sal_Int32>(SvxDateFormat::StdSmall); + mpImpl->mbBoolean1 = false; + break; + + case text::textfield::Type::EXTENDED_TIME: + case text::textfield::Type::TIME: + mpImpl->mbBoolean2 = false; + mpImpl->mbBoolean1 = false; + mpImpl->mnInt32 = static_cast<sal_Int32>(SvxTimeFormat::Standard); + break; + + case text::textfield::Type::URL: + mpImpl->mnInt16 = static_cast<sal_uInt16>(SvxURLFormat::Repr); + break; + + case text::textfield::Type::EXTENDED_FILE: + mpImpl->mbBoolean1 = false; + mpImpl->mnInt16 = text::FilenameDisplayFormat::FULL; + break; + + case text::textfield::Type::AUTHOR: + mpImpl->mnInt16 = static_cast<sal_uInt16>(SvxAuthorFormat::FullName); + mpImpl->mbBoolean1 = false; + mpImpl->mbBoolean2 = true; + break; + + case text::textfield::Type::MEASURE: + mpImpl->mnInt16 = static_cast<sal_uInt16>(SdrMeasureFieldKind::Value); + break; + + case text::textfield::Type::DOCINFO_CUSTOM: + mpImpl->mbBoolean1 = true; + mpImpl->mbBoolean2 = true; + mpImpl->mnInt32 = 0; + break; + + default: + mpImpl->mbBoolean1 = false; + mpImpl->mbBoolean2 = false; + mpImpl->mnInt32 = 0; + mpImpl->mnInt16 = 0; + + } +} + +SvxUnoTextField::SvxUnoTextField( uno::Reference< text::XTextRange > xAnchor, const OUString& rPresentation, const SvxFieldData* pData ) noexcept +: OComponentHelper( m_aMutex ) +, mxAnchor(std::move( xAnchor )) +, mpPropSet(nullptr) +, mnServiceId(text::textfield::Type::UNSPECIFIED) +, mpImpl( new SvxUnoFieldData_Impl ) +{ + DBG_ASSERT(pData, "pFieldData == NULL! [CL]" ); + + mpImpl->msPresentation = rPresentation; + + if(pData) + { + mnServiceId = pData->GetClassId(); + DBG_ASSERT(mnServiceId != text::textfield::Type::UNSPECIFIED, "unknown SvxFieldData! [CL]"); + if (mnServiceId != text::textfield::Type::UNSPECIFIED) + { + // extract field properties from data class + switch( mnServiceId ) + { + case text::textfield::Type::DATE: + { + mpImpl->mbBoolean2 = true; + // #i35416# for variable date field, don't use invalid "0000-00-00" date, + // use current date instead + bool bFixed = static_cast<const SvxDateField*>(pData)->GetType() == SvxDateType::Fix; + mpImpl->maDateTime = getDate( bFixed ? + static_cast<const SvxDateField*>(pData)->GetFixDate() : + Date( Date::SYSTEM ).GetDate() ); + mpImpl->mnInt32 = static_cast<sal_Int32>(static_cast<const SvxDateField*>(pData)->GetFormat()); + mpImpl->mbBoolean1 = bFixed; + } + break; + + case text::textfield::Type::TIME: + mpImpl->mbBoolean2 = false; + mpImpl->mbBoolean1 = false; + mpImpl->mnInt32 = static_cast<sal_Int32>(SvxTimeFormat::Standard); + break; + + case text::textfield::Type::EXTENDED_TIME: + mpImpl->mbBoolean2 = false; + mpImpl->maDateTime = getTime( static_cast<const SvxExtTimeField*>(pData)->GetFixTime() ); + mpImpl->mbBoolean1 = static_cast<const SvxExtTimeField*>(pData)->GetType() == SvxTimeType::Fix; + mpImpl->mnInt32 = static_cast<sal_Int32>(static_cast<const SvxExtTimeField*>(pData)->GetFormat()); + break; + + case text::textfield::Type::URL: + mpImpl->msString1 = static_cast<const SvxURLField*>(pData)->GetRepresentation(); + mpImpl->msString2 = static_cast<const SvxURLField*>(pData)->GetTargetFrame(); + mpImpl->msString3 = static_cast<const SvxURLField*>(pData)->GetURL(); + mpImpl->mnInt16 = sal::static_int_cast< sal_Int16 >( + static_cast<const SvxURLField*>(pData)->GetFormat()); + break; + + case text::textfield::Type::EXTENDED_FILE: + mpImpl->msString1 = static_cast<const SvxExtFileField*>(pData)->GetFile(); + mpImpl->mbBoolean1 = static_cast<const SvxExtFileField*>(pData)->GetType() == SvxFileType::Fix; + mpImpl->mnInt16 = getFileNameDisplayFormat(static_cast<const SvxExtFileField*>(pData)->GetFormat()); + break; + + case text::textfield::Type::AUTHOR: + mpImpl->msString1 = static_cast<const SvxAuthorField*>(pData)->GetFormatted(); + mpImpl->msString2 = static_cast<const SvxAuthorField*>(pData)->GetFormatted(); + mpImpl->mnInt16 = sal::static_int_cast< sal_Int16 >( + static_cast<const SvxAuthorField*>(pData)->GetFormat()); + mpImpl->mbBoolean1 = static_cast<const SvxAuthorField*>(pData)->GetType() == SvxAuthorType::Fix; + mpImpl->mbBoolean2 = static_cast<const SvxAuthorField*>(pData)->GetFormat() != SvxAuthorFormat::ShortName; + break; + + case text::textfield::Type::MEASURE: + mpImpl->mnInt16 = sal::static_int_cast< sal_Int16 >(static_cast<const SdrMeasureField*>(pData)->GetMeasureFieldKind()); + break; + + case text::textfield::Type::DOCINFO_CUSTOM: + mpImpl->msString1 = static_cast<const editeng::CustomPropertyField*>(pData)->GetName(); + mpImpl->msString2 = static_cast<const editeng::CustomPropertyField*>(pData)->GetCurrentPresentation(); + mpImpl->mbBoolean1 = false; + mpImpl->mbBoolean2 = false; + mpImpl->mnInt32 = 0; + break; + + default: + SAL_INFO("editeng", "Id service unknown: " << mnServiceId); + break; + } + } + } + + mpPropSet = ImplGetFieldItemPropertySet(mnServiceId); +} + +SvxUnoTextField::~SvxUnoTextField() noexcept +{ +} + +std::unique_ptr<SvxFieldData> SvxUnoTextField::CreateFieldData() const noexcept +{ + std::unique_ptr<SvxFieldData> pData; + + switch( mnServiceId ) + { + case text::textfield::Type::TIME: + case text::textfield::Type::EXTENDED_TIME: + case text::textfield::Type::DATE: + { + if( mpImpl->mbBoolean2 ) // IsDate? + { + Date aDate( setDate( mpImpl->maDateTime ) ); + pData.reset( new SvxDateField( aDate, mpImpl->mbBoolean1?SvxDateType::Fix:SvxDateType::Var ) ); + if( mpImpl->mnInt32 >= static_cast<sal_Int32>(SvxDateFormat::AppDefault) && + mpImpl->mnInt32 <= static_cast<sal_Int32>(SvxDateFormat::F) ) + static_cast<SvxDateField*>(pData.get())->SetFormat( static_cast<SvxDateFormat>(mpImpl->mnInt32) ); + } + else + { + if( mnServiceId != text::textfield::Type::TIME && mnServiceId != text::textfield::Type::DATE ) + { + tools::Time aTime( setTime( mpImpl->maDateTime ) ); + pData.reset( new SvxExtTimeField( aTime, mpImpl->mbBoolean1?SvxTimeType::Fix:SvxTimeType::Var ) ); + + if( static_cast<SvxTimeFormat>(mpImpl->mnInt32) >= SvxTimeFormat::AppDefault && + static_cast<SvxTimeFormat>(mpImpl->mnInt32) <= SvxTimeFormat::HH12_MM_SS_00_AMPM ) + static_cast<SvxExtTimeField*>(pData.get())->SetFormat( static_cast<SvxTimeFormat>(mpImpl->mnInt32) ); + } + else + { + pData.reset( new SvxTimeField() ); + } + } + + } + break; + + case text::textfield::Type::URL: + pData.reset( new SvxURLField( mpImpl->msString3, mpImpl->msString1, !mpImpl->msString1.isEmpty() ? SvxURLFormat::Repr : SvxURLFormat::Url ) ); + static_cast<SvxURLField*>(pData.get())->SetTargetFrame( mpImpl->msString2 ); + if( static_cast<SvxURLFormat>(mpImpl->mnInt16) >= SvxURLFormat::AppDefault && + static_cast<SvxURLFormat>(mpImpl->mnInt16) <= SvxURLFormat::Repr ) + static_cast<SvxURLField*>(pData.get())->SetFormat( static_cast<SvxURLFormat>(mpImpl->mnInt16) ); + break; + + case text::textfield::Type::PAGE: + pData.reset( new SvxPageField() ); + break; + + case text::textfield::Type::PAGES: + pData.reset( new SvxPagesField() ); + break; + + case text::textfield::Type::DOCINFO_TITLE: + pData.reset( new SvxFileField() ); + break; + + case text::textfield::Type::TABLE: + pData.reset( new SvxTableField() ); + break; + + case text::textfield::Type::EXTENDED_FILE: + { + // #92009# pass fixed attribute to constructor + pData.reset( new SvxExtFileField( mpImpl->msString1, + mpImpl->mbBoolean1 ? SvxFileType::Fix : SvxFileType::Var, + setFileNameDisplayFormat(mpImpl->mnInt16 ) ) ); + break; + } + + case text::textfield::Type::AUTHOR: + { + OUString aContent; + OUString aFirstName; + OUString aLastName; + + // do we have CurrentPresentation given? + // mimic behaviour of writer, which means: + // prefer CurrentPresentation over Content + // if both are given. + if( !mpImpl->msString1.isEmpty() ) + aContent = mpImpl->msString1; + else + aContent = mpImpl->msString2; + + sal_Int32 nPos = aContent.lastIndexOf( ' ', 0 ); + if( nPos > 0 ) + { + aFirstName = aContent.copy( 0, nPos ); + aLastName = aContent.copy( nPos + 1 ); + } + else + { + aLastName = aContent; + } + + // #92009# pass fixed attribute to constructor + pData.reset( new SvxAuthorField( aFirstName, aLastName, "", + mpImpl->mbBoolean1 ? SvxAuthorType::Fix : SvxAuthorType::Var ) ); + + if( !mpImpl->mbBoolean2 ) + { + static_cast<SvxAuthorField*>(pData.get())->SetFormat( SvxAuthorFormat::ShortName ); + } + else if( static_cast<SvxAuthorFormat>(mpImpl->mnInt16) >= SvxAuthorFormat::FullName && + static_cast<SvxAuthorFormat>(mpImpl->mnInt16) <= SvxAuthorFormat::ShortName ) + { + static_cast<SvxAuthorField*>(pData.get())->SetFormat( static_cast<SvxAuthorFormat>(mpImpl->mnInt16) ); + } + + break; + } + + case text::textfield::Type::MEASURE: + { + SdrMeasureFieldKind eKind = SdrMeasureFieldKind::Value; + if( mpImpl->mnInt16 == sal_Int16(SdrMeasureFieldKind::Unit) || mpImpl->mnInt16 == sal_Int16(SdrMeasureFieldKind::Rotate90Blanks) ) + eKind = static_cast<SdrMeasureFieldKind>(mpImpl->mnInt16); + pData.reset( new SdrMeasureField( eKind) ); + break; + } + case text::textfield::Type::PRESENTATION_HEADER: + pData.reset( new SvxHeaderField() ); + break; + case text::textfield::Type::PRESENTATION_FOOTER: + pData.reset( new SvxFooterField() ); + break; + case text::textfield::Type::PRESENTATION_DATE_TIME: + pData.reset( new SvxDateTimeField() ); + break; + case text::textfield::Type::PAGE_NAME: + pData.reset( new SvxPageTitleField() ); + break; + case text::textfield::Type::DOCINFO_CUSTOM: + pData.reset( new editeng::CustomPropertyField(mpImpl->msString1, mpImpl->msString2) ); + break; + } + + return pData; +} + +// uno::XInterface +uno::Any SAL_CALL SvxUnoTextField::queryAggregation( const uno::Type & rType ) +{ + uno::Any aAny; + + QUERYINT( beans::XPropertySet ); + else QUERYINT( text::XTextContent ); + else QUERYINT( text::XTextField ); + else QUERYINT( lang::XServiceInfo ); + else + return OComponentHelper::queryAggregation( rType ); + + return aAny; +} + +// XTypeProvider + +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextField::getTypes() +{ + if( !maTypeSequence.hasElements() ) + { + maTypeSequence = comphelper::concatSequences( + OComponentHelper::getTypes(), + uno::Sequence { + cppu::UnoType<text::XTextField>::get(), + cppu::UnoType<beans::XPropertySet>::get(), + cppu::UnoType<lang::XServiceInfo>::get(), + cppu::UnoType<lang::XUnoTunnel>::get() }); + } + return maTypeSequence; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextField::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +uno::Any SAL_CALL SvxUnoTextField::queryInterface( const uno::Type & rType ) +{ + return OComponentHelper::queryInterface(rType); +} + +void SAL_CALL SvxUnoTextField::acquire() noexcept +{ + OComponentHelper::acquire(); +} + +void SAL_CALL SvxUnoTextField::release() noexcept +{ + OComponentHelper::release(); +} + +// Interface text::XTextField +OUString SAL_CALL SvxUnoTextField::getPresentation( sal_Bool bShowCommand ) +{ + SolarMutexGuard aGuard; + if (bShowCommand) + { + switch (mnServiceId) + { + case text::textfield::Type::DATE: + return "Date"; + case text::textfield::Type::URL: + return "URL"; + case text::textfield::Type::PAGE: + return "Page"; + case text::textfield::Type::PAGES: + return "Pages"; + case text::textfield::Type::TIME: + return "Time"; + case text::textfield::Type::DOCINFO_TITLE: + return "File"; + case text::textfield::Type::TABLE: + return "Table"; + case text::textfield::Type::EXTENDED_TIME: + return "ExtTime"; + case text::textfield::Type::EXTENDED_FILE: + return "ExtFile"; + case text::textfield::Type::AUTHOR: + return "Author"; + case text::textfield::Type::MEASURE: + return "Measure"; + case text::textfield::Type::PRESENTATION_HEADER: + return "Header"; + case text::textfield::Type::PRESENTATION_FOOTER: + return "Footer"; + case text::textfield::Type::PRESENTATION_DATE_TIME: + return "DateTime"; + case text::textfield::Type::PAGE_NAME: + return "PageName"; + case text::textfield::Type::DOCINFO_CUSTOM: + return "Custom"; + default: + return "Unknown"; + } + } + else + { + return mpImpl->msPresentation; + } +} + +// Interface text::XTextContent +void SAL_CALL SvxUnoTextField::attach( const uno::Reference< text::XTextRange >& xTextRange ) +{ + SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRange>( xTextRange ); + if(pRange == nullptr) + throw lang::IllegalArgumentException(); + + std::unique_ptr<SvxFieldData> pData = CreateFieldData(); + if( pData ) + pRange->attachField( std::move(pData) ); +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextField::getAnchor() +{ + return mxAnchor; +} + +// lang::XComponent +void SAL_CALL SvxUnoTextField::dispose() +{ + OComponentHelper::dispose(); + mxAnchor.clear(); +} + +void SAL_CALL SvxUnoTextField::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) +{ + OComponentHelper::addEventListener(xListener); +} + +void SAL_CALL SvxUnoTextField::removeEventListener( const uno::Reference< lang::XEventListener >& aListener ) +{ + OComponentHelper::removeEventListener(aListener); +} + + +// Interface beans::XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL SvxUnoTextField::getPropertySetInfo( ) +{ + SolarMutexGuard aGuard; + return mpPropSet->getPropertySetInfo(); +} + +void SAL_CALL SvxUnoTextField::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue ) +{ + SolarMutexGuard aGuard; + + if( mpImpl == nullptr ) + throw uno::RuntimeException(); + + if (aPropertyName == UNO_TC_PROP_ANCHOR) + { + aValue >>= mxAnchor; + return; + } + + const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMap().getByName( aPropertyName ); + if ( !pMap ) + throw beans::UnknownPropertyException(aPropertyName); + + switch( pMap->nWID ) + { + case WID_DATE: + if(aValue >>= mpImpl->maDateTime) + return; + break; + case WID_BOOL1: + if(aValue >>= mpImpl->mbBoolean1) + return; + break; + case WID_BOOL2: + if(aValue >>= mpImpl->mbBoolean2) + return; + break; + case WID_INT16: + if(aValue >>= mpImpl->mnInt16) + return; + break; + case WID_INT32: + if(aValue >>= mpImpl->mnInt32) + return; + break; + case WID_STRING1: + if(aValue >>= mpImpl->msString1) + return; + break; + case WID_STRING2: + if(aValue >>= mpImpl->msString2) + return; + break; + case WID_STRING3: + if(aValue >>= mpImpl->msString3) + return; + break; + } + + throw lang::IllegalArgumentException(); +} + +uno::Any SAL_CALL SvxUnoTextField::getPropertyValue( const OUString& PropertyName ) +{ + SolarMutexGuard aGuard; + + if (PropertyName == UNO_TC_PROP_ANCHOR) + return uno::Any(mxAnchor); + + if (PropertyName == UNO_TC_PROP_TEXTFIELD_TYPE) + return uno::Any(mnServiceId); + + uno::Any aValue; + + const SfxItemPropertyMapEntry* pMap = mpPropSet->getPropertyMap().getByName( PropertyName ); + if ( !pMap ) + throw beans::UnknownPropertyException(PropertyName); + + switch( pMap->nWID ) + { + case WID_DATE: + aValue <<= mpImpl->maDateTime; + break; + case WID_BOOL1: + aValue <<= mpImpl->mbBoolean1; + break; + case WID_BOOL2: + aValue <<= mpImpl->mbBoolean2; + break; + case WID_INT16: + aValue <<= mpImpl->mnInt16; + break; + case WID_INT32: + aValue <<= mpImpl->mnInt32; + break; + case WID_STRING1: + aValue <<= mpImpl->msString1; + break; + case WID_STRING2: + aValue <<= mpImpl->msString2; + break; + case WID_STRING3: + aValue <<= mpImpl->msString3; + break; + } + + return aValue; +} + +void SAL_CALL SvxUnoTextField::addPropertyChangeListener( const OUString&, const uno::Reference< beans::XPropertyChangeListener >& ) {} +void SAL_CALL SvxUnoTextField::removePropertyChangeListener( const OUString&, const uno::Reference< beans::XPropertyChangeListener >& ) {} +void SAL_CALL SvxUnoTextField::addVetoableChangeListener( const OUString&, const uno::Reference< beans::XVetoableChangeListener >& ) {} +void SAL_CALL SvxUnoTextField::removeVetoableChangeListener( const OUString&, const uno::Reference< beans::XVetoableChangeListener >& ) {} + +// OComponentHelper +void SvxUnoTextField::disposing() +{ + // nothing to do +} + +// lang::XServiceInfo +OUString SAL_CALL SvxUnoTextField::getImplementationName() +{ + return "SvxUnoTextField"; +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextField::getSupportedServiceNames() +{ + uno::Sequence<OUString> aSeq(4); + OUString* pServices = aSeq.getArray(); + pServices[0] = "com.sun.star.text.TextContent"; + pServices[1] = "com.sun.star.text.TextField"; + + switch (mnServiceId) + { + case text::textfield::Type::DATE: + pServices[2] = "com.sun.star.text.TextField.DateTime"; + pServices[3] = "com.sun.star.text.textfield.DateTime"; + break; + case text::textfield::Type::URL: + pServices[2] = "com.sun.star.text.TextField.URL"; + pServices[3] = "com.sun.star.text.textfield.URL"; + break; + case text::textfield::Type::PAGE: + pServices[2] = "com.sun.star.text.TextField.PageNumber"; + pServices[3] = "com.sun.star.text.textfield.PageNumber"; + break; + case text::textfield::Type::PAGES: + pServices[2] = "com.sun.star.text.TextField.PageCount"; + pServices[3] = "com.sun.star.text.textfield.PageCount"; + break; + case text::textfield::Type::TIME: + pServices[2] = "com.sun.star.text.TextField.DateTime"; + pServices[3] = "com.sun.star.text.textfield.DateTime"; + break; + case text::textfield::Type::DOCINFO_TITLE: + pServices[2] = "com.sun.star.text.TextField.docinfo.Title"; + pServices[3] = "com.sun.star.text.textfield.docinfo.Title"; + break; + case text::textfield::Type::TABLE: + pServices[2] = "com.sun.star.text.TextField.SheetName"; + pServices[3] = "com.sun.star.text.textfield.SheetName"; + break; + case text::textfield::Type::EXTENDED_TIME: + pServices[2] = "com.sun.star.text.TextField.DateTime"; + pServices[3] = "com.sun.star.text.textfield.DateTime"; + break; + case text::textfield::Type::EXTENDED_FILE: + pServices[2] = "com.sun.star.text.TextField.FileName"; + pServices[3] = "com.sun.star.text.textfield.FileName"; + break; + case text::textfield::Type::AUTHOR: + pServices[2] = "com.sun.star.text.TextField.Author"; + pServices[3] = "com.sun.star.text.textfield.Author"; + break; + case text::textfield::Type::MEASURE: + pServices[2] = "com.sun.star.text.TextField.Measure"; + pServices[3] = "com.sun.star.text.textfield.Measure"; + break; + case text::textfield::Type::PRESENTATION_HEADER: + pServices[2] = "com.sun.star.presentation.TextField.Header"; + pServices[3] = "com.sun.star.presentation.textfield.Header"; + break; + case text::textfield::Type::PRESENTATION_FOOTER: + pServices[2] = "com.sun.star.presentation.TextField.Footer"; + pServices[3] = "com.sun.star.presentation.textfield.Footer"; + break; + case text::textfield::Type::PRESENTATION_DATE_TIME: + pServices[2] = "com.sun.star.presentation.TextField.DateTime"; + pServices[3] = "com.sun.star.presentation.textfield.DateTime"; + break; + case text::textfield::Type::PAGE_NAME: + pServices[2] = "com.sun.star.text.TextField.PageName"; + pServices[3] = "com.sun.star.text.textfield.PageName"; + break; + case text::textfield::Type::DOCINFO_CUSTOM: + pServices[2] = "com.sun.star.text.TextField.DocInfo.Custom"; + pServices[3] = "com.sun.star.text.textfield.DocInfo.Custom"; + break; + default: + aSeq.realloc(0); + } + + return aSeq; +} + +sal_Bool SAL_CALL SvxUnoTextField::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +uno::Reference< uno::XInterface > SvxUnoTextCreateTextField( std::u16string_view ServiceSpecifier ) +{ + uno::Reference< uno::XInterface > xRet; + + // #i93308# up to OOo 3.2 we used this wrong namespace name with the capital T & F. This is + // fixed since OOo 3.2 but for compatibility we will still provide support for the wrong notation. + + std::u16string_view aFieldType; + if( (o3tl::starts_with( ServiceSpecifier, u"com.sun.star.text.textfield.", &aFieldType )) || + (o3tl::starts_with( ServiceSpecifier, u"com.sun.star.text.TextField.", &aFieldType )) ) + { + sal_Int32 nId = text::textfield::Type::UNSPECIFIED; + + if ( aFieldType == u"DateTime" ) + { + nId = text::textfield::Type::DATE; + } + else if ( aFieldType == u"URL" ) + { + nId = text::textfield::Type::URL; + } + else if ( aFieldType == u"PageNumber" ) + { + nId = text::textfield::Type::PAGE; + } + else if ( aFieldType == u"PageCount" ) + { + nId = text::textfield::Type::PAGES; + } + else if ( aFieldType == u"SheetName" ) + { + nId = text::textfield::Type::TABLE; + } + else if ( aFieldType == u"FileName" ) + { + nId = text::textfield::Type::EXTENDED_FILE; + } + else if (aFieldType == u"docinfo.Title" || + aFieldType == u"DocInfo.Title" ) + { + nId = text::textfield::Type::DOCINFO_TITLE; + } + else if ( aFieldType == u"Author" ) + { + nId = text::textfield::Type::AUTHOR; + } + else if ( aFieldType == u"Measure" ) + { + nId = text::textfield::Type::MEASURE; + } + else if (aFieldType == u"DocInfo.Custom") + { + nId = text::textfield::Type::DOCINFO_CUSTOM; + } + + if (nId != text::textfield::Type::UNSPECIFIED) + xRet = getXWeak(new SvxUnoTextField( nId )); + } + + return xRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unofored.cxx b/editeng/source/uno/unofored.cxx new file mode 100644 index 0000000000..66f4fde2bf --- /dev/null +++ b/editeng/source/uno/unofored.cxx @@ -0,0 +1,520 @@ +/* -*- 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 <osl/diagnose.h> +#include <tools/debug.hxx> +#include <editeng/eeitem.hxx> +#include <com/sun/star/i18n/WordType.hpp> + +#include <svl/itemset.hxx> +#include <editeng/editeng.hxx> +#include <editeng/unoedhlp.hxx> +#include <editeng/editdata.hxx> +#include <editeng/outliner.hxx> +#include <editeng/editobj.hxx> + +#include <editeng/unofored.hxx> +#include "unofored_internal.hxx" + +using namespace ::com::sun::star; + + +SvxEditEngineForwarder::SvxEditEngineForwarder( EditEngine& rEngine ) : + rEditEngine( rEngine ) +{ +} + +SvxEditEngineForwarder::~SvxEditEngineForwarder() +{ + // the EditEngine may need to be deleted from the outside +} + +sal_Int32 SvxEditEngineForwarder::GetParagraphCount() const +{ + return rEditEngine.GetParagraphCount(); +} + +sal_Int32 SvxEditEngineForwarder::GetTextLen( sal_Int32 nParagraph ) const +{ + return rEditEngine.GetTextLen( nParagraph ); +} + +OUString SvxEditEngineForwarder::GetText( const ESelection& rSel ) const +{ + return convertLineEnd(rEditEngine.GetText(rSel), GetSystemLineEnd()); +} + +SfxItemSet SvxEditEngineForwarder::GetAttribs( const ESelection& rSel, EditEngineAttribs nOnlyHardAttrib ) const +{ + if( rSel.nStartPara == rSel.nEndPara ) + { + GetAttribsFlags nFlags = GetAttribsFlags::NONE; + switch( nOnlyHardAttrib ) + { + case EditEngineAttribs::All: + nFlags = GetAttribsFlags::ALL; + break; + case EditEngineAttribs::OnlyHard: + nFlags = GetAttribsFlags::CHARATTRIBS; + break; + default: + OSL_FAIL("unknown flags for SvxOutlinerForwarder::GetAttribs"); + } + + return rEditEngine.GetAttribs( rSel.nStartPara, rSel.nStartPos, rSel.nEndPos, nFlags ); + } + else + { + return rEditEngine.GetAttribs( rSel, nOnlyHardAttrib ); + } +} + +SfxItemSet SvxEditEngineForwarder::GetParaAttribs( sal_Int32 nPara ) const +{ + SfxItemSet aSet( rEditEngine.GetParaAttribs( nPara ) ); + + sal_uInt16 nWhich = EE_PARA_START; + while( nWhich <= EE_PARA_END ) + { + if( aSet.GetItemState( nWhich ) != SfxItemState::SET ) + { + if( rEditEngine.HasParaAttrib( nPara, nWhich ) ) + aSet.Put( rEditEngine.GetParaAttrib( nPara, nWhich ) ); + } + nWhich++; + } + + return aSet; +} + +void SvxEditEngineForwarder::SetParaAttribs( sal_Int32 nPara, const SfxItemSet& rSet ) +{ + rEditEngine.SetParaAttribs( nPara, rSet ); +} + +void SvxEditEngineForwarder::RemoveAttribs( const ESelection& rSelection ) +{ + rEditEngine.RemoveAttribs( rSelection, false/*bRemoveParaAttribs*/, 0 ); +} + +SfxItemPool* SvxEditEngineForwarder::GetPool() const +{ + return rEditEngine.GetEmptyItemSet().GetPool(); +} + +void SvxEditEngineForwarder::GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& rList ) const +{ + rEditEngine.GetPortions( nPara, rList ); +} + +OUString SvxEditEngineForwarder::GetStyleSheet(sal_Int32 nPara) const +{ + if (auto pStyle = rEditEngine.GetStyleSheet(nPara)) + return pStyle->GetName(); + return OUString(); +} + +void SvxEditEngineForwarder::SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) +{ + auto pStyleSheetPool = rEditEngine.GetStyleSheetPool(); + if (auto pStyle = pStyleSheetPool ? pStyleSheetPool->Find(rStyleName, SfxStyleFamily::Para) : nullptr) + rEditEngine.SetStyleSheet(nPara, static_cast<SfxStyleSheet*>(pStyle)); +} + +void SvxEditEngineForwarder::QuickInsertText( const OUString& rText, const ESelection& rSel ) +{ + rEditEngine.QuickInsertText( rText, rSel ); +} + +void SvxEditEngineForwarder::QuickInsertLineBreak( const ESelection& rSel ) +{ + rEditEngine.QuickInsertLineBreak( rSel ); +} + +void SvxEditEngineForwarder::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel ) +{ + rEditEngine.QuickInsertField( rFld, rSel ); +} + +void SvxEditEngineForwarder::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel ) +{ + rEditEngine.QuickSetAttribs( rSet, rSel ); +} + +bool SvxEditEngineForwarder::IsValid() const +{ + // cannot reliably query EditEngine state + // while in the middle of an update + return rEditEngine.IsUpdateLayout(); +} + +OUString SvxEditEngineForwarder::CalcFieldValue( const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos, std::optional<Color>& rpTxtColor, std::optional<Color>& rpFldColor, std::optional<FontLineStyle>& rpFldLineStyle ) +{ + return rEditEngine.CalcFieldValue( rField, nPara, nPos, rpTxtColor, rpFldColor, rpFldLineStyle ); +} + +void SvxEditEngineForwarder::FieldClicked( const SvxFieldItem& rField ) +{ + rEditEngine.FieldClicked( rField ); +} + +SfxItemState GetSvxEditEngineItemState( EditEngine const & rEditEngine, const ESelection& rSel, sal_uInt16 nWhich ) +{ + std::vector<EECharAttrib> aAttribs; + + const SfxPoolItem* pLastItem = nullptr; + + SfxItemState eState = SfxItemState::DEFAULT; + + // check all paragraphs inside the selection + for( sal_Int32 nPara = rSel.nStartPara; nPara <= rSel.nEndPara; nPara++ ) + { + SfxItemState eParaState = SfxItemState::DEFAULT; + + // calculate start and endpos for this paragraph + sal_Int32 nPos = 0; + if( rSel.nStartPara == nPara ) + nPos = rSel.nStartPos; + + sal_Int32 nEndPos = rSel.nEndPos; + if( rSel.nEndPara != nPara ) + nEndPos = rEditEngine.GetTextLen( nPara ); + + + // get list of char attribs + rEditEngine.GetCharAttribs( nPara, aAttribs ); + + bool bEmpty = true; // we found no item inside the selection of this paragraph + bool bGaps = false; // we found items but there are gaps between them + sal_Int32 nLastEnd = nPos; + + const SfxPoolItem* pParaItem = nullptr; + + for (auto const& attrib : aAttribs) + { + DBG_ASSERT(attrib.pAttr, "GetCharAttribs gives corrupt data"); + + const bool bEmptyPortion = attrib.nStart == attrib.nEnd; + if((!bEmptyPortion && attrib.nStart >= nEndPos) || + (bEmptyPortion && attrib.nStart > nEndPos)) + break; // break if we are already behind our selection + + if((!bEmptyPortion && attrib.nEnd <= nPos) || + (bEmptyPortion && attrib.nEnd < nPos)) + continue; // or if the attribute ends before our selection + + if(attrib.pAttr->Which() != nWhich) + continue; // skip if is not the searched item + + // if we already found an item + if( pParaItem ) + { + // ... and its different to this one than the state is don't care + if(*pParaItem != *(attrib.pAttr)) + return SfxItemState::DONTCARE; + } + else + pParaItem = attrib.pAttr; + + if( bEmpty ) + bEmpty = false; + + if(!bGaps && attrib.nStart > nLastEnd) + bGaps = true; + + nLastEnd = attrib.nEnd; + } + + if( !bEmpty && !bGaps && nLastEnd < ( nEndPos - 1 ) ) + bGaps = true; + + if( bEmpty ) + eParaState = SfxItemState::DEFAULT; + else if( bGaps ) + eParaState = SfxItemState::DONTCARE; + else + eParaState = SfxItemState::SET; + + // if we already found an item check if we found the same + if( pLastItem ) + { + if( (pParaItem == nullptr) || (*pLastItem != *pParaItem) ) + return SfxItemState::DONTCARE; + } + else + { + pLastItem = pParaItem; + eState = eParaState; + } + } + + return eState; +} + +SfxItemState SvxEditEngineForwarder::GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const +{ + return GetSvxEditEngineItemState( rEditEngine, rSel, nWhich ); +} + +SfxItemState SvxEditEngineForwarder::GetItemState( sal_Int32 nPara, sal_uInt16 nWhich ) const +{ + const SfxItemSet& rSet = rEditEngine.GetParaAttribs( nPara ); + return rSet.GetItemState( nWhich ); +} + +LanguageType SvxEditEngineForwarder::GetLanguage( sal_Int32 nPara, sal_Int32 nIndex ) const +{ + return rEditEngine.GetLanguage(nPara, nIndex).nLang; +} + +sal_Int32 SvxEditEngineForwarder::GetFieldCount( sal_Int32 nPara ) const +{ + return rEditEngine.GetFieldCount(nPara); +} + +EFieldInfo SvxEditEngineForwarder::GetFieldInfo( sal_Int32 nPara, sal_uInt16 nField ) const +{ + return rEditEngine.GetFieldInfo( nPara, nField ); +} + +EBulletInfo SvxEditEngineForwarder::GetBulletInfo( sal_Int32 ) const +{ + return EBulletInfo(); +} + +tools::Rectangle SvxEditEngineForwarder::GetCharBounds( sal_Int32 nPara, sal_Int32 nIndex ) const +{ + // EditEngine's 'internal' methods like GetCharacterBounds() + // don't rotate for vertical text. + Size aSize( rEditEngine.CalcTextWidth(), rEditEngine.GetTextHeight() ); + // swap width and height + tools::Long tmp = aSize.Width(); + aSize.setWidth(aSize.Height()); + aSize.setHeight(tmp); + bool bIsVertical( rEditEngine.IsEffectivelyVertical() ); + + // #108900# Handle virtual position one-past-the end of the string + if( nIndex >= rEditEngine.GetTextLen(nPara) ) + { + tools::Rectangle aLast; + + if( nIndex ) + { + // use last character, if possible + aLast = rEditEngine.GetCharacterBounds( EPosition(nPara, nIndex-1) ); + + // move at end of this last character, make one pixel wide + aLast.Move( aLast.Right() - aLast.Left(), 0 ); + aLast.SetSize( Size(1, aLast.GetHeight()) ); + + // take care for CTL + aLast = SvxEditSourceHelper::EEToUserSpace( aLast, aSize, bIsVertical ); + } + else + { + // #109864# Bounds must lie within the paragraph + aLast = GetParaBounds( nPara ); + + // #109151# Don't use paragraph height, but line height + // instead. aLast is already CTL-correct + if( bIsVertical) + aLast.SetSize( Size( rEditEngine.GetLineHeight(nPara), 1 ) ); + else + aLast.SetSize( Size( 1, rEditEngine.GetLineHeight(nPara) ) ); + } + + return aLast; + } + else + { + return SvxEditSourceHelper::EEToUserSpace( rEditEngine.GetCharacterBounds( EPosition(nPara, nIndex) ), + aSize, bIsVertical ); + } +} + +tools::Rectangle SvxEditEngineForwarder::GetParaBounds( sal_Int32 nPara ) const +{ + const Point aPnt = rEditEngine.GetDocPosTopLeft( nPara ); + sal_uInt32 nWidth; + sal_uInt32 nHeight; + + if( rEditEngine.IsEffectivelyVertical() ) + { + // Hargl. EditEngine's 'external' methods return the rotated + // dimensions, 'internal' methods like GetTextHeight( n ) + // don't rotate. + nWidth = rEditEngine.GetTextHeight( nPara ); + nHeight = rEditEngine.GetTextHeight(); + sal_uInt32 nTextWidth = rEditEngine.GetTextHeight(); + + return tools::Rectangle( nTextWidth - aPnt.Y() - nWidth, 0, nTextWidth - aPnt.Y(), nHeight ); + } + else + { + nWidth = rEditEngine.CalcTextWidth(); + nHeight = rEditEngine.GetTextHeight( nPara ); + + return tools::Rectangle( 0, aPnt.Y(), nWidth, aPnt.Y() + nHeight ); + } +} + +MapMode SvxEditEngineForwarder::GetMapMode() const +{ + return rEditEngine.GetRefMapMode(); +} + +OutputDevice* SvxEditEngineForwarder::GetRefDevice() const +{ + return rEditEngine.GetRefDevice(); +} + +bool SvxEditEngineForwarder::GetIndexAtPoint( const Point& rPos, sal_Int32& nPara, sal_Int32& nIndex ) const +{ + Size aSize( rEditEngine.CalcTextWidth(), rEditEngine.GetTextHeight() ); + // swap width and height + tools::Long tmp = aSize.Width(); + aSize.setWidth(aSize.Height()); + aSize.setHeight(tmp); + Point aEEPos( SvxEditSourceHelper::UserSpaceToEE( rPos, + aSize, + rEditEngine.IsEffectivelyVertical() )); + + EPosition aDocPos = rEditEngine.FindDocPosition( aEEPos ); + + nPara = aDocPos.nPara; + nIndex = aDocPos.nIndex; + + return true; +} + +bool SvxEditEngineForwarder::GetWordIndices( sal_Int32 nPara, sal_Int32 nIndex, sal_Int32& nStart, sal_Int32& nEnd ) const +{ + ESelection aRes = rEditEngine.GetWord( ESelection(nPara, nIndex, nPara, nIndex), css::i18n::WordType::DICTIONARY_WORD ); + + if( aRes.nStartPara == nPara && + aRes.nStartPara == aRes.nEndPara ) + { + nStart = aRes.nStartPos; + nEnd = aRes.nEndPos; + + return true; + } + + return false; +} + +bool SvxEditEngineForwarder::GetAttributeRun( sal_Int32& nStartIndex, sal_Int32& nEndIndex, sal_Int32 nPara, sal_Int32 nIndex, bool bInCell ) const +{ + SvxEditSourceHelper::GetAttributeRun( nStartIndex, nEndIndex, rEditEngine, nPara, nIndex, bInCell ); + return true; +} + +sal_Int32 SvxEditEngineForwarder::GetLineCount( sal_Int32 nPara ) const +{ + return rEditEngine.GetLineCount(nPara); +} + +sal_Int32 SvxEditEngineForwarder::GetLineLen( sal_Int32 nPara, sal_Int32 nLine ) const +{ + return rEditEngine.GetLineLen(nPara, nLine); +} + +void SvxEditEngineForwarder::GetLineBoundaries( /*out*/sal_Int32 &rStart, /*out*/sal_Int32 &rEnd, sal_Int32 nPara, sal_Int32 nLine ) const +{ + rEditEngine.GetLineBoundaries(rStart, rEnd, nPara, nLine); +} + +sal_Int32 SvxEditEngineForwarder::GetLineNumberAtIndex( sal_Int32 nPara, sal_Int32 nIndex ) const +{ + return rEditEngine.GetLineNumberAtIndex(nPara, nIndex); +} + + +bool SvxEditEngineForwarder::QuickFormatDoc( bool ) +{ + rEditEngine.QuickFormatDoc(); + + return true; +} + +bool SvxEditEngineForwarder::Delete( const ESelection& rSelection ) +{ + rEditEngine.QuickDelete( rSelection ); + rEditEngine.QuickFormatDoc(); + + return true; +} + +bool SvxEditEngineForwarder::InsertText( const OUString& rStr, const ESelection& rSelection ) +{ + rEditEngine.QuickInsertText( rStr, rSelection ); + rEditEngine.QuickFormatDoc(); + + return true; +} + +sal_Int16 SvxEditEngineForwarder::GetDepth( sal_Int32 ) const +{ + // EditEngine does not support outline depth + return -1; +} + +bool SvxEditEngineForwarder::SetDepth( sal_Int32, sal_Int16 nNewDepth ) +{ + // EditEngine does not support outline depth + return nNewDepth == -1; +} + +const SfxItemSet * SvxEditEngineForwarder::GetEmptyItemSetPtr() +{ + return &rEditEngine.GetEmptyItemSet(); +} + +void SvxEditEngineForwarder::AppendParagraph() +{ + rEditEngine.InsertParagraph( rEditEngine.GetParagraphCount(), OUString() ); +} + +sal_Int32 SvxEditEngineForwarder::AppendTextPortion( sal_Int32 nPara, const OUString &rText, const SfxItemSet & /*rSet*/ ) +{ + sal_Int32 nLen = 0; + + sal_Int32 nParaCount = rEditEngine.GetParagraphCount(); + DBG_ASSERT( nPara < nParaCount, "paragraph index out of bounds" ); + if (0 <= nPara && nPara < nParaCount) + { + nLen = rEditEngine.GetTextLen( nPara ); + rEditEngine.QuickInsertText( rText, ESelection( nPara, nLen, nPara, nLen ) ); + } + + return nLen; +} + +void SvxEditEngineForwarder::CopyText(const SvxTextForwarder& rSource) +{ + const SvxEditEngineForwarder* pSourceForwarder = dynamic_cast< const SvxEditEngineForwarder* >( &rSource ); + if( !pSourceForwarder ) + return; + std::unique_ptr<EditTextObject> pNewTextObject = pSourceForwarder->rEditEngine.CreateTextObject(); + rEditEngine.SetText( *pNewTextObject ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unofored_internal.hxx b/editeng/source/uno/unofored_internal.hxx new file mode 100644 index 0000000000..cadb194159 --- /dev/null +++ b/editeng/source/uno/unofored_internal.hxx @@ -0,0 +1,28 @@ +/* -*- 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 . + */ + +#pragma once + +#include <editeng/editeng.hxx> +#include <svl/poolitem.hxx> + +SfxItemState GetSvxEditEngineItemState( EditEngine const & rEditEngine, const ESelection& rSel, sal_uInt16 nWhich ); + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unoforou.cxx b/editeng/source/uno/unoforou.cxx new file mode 100644 index 0000000000..8772ff9a77 --- /dev/null +++ b/editeng/source/uno/unoforou.cxx @@ -0,0 +1,582 @@ +/* -*- 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 <osl/diagnose.h> +#include <tools/debug.hxx> +#include <svl/style.hxx> +#include <com/sun/star/i18n/WordType.hpp> + +#include <svl/itemset.hxx> +#include <editeng/editeng.hxx> +#include <editeng/editdata.hxx> +#include <editeng/outliner.hxx> +#include <editeng/unoedhlp.hxx> +#include <svl/poolitem.hxx> + +#include <editeng/unoforou.hxx> +#include <editeng/outlobj.hxx> +#include "unofored_internal.hxx" + +using namespace ::com::sun::star; + + +SvxOutlinerForwarder::SvxOutlinerForwarder( Outliner& rOutl, bool bOutlText /* = false */ ) : + rOutliner( rOutl ), + bOutlinerText( bOutlText ), + mnParaAttribsCache( 0 ) +{ +} + +SvxOutlinerForwarder::~SvxOutlinerForwarder() +{ + flushCache(); +} + +sal_Int32 SvxOutlinerForwarder::GetParagraphCount() const +{ + return rOutliner.GetParagraphCount(); +} + +sal_Int32 SvxOutlinerForwarder::GetTextLen( sal_Int32 nParagraph ) const +{ + return rOutliner.GetEditEngine().GetTextLen( nParagraph ); +} + +OUString SvxOutlinerForwarder::GetText( const ESelection& rSel ) const +{ + //! GetText (ESelection) should probably also be in the Outliner + // in the time being use as the hack for the EditEngine: + EditEngine* pEditEngine = const_cast<EditEngine*>(&rOutliner.GetEditEngine()); + return pEditEngine->GetText( rSel ); +} + +static SfxItemSet ImplOutlinerForwarderGetAttribs( const ESelection& rSel, EditEngineAttribs nOnlyHardAttrib, EditEngine& rEditEngine ) +{ + if( rSel.nStartPara == rSel.nEndPara ) + { + GetAttribsFlags nFlags = GetAttribsFlags::NONE; + + switch( nOnlyHardAttrib ) + { + case EditEngineAttribs::All: + nFlags = GetAttribsFlags::ALL; + break; + case EditEngineAttribs::OnlyHard: + nFlags = GetAttribsFlags::CHARATTRIBS; + break; + default: + OSL_FAIL("unknown flags for SvxOutlinerForwarder::GetAttribs"); + } + return rEditEngine.GetAttribs( rSel.nStartPara, rSel.nStartPos, rSel.nEndPos, nFlags ); + } + else + { + return rEditEngine.GetAttribs( rSel, nOnlyHardAttrib ); + } +} + +SfxItemSet SvxOutlinerForwarder::GetAttribs( const ESelection& rSel, EditEngineAttribs nOnlyHardAttrib ) const +{ + if( moAttribsCache && ( EditEngineAttribs::All == nOnlyHardAttrib ) ) + { + // have we the correct set in cache? + if( maAttribCacheSelection == rSel ) + { + // yes! just return the cache + return *moAttribsCache; + } + else + { + // no, we need delete the old cache + moAttribsCache.reset(); + } + } + + //! Does it not exist on the Outliner? + //! and why is the GetAttribs on the EditEngine not a const? + EditEngine& rEditEngine = const_cast<EditEngine&>(rOutliner.GetEditEngine()); + + SfxItemSet aSet( ImplOutlinerForwarderGetAttribs( rSel, nOnlyHardAttrib, rEditEngine ) ); + + if( EditEngineAttribs::All == nOnlyHardAttrib ) + { + moAttribsCache.emplace( aSet ); + maAttribCacheSelection = rSel; + } + + SfxStyleSheet* pStyle = rEditEngine.GetStyleSheet( rSel.nStartPara ); + if( pStyle ) + aSet.SetParent( &(pStyle->GetItemSet() ) ); + + return aSet; +} + +SfxItemSet SvxOutlinerForwarder::GetParaAttribs( sal_Int32 nPara ) const +{ + if( moParaAttribsCache ) + { + // have we the correct set in cache? + if( nPara == mnParaAttribsCache ) + { + // yes! just return the cache + return *moParaAttribsCache; + } + else + { + // no, we need delete the old cache + moParaAttribsCache.reset(); + } + } + + moParaAttribsCache.emplace( rOutliner.GetParaAttribs( nPara ) ); + mnParaAttribsCache = nPara; + + EditEngine& rEditEngine = const_cast<EditEngine&>(rOutliner.GetEditEngine()); + + SfxStyleSheet* pStyle = rEditEngine.GetStyleSheet( nPara ); + if( pStyle ) + moParaAttribsCache->SetParent( &(pStyle->GetItemSet() ) ); + + return *moParaAttribsCache; +} + +void SvxOutlinerForwarder::SetParaAttribs( sal_Int32 nPara, const SfxItemSet& rSet ) +{ + flushCache(); + + const SfxItemSet* pOldParent = rSet.GetParent(); + if( pOldParent ) + const_cast<SfxItemSet*>(&rSet)->SetParent( nullptr ); + + rOutliner.SetParaAttribs( nPara, rSet ); + + if( pOldParent ) + const_cast<SfxItemSet*>(&rSet)->SetParent( pOldParent ); +} + +void SvxOutlinerForwarder::RemoveAttribs( const ESelection& rSelection ) +{ + rOutliner.RemoveAttribs( rSelection, false/*bRemoveParaAttribs*/, 0 ); +} + +SfxItemPool* SvxOutlinerForwarder::GetPool() const +{ + return rOutliner.GetEmptyItemSet().GetPool(); +} + +void SvxOutlinerForwarder::GetPortions( sal_Int32 nPara, std::vector<sal_Int32>& rList ) const +{ + const_cast<EditEngine&>(rOutliner.GetEditEngine()).GetPortions( nPara, rList ); +} + +OUString SvxOutlinerForwarder::GetStyleSheet(sal_Int32 nPara) const +{ + if (auto pStyle = rOutliner.GetStyleSheet(nPara)) + return pStyle->GetName(); + return OUString(); +} + +void SvxOutlinerForwarder::SetStyleSheet(sal_Int32 nPara, const OUString& rStyleName) +{ + auto pStyleSheetPool = rOutliner.GetStyleSheetPool(); + if (auto pStyle = pStyleSheetPool ? pStyleSheetPool->Find(rStyleName, SfxStyleFamily::Para) : nullptr) + rOutliner.SetStyleSheet(nPara, static_cast<SfxStyleSheet*>(pStyle)); +} + +void SvxOutlinerForwarder::QuickInsertText( const OUString& rText, const ESelection& rSel ) +{ + flushCache(); + if( rText.isEmpty() ) + { + rOutliner.QuickDelete( rSel ); + } + else + { + rOutliner.QuickInsertText( rText, rSel ); + } +} + +void SvxOutlinerForwarder::QuickInsertLineBreak( const ESelection& rSel ) +{ + flushCache(); + rOutliner.QuickInsertLineBreak( rSel ); +} + +void SvxOutlinerForwarder::QuickInsertField( const SvxFieldItem& rFld, const ESelection& rSel ) +{ + flushCache(); + rOutliner.QuickInsertField( rFld, rSel ); +} + +void SvxOutlinerForwarder::QuickSetAttribs( const SfxItemSet& rSet, const ESelection& rSel ) +{ + flushCache(); + rOutliner.QuickSetAttribs( rSet, rSel ); +} + +OUString SvxOutlinerForwarder::CalcFieldValue( const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos, std::optional<Color>& rpTxtColor, std::optional<Color>& rpFldColor, std::optional<FontLineStyle>& rpFldLineStyle ) +{ + return rOutliner.CalcFieldValue( rField, nPara, nPos, rpTxtColor, rpFldColor, rpFldLineStyle ); +} + +void SvxOutlinerForwarder::FieldClicked( const SvxFieldItem& /*rField*/ ) +{ +} + +bool SvxOutlinerForwarder::IsValid() const +{ + // cannot reliably query outliner state + // while in the middle of an update + return rOutliner.IsUpdateLayout(); +} + +SfxItemState SvxOutlinerForwarder::GetItemState( const ESelection& rSel, sal_uInt16 nWhich ) const +{ + return GetSvxEditEngineItemState( rOutliner.GetEditEngine(), rSel, nWhich ); +} + +SfxItemState SvxOutlinerForwarder::GetItemState( sal_Int32 nPara, sal_uInt16 nWhich ) const +{ + const SfxItemSet& rSet = rOutliner.GetParaAttribs( nPara ); + return rSet.GetItemState( nWhich ); +} + + +void SvxOutlinerForwarder::flushCache() +{ + moAttribsCache.reset(); + moParaAttribsCache.reset(); +} + +LanguageType SvxOutlinerForwarder::GetLanguage( sal_Int32 nPara, sal_Int32 nIndex ) const +{ + return rOutliner.GetLanguage(nPara, nIndex); +} + +sal_Int32 SvxOutlinerForwarder::GetFieldCount( sal_Int32 nPara ) const +{ + return rOutliner.GetEditEngine().GetFieldCount(nPara); +} + +EFieldInfo SvxOutlinerForwarder::GetFieldInfo( sal_Int32 nPara, sal_uInt16 nField ) const +{ + return rOutliner.GetEditEngine().GetFieldInfo( nPara, nField ); +} + +EBulletInfo SvxOutlinerForwarder::GetBulletInfo( sal_Int32 nPara ) const +{ + return rOutliner.GetBulletInfo( nPara ); +} + +tools::Rectangle SvxOutlinerForwarder::GetCharBounds( sal_Int32 nPara, sal_Int32 nIndex ) const +{ + // EditEngine's 'internal' methods like GetCharacterBounds() + // don't rotate for vertical text. + Size aSize( rOutliner.CalcTextSize() ); + // swap width and height + tools::Long tmp = aSize.Width(); + aSize.setWidth(aSize.Height()); + aSize.setHeight(tmp); + bool bIsVertical( rOutliner.IsVertical() ); + + // #108900# Handle virtual position one-past-the end of the string + if( nIndex >= GetTextLen(nPara) ) + { + tools::Rectangle aLast; + + if( nIndex ) + { + // use last character, if possible + aLast = rOutliner.GetEditEngine().GetCharacterBounds( EPosition(nPara, nIndex-1) ); + + // move at end of this last character, make one pixel wide + aLast.Move( aLast.Right() - aLast.Left(), 0 ); + aLast.SetSize( Size(1, aLast.GetHeight()) ); + + // take care for CTL + aLast = SvxEditSourceHelper::EEToUserSpace( aLast, aSize, bIsVertical ); + } + else + { + // #109864# Bounds must lie within the paragraph + aLast = GetParaBounds( nPara ); + + // #109151# Don't use paragraph height, but line height + // instead. aLast is already CTL-correct + if( bIsVertical) + aLast.SetSize( Size( rOutliner.GetLineHeight(nPara), 1 ) ); + else + aLast.SetSize( Size( 1, rOutliner.GetLineHeight(nPara) ) ); + } + + return aLast; + } + else + { + return SvxEditSourceHelper::EEToUserSpace( rOutliner.GetEditEngine().GetCharacterBounds( EPosition(nPara, nIndex) ), + aSize, bIsVertical ); + } +} + +tools::Rectangle SvxOutlinerForwarder::GetParaBounds( sal_Int32 nPara ) const +{ + return rOutliner.GetParaBounds( nPara ); +} + +MapMode SvxOutlinerForwarder::GetMapMode() const +{ + return rOutliner.GetRefMapMode(); +} + +OutputDevice* SvxOutlinerForwarder::GetRefDevice() const +{ + return rOutliner.GetRefDevice(); +} + +bool SvxOutlinerForwarder::GetIndexAtPoint( const Point& rPos, sal_Int32& nPara, sal_Int32& nIndex ) const +{ + Size aSize( rOutliner.CalcTextSize() ); + // swap width and height + tools::Long tmp = aSize.Width(); + aSize.setWidth(aSize.Height()); + aSize.setHeight(tmp); + Point aEEPos( SvxEditSourceHelper::UserSpaceToEE( rPos, + aSize, + rOutliner.IsVertical() )); + + EPosition aDocPos = rOutliner.GetEditEngine().FindDocPosition( aEEPos ); + + nPara = aDocPos.nPara; + nIndex = aDocPos.nIndex; + + return true; +} + +bool SvxOutlinerForwarder::GetWordIndices( sal_Int32 nPara, sal_Int32 nIndex, sal_Int32& nStart, sal_Int32& nEnd ) const +{ + ESelection aRes = rOutliner.GetEditEngine().GetWord( ESelection(nPara, nIndex, nPara, nIndex), css::i18n::WordType::DICTIONARY_WORD ); + + if( aRes.nStartPara == nPara && + aRes.nStartPara == aRes.nEndPara ) + { + nStart = aRes.nStartPos; + nEnd = aRes.nEndPos; + + return true; + } + + return false; +} + +bool SvxOutlinerForwarder::GetAttributeRun( sal_Int32& nStartIndex, sal_Int32& nEndIndex, sal_Int32 nPara, sal_Int32 nIndex, bool bInCell ) const +{ + SvxEditSourceHelper::GetAttributeRun( nStartIndex, nEndIndex, rOutliner.GetEditEngine(), nPara, nIndex, bInCell ); + return true; +} + +sal_Int32 SvxOutlinerForwarder::GetLineCount( sal_Int32 nPara ) const +{ + return rOutliner.GetLineCount(nPara); +} + +sal_Int32 SvxOutlinerForwarder::GetLineLen( sal_Int32 nPara, sal_Int32 nLine ) const +{ + return rOutliner.GetLineLen(nPara, nLine); +} + +void SvxOutlinerForwarder::GetLineBoundaries( /*out*/sal_Int32 &rStart, /*out*/sal_Int32 &rEnd, sal_Int32 nPara, sal_Int32 nLine ) const +{ + return rOutliner.GetEditEngine().GetLineBoundaries( rStart, rEnd, nPara, nLine ); +} + +sal_Int32 SvxOutlinerForwarder::GetLineNumberAtIndex( sal_Int32 nPara, sal_Int32 nIndex ) const +{ + return rOutliner.GetEditEngine().GetLineNumberAtIndex( nPara, nIndex ); +} + +bool SvxOutlinerForwarder::QuickFormatDoc( bool ) +{ + rOutliner.QuickFormatDoc(); + + return true; +} + +bool SvxOutlinerForwarder::Delete( const ESelection& rSelection ) +{ + flushCache(); + rOutliner.QuickDelete( rSelection ); + rOutliner.QuickFormatDoc(); + + return true; +} + +bool SvxOutlinerForwarder::InsertText( const OUString& rStr, const ESelection& rSelection ) +{ + flushCache(); + rOutliner.QuickInsertText( rStr, rSelection ); + rOutliner.QuickFormatDoc(); + + return true; +} + +sal_Int16 SvxOutlinerForwarder::GetDepth( sal_Int32 nPara ) const +{ + DBG_ASSERT( 0 <= nPara && nPara < GetParagraphCount(), "SvxOutlinerForwarder::GetDepth: Invalid paragraph index"); + + Paragraph* pPara = rOutliner.GetParagraph( nPara ); + + sal_Int16 nLevel = -1; + + if( pPara ) + nLevel = rOutliner.GetDepth( nPara ); + + return nLevel; +} + +bool SvxOutlinerForwarder::SetDepth( sal_Int32 nPara, sal_Int16 nNewDepth ) +{ + DBG_ASSERT( 0 <= nPara && nPara < GetParagraphCount(), "SvxOutlinerForwarder::SetDepth: Invalid paragraph index"); + + if( (nNewDepth >= -1) && (nNewDepth <= 9) && (0 <= nPara && nPara < GetParagraphCount()) ) + { + Paragraph* pPara = rOutliner.GetParagraph( nPara ); + if( pPara ) + { + rOutliner.SetDepth( pPara, nNewDepth ); + +// const bool bOutlinerText = pSdrObject && (pSdrObject->GetObjInventor() == SdrInventor::Default) && (pSdrObject->GetObjIdentifier() == OBJ_OUTLINETEXT); + if( bOutlinerText ) + rOutliner.SetLevelDependentStyleSheet( nPara ); + + return true; + } + } + + return false; +} + +sal_Int32 SvxOutlinerForwarder::GetNumberingStartValue( sal_Int32 nPara ) +{ + if( 0 <= nPara && nPara < GetParagraphCount() ) + { + return rOutliner.GetNumberingStartValue( nPara ); + } + else + { + OSL_FAIL( "SvxOutlinerForwarder::GetNumberingStartValue)(), Invalid paragraph index"); + return -1; + } +} + +void SvxOutlinerForwarder::SetNumberingStartValue( sal_Int32 nPara, sal_Int32 nNumberingStartValue ) +{ + if( 0 <= nPara && nPara < GetParagraphCount() ) + { + rOutliner.SetNumberingStartValue( nPara, nNumberingStartValue ); + } + else + { + OSL_FAIL( "SvxOutlinerForwarder::SetNumberingStartValue)(), Invalid paragraph index"); + } +} + +bool SvxOutlinerForwarder::IsParaIsNumberingRestart( sal_Int32 nPara ) +{ + if( 0 <= nPara && nPara < GetParagraphCount() ) + { + return rOutliner.IsParaIsNumberingRestart( nPara ); + } + else + { + OSL_FAIL( "SvxOutlinerForwarder::IsParaIsNumberingRestart)(), Invalid paragraph index"); + return false; + } +} + +void SvxOutlinerForwarder::SetParaIsNumberingRestart( sal_Int32 nPara, bool bParaIsNumberingRestart ) +{ + if( 0 <= nPara && nPara < GetParagraphCount() ) + { + rOutliner.SetParaIsNumberingRestart( nPara, bParaIsNumberingRestart ); + } + else + { + OSL_FAIL( "SvxOutlinerForwarder::SetParaIsNumberingRestart)(), Invalid paragraph index"); + } +} + +const SfxItemSet * SvxOutlinerForwarder::GetEmptyItemSetPtr() +{ + EditEngine& rEditEngine = const_cast< EditEngine& >( rOutliner.GetEditEngine() ); + return &rEditEngine.GetEmptyItemSet(); +} + +void SvxOutlinerForwarder::AppendParagraph() +{ + EditEngine& rEditEngine = const_cast< EditEngine& >( rOutliner.GetEditEngine() ); + rEditEngine.InsertParagraph( rEditEngine.GetParagraphCount(), OUString() ); +} + +sal_Int32 SvxOutlinerForwarder::AppendTextPortion( sal_Int32 nPara, const OUString &rText, const SfxItemSet & /*rSet*/ ) +{ + sal_Int32 nLen = 0; + + EditEngine& rEditEngine = const_cast< EditEngine& >( rOutliner.GetEditEngine() ); + sal_Int32 nParaCount = rEditEngine.GetParagraphCount(); + DBG_ASSERT( 0 <= nPara && nPara < nParaCount, "paragraph index out of bounds" ); + if (0 <= nPara && nPara < nParaCount) + { + nLen = rEditEngine.GetTextLen( nPara ); + rEditEngine.QuickInsertText( rText, ESelection( nPara, nLen, nPara, nLen ) ); + } + + return nLen; +} + +void SvxOutlinerForwarder::CopyText(const SvxTextForwarder& rSource) +{ + const SvxOutlinerForwarder* pSourceForwarder = dynamic_cast< const SvxOutlinerForwarder* >( &rSource ); + if( !pSourceForwarder ) + return; + std::optional<OutlinerParaObject> pNewOutlinerParaObject = pSourceForwarder->rOutliner.CreateParaObject(); + rOutliner.SetText( *pNewOutlinerParaObject ); +} + + +sal_Int32 SvxTextForwarder::GetNumberingStartValue( sal_Int32 ) +{ + return -1; +} + +void SvxTextForwarder::SetNumberingStartValue( sal_Int32, sal_Int32 ) +{ +} + +bool SvxTextForwarder::IsParaIsNumberingRestart( sal_Int32 ) +{ + return false; +} + +void SvxTextForwarder::SetParaIsNumberingRestart( sal_Int32, bool ) +{ +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unoipset.cxx b/editeng/source/uno/unoipset.cxx new file mode 100644 index 0000000000..4a4dd9f5e5 --- /dev/null +++ b/editeng/source/uno/unoipset.cxx @@ -0,0 +1,333 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <svl/itemprop.hxx> +#include <tools/UnitConversion.hxx> +#include <editeng/unoipset.hxx> +#include <svl/itempool.hxx> +#include <svl/solar.hrc> +#include <o3tl/any.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <algorithm> + +using namespace ::com::sun::star; + + +SvxItemPropertySet::SvxItemPropertySet( std::span<const SfxItemPropertyMapEntry> pMap, SfxItemPool& rItemPool ) +: m_aPropertyMap( pMap ), + mrItemPool( rItemPool ) +{ +} + + +SvxItemPropertySet::~SvxItemPropertySet() +{ +} + + +static bool SvxUnoCheckForPositiveValue( const uno::Any& rVal ) +{ + bool bConvert = true; // the default is that all metric items must be converted + sal_Int32 nValue = 0; + if( rVal >>= nValue ) + bConvert = (nValue > 0); + return bConvert; +} + + +uno::Any SvxItemPropertySet::getPropertyValue( const SfxItemPropertyMapEntry* pMap, const SfxItemSet& rSet, bool bSearchInParent, bool bDontConvertNegativeValues ) +{ + uno::Any aVal; + if(!pMap || !pMap->nWID) + return aVal; + + const SfxPoolItem* pItem = nullptr; + SfxItemPool* pPool = rSet.GetPool(); + (void)rSet.GetItemState( pMap->nWID, bSearchInParent, &pItem ); + if( nullptr == pItem && pPool ) + pItem = &(pPool->GetDefaultItem( pMap->nWID )); + + const MapUnit eMapUnit = pPool ? pPool->GetMetric(pMap->nWID) : MapUnit::Map100thMM; + sal_uInt8 nMemberId = pMap->nMemberId; + if( eMapUnit == MapUnit::Map100thMM ) + nMemberId &= (~CONVERT_TWIPS); + + if(pItem) + { + pItem->QueryValue( aVal, nMemberId ); + if( pMap->nMoreFlags & PropertyMoreFlags::METRIC_ITEM ) + { + if( eMapUnit != MapUnit::Map100thMM ) + { + if ( !bDontConvertNegativeValues || SvxUnoCheckForPositiveValue( aVal ) ) + SvxUnoConvertToMM( eMapUnit, aVal ); + } + } + else if ( pMap->aType.getTypeClass() == uno::TypeClass_ENUM && + aVal.getValueType() == ::cppu::UnoType<sal_Int32>::get() ) + { + // convert typeless SfxEnumItem to enum type + sal_Int32 nEnum; + aVal >>= nEnum; + aVal.setValue( &nEnum, pMap->aType ); + } + } + else + { + OSL_FAIL( "No SfxPoolItem found for property!" ); + } + + return aVal; +} + + +void SvxItemPropertySet::setPropertyValue( const SfxItemPropertyMapEntry* pMap, const uno::Any& rVal, SfxItemSet& rSet, bool bDontConvertNegativeValues ) +{ + if(!pMap || !pMap->nWID) + return; + + // Get item + const SfxPoolItem* pItem = nullptr; + SfxItemState eState = rSet.GetItemState( pMap->nWID, true, &pItem ); + SfxItemPool* pPool = rSet.GetPool(); + + // Put UnoAny in the item value + if(eState < SfxItemState::DEFAULT || pItem == nullptr) + { + if( pPool == nullptr ) + { + OSL_FAIL( "No default item and no pool?" ); + return; + } + + pItem = &pPool->GetDefaultItem( pMap->nWID ); + } + + uno::Any aValue(rVal); + + const MapUnit eMapUnit = pPool ? pPool->GetMetric(pMap->nWID) : MapUnit::Map100thMM; + + // check for needed metric translation + if ((pMap->nMoreFlags & PropertyMoreFlags::METRIC_ITEM) && eMapUnit != MapUnit::Map100thMM) + { + if (!bDontConvertNegativeValues || SvxUnoCheckForPositiveValue(aValue)) + SvxUnoConvertFromMM(eMapUnit, aValue); + } + + std::unique_ptr<SfxPoolItem> pNewItem(pItem->Clone()); + + sal_uInt8 nMemberId = pMap->nMemberId; + if (eMapUnit == MapUnit::Map100thMM) + nMemberId &= (~CONVERT_TWIPS); + + if (pNewItem->PutValue(aValue, nMemberId)) + { + // Set new item in item set + pNewItem->SetWhich(pMap->nWID); + rSet.Put(std::move(pNewItem)); + } +} + + +uno::Any SvxItemPropertySet::getPropertyValue( const SfxItemPropertyMapEntry* pMap, SvxItemPropertySetUsrAnys& rAnys ) const +{ + // Already entered a value? Then finish quickly + uno::Any* pUsrAny = rAnys.GetUsrAnyForID(*pMap); + if(pUsrAny) + return *pUsrAny; + + // No UsrAny detected yet, generate Default entry and return this + const MapUnit eMapUnit = mrItemPool.GetMetric(pMap->nWID); + sal_uInt8 nMemberId = pMap->nMemberId; + if( eMapUnit == MapUnit::Map100thMM ) + nMemberId &= (~CONVERT_TWIPS); + uno::Any aVal; + SfxItemSet aSet( mrItemPool, pMap->nWID, pMap->nWID); + + if( (pMap->nWID < OWN_ATTR_VALUE_START) || (pMap->nWID > OWN_ATTR_VALUE_END ) ) + { + // Get Default from ItemPool + if(SfxItemPool::IsWhich(pMap->nWID)) + aSet.Put(mrItemPool.GetDefaultItem(pMap->nWID)); + } + + if(aSet.Count()) + { + const SfxPoolItem* pItem = nullptr; + SfxItemState eState = aSet.GetItemState( pMap->nWID, true, &pItem ); + if(eState >= SfxItemState::DEFAULT && pItem) + { + pItem->QueryValue( aVal, nMemberId ); + rAnys.AddUsrAnyForID(aVal, *pMap); + } + } + + // check for needed metric translation + if(pMap->nMoreFlags & PropertyMoreFlags::METRIC_ITEM && eMapUnit != MapUnit::Map100thMM) + { + SvxUnoConvertToMM( eMapUnit, aVal ); + } + + if ( pMap->aType.getTypeClass() == uno::TypeClass_ENUM && + aVal.getValueType() == ::cppu::UnoType<sal_Int32>::get() ) + { + sal_Int32 nEnum; + aVal >>= nEnum; + + aVal.setValue( &nEnum, pMap->aType ); + } + + return aVal; +} + + +void SvxItemPropertySet::setPropertyValue( const SfxItemPropertyMapEntry* pMap, const uno::Any& rVal, SvxItemPropertySetUsrAnys& rAnys ) +{ + uno::Any* pUsrAny = rAnys.GetUsrAnyForID(*pMap); + if(!pUsrAny) + rAnys.AddUsrAnyForID(rVal, *pMap); + else + *pUsrAny = rVal; +} + + +const SfxItemPropertyMapEntry* SvxItemPropertySet::getPropertyMapEntry(std::u16string_view rName) const +{ + return m_aPropertyMap.getByName( rName ); + } + + +uno::Reference< beans::XPropertySetInfo > const & SvxItemPropertySet::getPropertySetInfo() const +{ + if( !m_xInfo.is() ) + m_xInfo = new SfxItemPropertySetInfo( m_aPropertyMap ); + return m_xInfo; +} + + +/** converts the given any with a metric to 100th/mm if needed */ +void SvxUnoConvertToMM( const MapUnit eSourceMapUnit, uno::Any & rMetric ) noexcept +{ + // map the metric of the itempool to 100th mm + switch(eSourceMapUnit) + { + case MapUnit::MapTwip : + { + switch( rMetric.getValueTypeClass() ) + { + case uno::TypeClass_BYTE: + rMetric <<= static_cast<sal_Int8>(convertTwipToMm100(*o3tl::forceAccess<sal_Int8>(rMetric))); + break; + case uno::TypeClass_SHORT: + rMetric <<= static_cast<sal_Int16>(convertTwipToMm100(*o3tl::forceAccess<sal_Int16>(rMetric))); + break; + case uno::TypeClass_UNSIGNED_SHORT: + rMetric <<= static_cast<sal_uInt16>(convertTwipToMm100(*o3tl::forceAccess<sal_uInt16>(rMetric))); + break; + case uno::TypeClass_LONG: + rMetric <<= static_cast<sal_Int32>(convertTwipToMm100(*o3tl::forceAccess<sal_Int32>(rMetric))); + break; + case uno::TypeClass_UNSIGNED_LONG: + rMetric <<= static_cast<sal_uInt32>(convertTwipToMm100(*o3tl::forceAccess<sal_uInt32>(rMetric))); + break; + default: + SAL_WARN("editeng", "AW: Missing unit translation to 100th mm, " << OString::number(static_cast<sal_Int32>(rMetric.getValueTypeClass()))); + assert(false); + } + break; + } + default: + { + OSL_FAIL("AW: Missing unit translation to 100th mm!"); + } + } +} + + +/** converts the given any with a metric from 100th/mm to the given metric if needed */ +void SvxUnoConvertFromMM( const MapUnit eDestinationMapUnit, uno::Any & rMetric ) noexcept +{ + switch(eDestinationMapUnit) + { + case MapUnit::MapTwip : + { + switch( rMetric.getValueTypeClass() ) + { + case uno::TypeClass_BYTE: + rMetric <<= static_cast<sal_Int8>(sanitiseMm100ToTwip(*o3tl::forceAccess<sal_Int8>(rMetric))); + break; + case uno::TypeClass_SHORT: + rMetric <<= static_cast<sal_Int16>(sanitiseMm100ToTwip(*o3tl::forceAccess<sal_Int16>(rMetric))); + break; + case uno::TypeClass_UNSIGNED_SHORT: + rMetric <<= static_cast<sal_uInt16>(sanitiseMm100ToTwip(*o3tl::forceAccess<sal_uInt16>(rMetric))); + break; + case uno::TypeClass_LONG: + rMetric <<= static_cast<sal_Int32>(sanitiseMm100ToTwip(*o3tl::forceAccess<sal_Int32>(rMetric))); + break; + case uno::TypeClass_UNSIGNED_LONG: + rMetric <<= static_cast<sal_uInt32>(sanitiseMm100ToTwip(*o3tl::forceAccess<sal_uInt32>(rMetric))); + break; + default: + OSL_FAIL("AW: Missing unit translation to 100th mm!"); + } + break; + } + default: + { + OSL_FAIL("AW: Missing unit translation to PoolMetrics!"); + } + } +} + +SvxItemPropertySetUsrAnys::SvxItemPropertySetUsrAnys() = default; + +SvxItemPropertySetUsrAnys::~SvxItemPropertySetUsrAnys() +{ + ClearAllUsrAny(); +} + +uno::Any* SvxItemPropertySetUsrAnys::GetUsrAnyForID(SfxItemPropertyMapEntry const & entry) const +{ + for (auto const & rActual : aCombineList) + { + if( rActual.nWID == entry.nWID && rActual.memberId == entry.nMemberId ) + return const_cast<uno::Any*>(&rActual.aAny); + } + return nullptr; +} + +void SvxItemPropertySetUsrAnys::AddUsrAnyForID( + const uno::Any& rAny, SfxItemPropertyMapEntry const & entry) +{ + SvxIDPropertyCombine aNew; + aNew.nWID = entry.nWID; + aNew.memberId = entry.nMemberId; + aNew.aAny = rAny; + aCombineList.push_back( std::move(aNew) ); +} + +void SvxItemPropertySetUsrAnys::ClearAllUsrAny() +{ + aCombineList.clear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unonrule.cxx b/editeng/source/uno/unonrule.cxx new file mode 100644 index 0000000000..5083f4d8e8 --- /dev/null +++ b/editeng/source/uno/unonrule.cxx @@ -0,0 +1,544 @@ +/* -*- 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 <sal/config.h> + +#include <com/sun/star/awt/FontDescriptor.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <com/sun/star/text/HoriOrientation.hpp> +#include <com/sun/star/awt/XBitmap.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/implbase1.hxx> +#include <utility> +#include <vcl/font.hxx> +#include <vcl/svapp.hxx> +#include <vcl/graph.hxx> +#include <vcl/GraphicObject.hxx> +#include <vcl/GraphicLoader.hxx> +#include <tools/debug.hxx> + +#include <editeng/brushitem.hxx> +#include <editeng/unoprnms.hxx> +#include <editeng/numitem.hxx> +#include <editeng/unofdesc.hxx> +#include <editeng/unonrule.hxx> +#include <editeng/editids.hrc> +#include <o3tl/enumarray.hxx> +#include <o3tl/temporary.hxx> +#include <memory> + +using ::com::sun::star::util::XCloneable; +using ::com::sun::star::ucb::XAnyCompare; + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; + +const SvxAdjust aUnoToSvxAdjust[] = +{ + SvxAdjust::Left, + SvxAdjust::Right, + SvxAdjust::Center, + SvxAdjust::Left, + SvxAdjust::Left, + SvxAdjust::Left, + SvxAdjust::Block +}; + +const o3tl::enumarray<SvxAdjust, sal_Int16> aSvxToUnoAdjust +{ + text::HoriOrientation::LEFT, + text::HoriOrientation::RIGHT, + text::HoriOrientation::FULL, + text::HoriOrientation::CENTER, + text::HoriOrientation::FULL, + text::HoriOrientation::LEFT +}; + +static SvxAdjust ConvertUnoAdjust( unsigned short nAdjust ) +{ + DBG_ASSERT( nAdjust <= 7, "Enum has changed! [CL]" ); + return aUnoToSvxAdjust[nAdjust]; +} + +static unsigned short ConvertUnoAdjust( SvxAdjust eAdjust ) +{ + DBG_ASSERT( static_cast<int>(eAdjust) <= 6, "Enum has changed! [CL]" ); + return aSvxToUnoAdjust[eAdjust]; +} + +SvxUnoNumberingRules::SvxUnoNumberingRules(SvxNumRule aRule) +: maRule(std::move( aRule )) +{ +} + +SvxUnoNumberingRules::~SvxUnoNumberingRules() noexcept +{ +} + +//XIndexReplace +void SAL_CALL SvxUnoNumberingRules::replaceByIndex( sal_Int32 Index, const uno::Any& Element ) +{ + SolarMutexGuard aGuard; + + if( Index < 0 || Index >= maRule.GetLevelCount() ) + throw IndexOutOfBoundsException(); + + Sequence< beans::PropertyValue > aSeq; + + if( !( Element >>= aSeq) ) + throw IllegalArgumentException(); + setNumberingRuleByIndex( aSeq, Index ); +} + +// XIndexAccess +sal_Int32 SAL_CALL SvxUnoNumberingRules::getCount() +{ + SolarMutexGuard aGuard; + + return maRule.GetLevelCount(); +} + +Any SAL_CALL SvxUnoNumberingRules::getByIndex( sal_Int32 Index ) +{ + SolarMutexGuard aGuard; + + if( Index < 0 || Index >= maRule.GetLevelCount() ) + throw IndexOutOfBoundsException(); + + return Any( getNumberingRuleByIndex(Index) ); +} + +//XElementAccess +Type SAL_CALL SvxUnoNumberingRules::getElementType() +{ + return cppu::UnoType<Sequence< beans::PropertyValue >>::get(); +} + +sal_Bool SAL_CALL SvxUnoNumberingRules::hasElements() +{ + return true; +} + +// XAnyCompare +sal_Int16 SAL_CALL SvxUnoNumberingRules::compare( const Any& rAny1, const Any& rAny2 ) +{ + return SvxUnoNumberingRules::Compare( rAny1, rAny2 ); +} + +// XCloneable +Reference< XCloneable > SAL_CALL SvxUnoNumberingRules::createClone( ) +{ + return new SvxUnoNumberingRules(maRule); +} + +OUString SAL_CALL SvxUnoNumberingRules::getImplementationName( ) +{ + return "SvxUnoNumberingRules"; +} + +sal_Bool SAL_CALL SvxUnoNumberingRules::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL SvxUnoNumberingRules::getSupportedServiceNames( ) +{ + return { "com.sun.star.text.NumberingRules" }; +} + +Sequence<beans::PropertyValue> SvxUnoNumberingRules::getNumberingRuleByIndex(sal_Int32 nIndex) const +{ + // NumberingRule aRule; + const SvxNumberFormat& rFmt = maRule.GetLevel(static_cast<sal_uInt16>(nIndex)); + sal_uInt16 nIdx = 0; + + const int nProps = 15; + std::unique_ptr<beans::PropertyValue[]> pArray(new beans::PropertyValue[nProps]); + + Any aVal; + { + aVal <<= static_cast<sal_uInt16>(rFmt.GetNumberingType()); + beans::PropertyValue aAlignProp( UNO_NAME_NRULE_NUMBERINGTYPE, -1, aVal, beans::PropertyState_DIRECT_VALUE); + pArray[nIdx++] = aAlignProp; + } + + { + SvxAdjust eAdj = rFmt.GetNumAdjust(); + aVal <<= ConvertUnoAdjust(eAdj); + pArray[nIdx++] = beans::PropertyValue( UNO_NAME_NRULE_ADJUST, -1, aVal, beans::PropertyState_DIRECT_VALUE); + } + + { + aVal <<= rFmt.GetPrefix(); + beans::PropertyValue aPrefixProp( UNO_NAME_NRULE_PREFIX, -1, aVal, beans::PropertyState_DIRECT_VALUE); + pArray[nIdx++] = aPrefixProp; + } + + { + aVal <<= rFmt.GetSuffix(); + beans::PropertyValue aSuffixProp( UNO_NAME_NRULE_SUFFIX, -1, aVal, beans::PropertyState_DIRECT_VALUE); + pArray[nIdx++] = aSuffixProp; + } + + if(SVX_NUM_CHAR_SPECIAL == rFmt.GetNumberingType()) + { + sal_UCS4 nCode = rFmt.GetBulletChar(); + OUString aStr( &nCode, 1 ); + aVal <<= aStr; + pArray[nIdx++] = beans::PropertyValue("BulletChar", -1, aVal, beans::PropertyState_DIRECT_VALUE); + } + + if( rFmt.GetBulletFont() ) + { + awt::FontDescriptor aDesc; + SvxUnoFontDescriptor::ConvertFromFont( *rFmt.GetBulletFont(), aDesc ); + aVal <<= aDesc; + pArray[nIdx++] = beans::PropertyValue( UNO_NAME_NRULE_BULLET_FONT, -1, aVal, beans::PropertyState_DIRECT_VALUE); + } + + { + const SvxBrushItem* pBrush = rFmt.GetBrush(); + const Graphic* pGraphic = nullptr; + if (pBrush) + pGraphic = pBrush->GetGraphic(); + if (pGraphic) + { + uno::Reference<awt::XBitmap> xBitmap(pGraphic->GetXGraphic(), uno::UNO_QUERY); + aVal <<= xBitmap; + + const beans::PropertyValue aGraphicProp("GraphicBitmap", -1, aVal, beans::PropertyState_DIRECT_VALUE); + pArray[nIdx++] = aGraphicProp; + } + } + + { + const Size aSize( rFmt.GetGraphicSize() ); + const awt::Size aUnoSize( aSize.Width(), aSize.Height() ); + aVal <<= aUnoSize; + const beans::PropertyValue aGraphicSizeProp("GraphicSize", -1, aVal, beans::PropertyState_DIRECT_VALUE ); + pArray[nIdx++] = aGraphicSizeProp; + } + + aVal <<= static_cast<sal_Int16>(rFmt.GetStart()); + pArray[nIdx++] = beans::PropertyValue(UNO_NAME_NRULE_START_WITH, -1, aVal, beans::PropertyState_DIRECT_VALUE); + + aVal <<= rFmt.GetAbsLSpace(); + pArray[nIdx++] = beans::PropertyValue(UNO_NAME_NRULE_LEFT_MARGIN, -1, aVal, beans::PropertyState_DIRECT_VALUE); + + aVal <<= rFmt.GetFirstLineOffset(); + pArray[nIdx++] = beans::PropertyValue(UNO_NAME_NRULE_FIRST_LINE_OFFSET, -1, aVal, beans::PropertyState_DIRECT_VALUE); + + pArray[nIdx++] = beans::PropertyValue("SymbolTextDistance", -1, aVal, beans::PropertyState_DIRECT_VALUE); + + aVal <<= rFmt.GetBulletColor(); + pArray[nIdx++] = beans::PropertyValue(UNO_NAME_NRULE_BULLET_COLOR, -1, aVal, beans::PropertyState_DIRECT_VALUE); + + aVal <<= static_cast<sal_Int16>(rFmt.GetBulletRelSize()); + pArray[nIdx++] = beans::PropertyValue(UNO_NAME_NRULE_BULLET_RELSIZE, -1, aVal, beans::PropertyState_DIRECT_VALUE); + + DBG_ASSERT( nIdx <= nProps, "FixMe: overflow in Array!!! [CL]" ); + Sequence< beans::PropertyValue> aSeq(pArray.get(), nIdx); + + return aSeq; +} + +void SvxUnoNumberingRules::setNumberingRuleByIndex(const Sequence<beans::PropertyValue >& rProperties, sal_Int32 nIndex) +{ + SvxNumberFormat aFmt(maRule.GetLevel( static_cast<sal_uInt16>(nIndex) )); + for(const beans::PropertyValue& rProp : rProperties) + { + const OUString& rPropName = rProp.Name; + const Any& aVal = rProp.Value; + + if ( rPropName == UNO_NAME_NRULE_NUMBERINGTYPE ) + { + sal_Int16 nSet = sal_Int16(); + aVal >>= nSet; + + // There is no reason to limit numbering types. + if ( nSet>=0 ) + { + aFmt.SetNumberingType(static_cast<SvxNumType>(nSet)); + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_PREFIX ) + { + OUString aPrefix; + if( aVal >>= aPrefix ) + { + aFmt.SetPrefix(aPrefix); + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_SUFFIX ) + { + OUString aSuffix; + if( aVal >>= aSuffix ) + { + aFmt.SetSuffix(aSuffix); + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_BULLETID ) + { + sal_Int16 nSet = sal_Int16(); + if( aVal >>= nSet ) + { + if(nSet < 0x100) + { + aFmt.SetBulletChar(nSet); + continue; + } + } + } + else if ( rPropName == "BulletChar" ) + { + OUString aStr; + if( aVal >>= aStr ) + { + if(!aStr.isEmpty()) + { + aFmt.SetBulletChar(aStr.iterateCodePoints(&o3tl::temporary(sal_Int32(0)))); + } + else + { + aFmt.SetBulletChar(0); + } + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_ADJUST ) + { + sal_Int16 nAdjust = sal_Int16(); + if( aVal >>= nAdjust ) + { + aFmt.SetNumAdjust(ConvertUnoAdjust( static_cast<unsigned short>(nAdjust) )); + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_BULLET_FONT ) + { + awt::FontDescriptor aDesc; + if( aVal >>= aDesc ) + { + vcl::Font aFont; + SvxUnoFontDescriptor::ConvertToFont( aDesc, aFont ); + aFmt.SetBulletFont(&aFont); + continue; + } + } + else if ( rPropName == "GraphicURL" ) + { + OUString aURL; + if (aVal >>= aURL) + { + Graphic aGraphic = vcl::graphic::loadFromURL(aURL); + if (!aGraphic.IsNone()) + { + SvxBrushItem aBrushItem(aGraphic, GPOS_AREA, SID_ATTR_BRUSH); + aFmt.SetGraphicBrush(&aBrushItem); + } + continue; + } + } + else if ( rPropName == "GraphicBitmap" ) + { + uno::Reference<awt::XBitmap> xBitmap; + if (aVal >>= xBitmap) + { + uno::Reference<graphic::XGraphic> xGraphic(xBitmap, uno::UNO_QUERY); + Graphic aGraphic(xGraphic); + SvxBrushItem aBrushItem(aGraphic, GPOS_AREA, SID_ATTR_BRUSH); + aFmt.SetGraphicBrush( &aBrushItem ); + continue; + } + } + else if ( rPropName == "GraphicSize" ) + { + awt::Size aUnoSize; + if( aVal >>= aUnoSize ) + { + aFmt.SetGraphicSize( Size( aUnoSize.Width, aUnoSize.Height ) ); + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_START_WITH ) + { + sal_Int16 nStart = sal_Int16(); + if( aVal >>= nStart ) + { + aFmt.SetStart( nStart ); + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_LEFT_MARGIN ) + { + sal_Int32 nMargin = 0; + if( aVal >>= nMargin ) + { + aFmt.SetAbsLSpace(nMargin); + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_FIRST_LINE_OFFSET ) + { + sal_Int32 nMargin = 0; + if( aVal >>= nMargin ) + { + aFmt.SetFirstLineOffset(nMargin); + continue; + } + } + else if ( rPropName == "SymbolTextDistance" ) + { + sal_Int32 nTextDistance = 0; + if( aVal >>= nTextDistance ) + { + aFmt.SetCharTextDistance(static_cast<sal_uInt16>(nTextDistance)); + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_BULLET_COLOR ) + { + Color aColor; + if( aVal >>= aColor ) + { + aFmt.SetBulletColor( aColor ); + continue; + } + } + else if ( rPropName == UNO_NAME_NRULE_BULLET_RELSIZE ) + { + sal_Int16 nSize = sal_Int16(); + if( aVal >>= nSize ) + { + // [AOO Bug 120650] the slide content corrupt when open in Aoo + // [TDF# 126234] when MS Office document being imported, the value of the relative size + // of the bullet could be as high as 400% + if ((nSize>400)||(nSize<=0)) + { + nSize = 100; + } + + aFmt.SetBulletRelSize( static_cast<short>(nSize) ); + continue; + } + } + else + { + continue; + } + + throw IllegalArgumentException(); + } + + // check that we always have a brush item for bitmap numbering + if( aFmt.GetNumberingType() == SVX_NUM_BITMAP ) + { + if( nullptr == aFmt.GetBrush() ) + { + GraphicObject aGrafObj; + SvxBrushItem aBrushItem( aGrafObj, GPOS_AREA, SID_ATTR_BRUSH ); + aFmt.SetGraphicBrush( &aBrushItem ); + } + } + maRule.SetLevel( static_cast<sal_uInt16>(nIndex), aFmt ); +} + +const SvxNumRule& SvxGetNumRule( Reference< XIndexReplace > const & xRule ) +{ + SvxUnoNumberingRules* pRule = dynamic_cast<SvxUnoNumberingRules*>( xRule.get() ); + if( pRule == nullptr ) + throw IllegalArgumentException(); + + return pRule->getNumRule(); +} + +css::uno::Reference< css::container::XIndexReplace > SvxCreateNumRule(const SvxNumRule& rRule) +{ + return new SvxUnoNumberingRules( rRule ); +} + +namespace { + +class SvxUnoNumberingRulesCompare : public ::cppu::WeakImplHelper< XAnyCompare > +{ +public: + virtual sal_Int16 SAL_CALL compare( const Any& Any1, const Any& Any2 ) override; +}; + +} + +sal_Int16 SAL_CALL SvxUnoNumberingRulesCompare::compare( const Any& Any1, const Any& Any2 ) +{ + return SvxUnoNumberingRules::Compare( Any1, Any2 ); +} + +sal_Int16 SvxUnoNumberingRules::Compare( const Any& Any1, const Any& Any2 ) +{ + Reference< XIndexReplace > x1( Any1, UNO_QUERY ), x2( Any2, UNO_QUERY ); + if( !x1 || !x2 ) + return -1; + + if( x1.get() == x2.get() ) + return 0; + + SvxUnoNumberingRules* pRule1 = dynamic_cast<SvxUnoNumberingRules*>( x1.get() ); + if( !pRule1 ) + return -1; + SvxUnoNumberingRules* pRule2 = dynamic_cast<SvxUnoNumberingRules*>( x2.get() ); + if( !pRule2 ) + return -1; + + const SvxNumRule& rRule1 = pRule1->getNumRule(); + const SvxNumRule& rRule2 = pRule2->getNumRule(); + + const sal_uInt16 nLevelCount1 = rRule1.GetLevelCount(); + const sal_uInt16 nLevelCount2 = rRule2.GetLevelCount(); + + if( nLevelCount1 == 0 || nLevelCount2 == 0 ) + return -1; + + for( sal_uInt16 i = 0; (i < nLevelCount1) && (i < nLevelCount2); i++ ) + { + if( rRule1.GetLevel(i) != rRule2.GetLevel(i) ) + return -1; + } + return 0; +} + +Reference< XAnyCompare > SvxCreateNumRuleCompare() noexcept +{ + return new SvxUnoNumberingRulesCompare; +} + +css::uno::Reference< css::container::XIndexReplace > SvxCreateNumRule() +{ + SvxNumRule aTempRule( SvxNumRuleFlags::NONE, 10, false ); + return SvxCreateNumRule( aTempRule ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unopracc.cxx b/editeng/source/uno/unopracc.cxx new file mode 100644 index 0000000000..c36fc152e2 --- /dev/null +++ b/editeng/source/uno/unopracc.cxx @@ -0,0 +1,92 @@ +/* -*- 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 <cppuhelper/typeprovider.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <unopracc.hxx> +#include <editeng/unoedsrc.hxx> + +using namespace ::com::sun::star; + + +SvxAccessibleTextPropertySet::SvxAccessibleTextPropertySet( const SvxEditSource* pEditSrc, const SvxItemPropertySet* pPropSet ) + : SvxUnoTextRangeBase( pEditSrc, pPropSet ) +{ +} + +SvxAccessibleTextPropertySet::~SvxAccessibleTextPropertySet() noexcept +{ +} + +uno::Reference< text::XText > SAL_CALL SvxAccessibleTextPropertySet::getText() +{ + // TODO (empty?) + return uno::Reference< text::XText > (); +} + +uno::Any SAL_CALL SvxAccessibleTextPropertySet::queryInterface( const uno::Type & rType ) +{ + return OWeakObject::queryInterface(rType); +} + +void SAL_CALL SvxAccessibleTextPropertySet::acquire() + noexcept +{ + OWeakObject::acquire(); +} + +void SAL_CALL SvxAccessibleTextPropertySet::release() + noexcept +{ + OWeakObject::release(); +} + +// XTypeProvider +uno::Sequence< uno::Type > SAL_CALL SvxAccessibleTextPropertySet::getTypes() +{ + static ::cppu::OTypeCollection ourTypeCollection( + ::cppu::UnoType<beans::XPropertySet>::get(), + ::cppu::UnoType<beans::XMultiPropertySet>::get(), + ::cppu::UnoType<beans::XPropertyState>::get(), + ::cppu::UnoType<lang::XServiceInfo>::get(), + ::cppu::UnoType<lang::XTypeProvider>::get() ); + + return ourTypeCollection.getTypes() ; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxAccessibleTextPropertySet::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// XServiceInfo +OUString SAL_CALL SAL_CALL SvxAccessibleTextPropertySet::getImplementationName() +{ + return "SvxAccessibleTextPropertySet"; +} + +sal_Bool SAL_CALL SvxAccessibleTextPropertySet::supportsService (const OUString& sServiceName) +{ + return cppu::supportsService(this, sServiceName); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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: */ diff --git a/editeng/source/uno/unotext2.cxx b/editeng/source/uno/unotext2.cxx new file mode 100644 index 0000000000..54714027b3 --- /dev/null +++ b/editeng/source/uno/unotext2.cxx @@ -0,0 +1,629 @@ +/* -*- 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 <sal/config.h> + +#include <initializer_list> +#include <string_view> + +#include <o3tl/safeint.hxx> +#include <vcl/svapp.hxx> + +#include <editeng/unotext.hxx> +#include <comphelper/sequence.hxx> +#include <cppuhelper/supportsservice.hxx> + +using namespace ::cppu; +using namespace ::com::sun::star; + +#define QUERYINT( xint ) \ + if( rType == cppu::UnoType<xint>::get() ) \ + return uno::Any(uno::Reference< xint >(this)) + + +// SvxUnoTextContentEnumeration + + +SvxUnoTextContentEnumeration::SvxUnoTextContentEnumeration( const SvxUnoTextBase& rText, const ESelection& rSel ) noexcept +{ + mxParentText = const_cast<SvxUnoTextBase*>(&rText); + if( rText.GetEditSource() ) + mpEditSource = rText.GetEditSource()->Clone(); + mnNextParagraph = 0; + + if (!mpEditSource) + return; + + const SvxTextForwarder* pTextForwarder = rText.GetEditSource()->GetTextForwarder(); + const sal_Int32 maxParaIndex = std::min( rSel.nEndPara + 1, pTextForwarder->GetParagraphCount() ); + + for( sal_Int32 currentPara = rSel.nStartPara; currentPara < maxParaIndex; currentPara++ ) + { + const SvxUnoTextRangeBaseVec& rRanges( mpEditSource->getRanges() ); + rtl::Reference<SvxUnoTextContent> pContent; + sal_Int32 nStartPos = 0; + sal_Int32 nEndPos = pTextForwarder->GetTextLen( currentPara ); + if( currentPara == rSel.nStartPara ) + nStartPos = std::max(nStartPos, rSel.nStartPos); + if( currentPara == rSel.nEndPara ) + nEndPos = std::min(nEndPos, rSel.nEndPos); + ESelection aCurrentParaSel( currentPara, nStartPos, currentPara, nEndPos ); + for (auto const& elemRange : rRanges) + { + if (pContent) + break; + SvxUnoTextContent* pIterContent = dynamic_cast< SvxUnoTextContent* >( elemRange ); + if( pIterContent && (pIterContent->mnParagraph == currentPara) ) + { + ESelection aIterSel = pIterContent->GetSelection(); + if( aIterSel == aCurrentParaSel ) + { + pContent = pIterContent; + maContents.emplace_back(pContent ); + } + } + } + if( pContent == nullptr ) + { + pContent = new SvxUnoTextContent( rText, currentPara ); + pContent->SetSelection( aCurrentParaSel ); + maContents.emplace_back(pContent ); + } + } +} + +SvxUnoTextContentEnumeration::~SvxUnoTextContentEnumeration() noexcept +{ +} + +// container::XEnumeration +sal_Bool SAL_CALL SvxUnoTextContentEnumeration::hasMoreElements() +{ + SolarMutexGuard aGuard; + if( mpEditSource && !maContents.empty() ) + return o3tl::make_unsigned(mnNextParagraph) < maContents.size(); + else + return false; +} + +uno::Any SvxUnoTextContentEnumeration::nextElement() +{ + SolarMutexGuard aGuard; + + if(!hasMoreElements()) + throw container::NoSuchElementException(); + + uno::Reference< text::XTextContent > xRef( maContents.at(mnNextParagraph) ); + mnNextParagraph++; + return uno::Any( xRef ); +} + + + + +SvxUnoTextContent::SvxUnoTextContent( const SvxUnoTextBase& rText, sal_Int32 nPara ) noexcept +: SvxUnoTextRangeBase(rText) +, mnParagraph(nPara) +, mrParentText(rText) +, mbDisposing( false ) +{ + mxParentText = const_cast<SvxUnoTextBase*>(&rText); +} + +SvxUnoTextContent::SvxUnoTextContent( const SvxUnoTextContent& rContent ) noexcept +: SvxUnoTextRangeBase(rContent) +, text::XTextContent() +, container::XEnumerationAccess() +, lang::XTypeProvider() +, cppu::OWeakAggObject() +, mrParentText(rContent.mrParentText) +, mbDisposing( false ) +{ + mxParentText = rContent.mxParentText; + mnParagraph = rContent.mnParagraph; + SetSelection( rContent.GetSelection() ); +} + +SvxUnoTextContent::~SvxUnoTextContent() noexcept +{ +} + +// uno::XInterface +uno::Any SAL_CALL SvxUnoTextContent::queryAggregation( const uno::Type & rType ) +{ + QUERYINT( text::XTextRange ); + else QUERYINT( beans::XMultiPropertyStates ); + else QUERYINT( beans::XPropertySet ); + else QUERYINT( beans::XMultiPropertySet ); + else QUERYINT( beans::XPropertyState ); + else QUERYINT( text::XTextContent ); + else QUERYINT( text::XTextRangeCompare ); + else QUERYINT( lang::XComponent ); + else QUERYINT( container::XEnumerationAccess ); + else QUERYINT( container::XElementAccess ); + else QUERYINT( lang::XServiceInfo ); + else QUERYINT( lang::XTypeProvider ); + else QUERYINT( lang::XUnoTunnel ); + else + return OWeakAggObject::queryAggregation( rType ); +} + +uno::Any SAL_CALL SvxUnoTextContent::queryInterface( const uno::Type & rType ) +{ + return OWeakAggObject::queryInterface(rType); +} + +void SAL_CALL SvxUnoTextContent::acquire() noexcept +{ + OWeakAggObject::acquire(); +} + +void SAL_CALL SvxUnoTextContent::release() noexcept +{ + OWeakAggObject::release(); +} + +// XTypeProvider + +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextContent::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<text::XTextRangeCompare>::get(), + cppu::UnoType<text::XTextContent>::get(), + cppu::UnoType<container::XEnumerationAccess>::get(), + cppu::UnoType<lang::XServiceInfo>::get(), + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<lang::XUnoTunnel>::get() }; + return TYPES; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextContent::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// text::XTextRange + +uno::Reference< text::XText > SAL_CALL SvxUnoTextContent::getText() +{ + return mxParentText; +} + +// text::XTextContent +void SAL_CALL SvxUnoTextContent::attach( const uno::Reference< text::XTextRange >& ) +{ +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextContent::getAnchor() +{ + return mxParentText; +} + +// XComponent + +void SAL_CALL SvxUnoTextContent::dispose() +{ + SolarMutexGuard aGuard; + + if( mbDisposing ) + return; // caught a recursion + + mbDisposing = true; + + lang::EventObject aEvt; + aEvt.Source = *static_cast<OWeakAggObject*>(this); + { + std::unique_lock aMutexGuard(maDisposeContainerMutex); + maDisposeListeners.disposeAndClear(aMutexGuard, aEvt); + } + + if( mxParentText.is() ) + { + mxParentText->removeTextContent( this ); + mxParentText.clear(); + } +} + +void SAL_CALL SvxUnoTextContent::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) +{ + std::unique_lock aGuard(maDisposeContainerMutex); + maDisposeListeners.addInterface(aGuard, xListener); +} + +void SAL_CALL SvxUnoTextContent::removeEventListener( const uno::Reference< lang::XEventListener >& aListener ) +{ + std::unique_lock aGuard(maDisposeContainerMutex); + maDisposeListeners.removeInterface(aGuard, aListener); +} + +// XEnumerationAccess + +uno::Reference< container::XEnumeration > SAL_CALL SvxUnoTextContent::createEnumeration() +{ + SolarMutexGuard aGuard; + + return new SvxUnoTextRangeEnumeration( mrParentText, mnParagraph, maSelection ); +} + +// XElementAccess ( container::XEnumerationAccess ) + +uno::Type SAL_CALL SvxUnoTextContent::getElementType() +{ + return cppu::UnoType<text::XTextRange>::get(); +} + +sal_Bool SAL_CALL SvxUnoTextContent::hasElements() +{ + SolarMutexGuard aGuard; + + SvxTextForwarder* pForwarder = GetEditSource() ? GetEditSource()->GetTextForwarder() : nullptr; + if( pForwarder ) + { + std::vector<sal_Int32> aPortions; + pForwarder->GetPortions( mnParagraph, aPortions ); + return !aPortions.empty(); + } + else + { + return false; + } +} + +// XPropertySet + +void SAL_CALL SvxUnoTextContent::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue ) +{ + _setPropertyValue( aPropertyName, aValue, mnParagraph ); +} + +uno::Any SAL_CALL SvxUnoTextContent::getPropertyValue( const OUString& PropertyName ) +{ + return _getPropertyValue( PropertyName, mnParagraph ); +} + +// XMultiPropertySet +void SAL_CALL SvxUnoTextContent::setPropertyValues( const uno::Sequence< OUString >& aPropertyNames, const uno::Sequence< uno::Any >& aValues ) +{ + _setPropertyValues( aPropertyNames, aValues, mnParagraph ); +} + +uno::Sequence< uno::Any > SAL_CALL SvxUnoTextContent::getPropertyValues( const uno::Sequence< OUString >& aPropertyNames ) +{ + return _getPropertyValues( aPropertyNames, mnParagraph ); +} + +/*// XTolerantMultiPropertySet +uno::Sequence< beans::SetPropertyTolerantFailed > SAL_CALL SvxUnoTextContent::setPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames, const uno::Sequence< uno::Any >& aValues ) throw (lang::IllegalArgumentException, uno::RuntimeException) +{ + return _setPropertyValuesTolerant(aPropertyNames, aValues, mnParagraph); +} + +uno::Sequence< beans::GetPropertyTolerantResult > SAL_CALL SvxUnoTextContent::getPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames ) throw (uno::RuntimeException) +{ + return _getPropertyValuesTolerant(aPropertyNames, mnParagraph); +} + +uno::Sequence< beans::GetDirectPropertyTolerantResult > SAL_CALL SvxUnoTextContent::getDirectPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames ) + throw (uno::RuntimeException) +{ + return _getDirectPropertyValuesTolerant(aPropertyNames, mnParagraph); +}*/ + +// beans::XPropertyState +beans::PropertyState SAL_CALL SvxUnoTextContent::getPropertyState( const OUString& PropertyName ) +{ + return _getPropertyState( PropertyName, mnParagraph ); +} + +uno::Sequence< beans::PropertyState > SAL_CALL SvxUnoTextContent::getPropertyStates( const uno::Sequence< OUString >& aPropertyName ) +{ + return _getPropertyStates( aPropertyName, mnParagraph ); +} + +void SAL_CALL SvxUnoTextContent::setPropertyToDefault( const OUString& PropertyName ) +{ + _setPropertyToDefault( PropertyName, mnParagraph ); +} + +// lang::XServiceInfo + +OUString SAL_CALL SvxUnoTextContent::getImplementationName() +{ + return "SvxUnoTextContent"; +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextContent::getSupportedServiceNames() +{ + return comphelper::concatSequences( + SvxUnoTextRangeBase::getSupportedServiceNames(), + std::initializer_list<std::u16string_view>{ u"com.sun.star.style.ParagraphProperties", + u"com.sun.star.style.ParagraphPropertiesComplex", + u"com.sun.star.style.ParagraphPropertiesAsian", + u"com.sun.star.text.TextContent", + u"com.sun.star.text.Paragraph" }); +} + + + + +SvxUnoTextRangeEnumeration::SvxUnoTextRangeEnumeration(const SvxUnoTextBase& rParentText, sal_Int32 nParagraph, const ESelection& rSel) +: mxParentText( const_cast<SvxUnoTextBase*>(&rParentText) ), + mnNextPortion( 0 ) +{ + if (rParentText.GetEditSource()) + mpEditSource = rParentText.GetEditSource()->Clone(); + + if( !(mpEditSource && mpEditSource->GetTextForwarder() && (nParagraph == rSel.nStartPara && nParagraph == rSel.nEndPara)) ) + return; + + std::vector<sal_Int32> aPortions; + mpEditSource->GetTextForwarder()->GetPortions( nParagraph, aPortions ); + for( size_t aPortionIndex = 0; aPortionIndex < aPortions.size(); aPortionIndex++ ) + { + sal_uInt16 nStartPos = 0; + if ( aPortionIndex > 0 ) + nStartPos = aPortions.at( aPortionIndex - 1 ); + if( nStartPos > rSel.nEndPos ) + continue; + sal_uInt16 nEndPos = aPortions.at( aPortionIndex ); + if( nEndPos < rSel.nStartPos ) + continue; + + nStartPos = std::max<int>(nStartPos, rSel.nStartPos); + nEndPos = std::min<sal_uInt16>(nEndPos, rSel.nEndPos); + ESelection aSel( nParagraph, nStartPos, nParagraph, nEndPos ); + + const SvxUnoTextRangeBaseVec& rRanges( mpEditSource->getRanges() ); + rtl::Reference<SvxUnoTextRange> pRange; + for (auto const& elemRange : rRanges) + { + if (pRange) + break; + SvxUnoTextRange* pIterRange = dynamic_cast< SvxUnoTextRange* >( elemRange ); + if( pIterRange && pIterRange->mbPortion && (aSel == pIterRange->maSelection) ) + pRange = pIterRange; + } + if( pRange == nullptr ) + { + pRange = new SvxUnoTextRange( rParentText, true ); + pRange->SetSelection( aSel ); + } + maPortions.emplace_back(pRange ); + } +} + +SvxUnoTextRangeEnumeration::~SvxUnoTextRangeEnumeration() noexcept +{ +} + +// container::XEnumeration + +sal_Bool SAL_CALL SvxUnoTextRangeEnumeration::hasMoreElements() +{ + SolarMutexGuard aGuard; + + return !maPortions.empty() && mnNextPortion < maPortions.size(); +} + +uno::Any SAL_CALL SvxUnoTextRangeEnumeration::nextElement() +{ + SolarMutexGuard aGuard; + + if( maPortions.empty() || mnNextPortion >= maPortions.size() ) + throw container::NoSuchElementException(); + + uno::Reference< text::XTextRange > xRange = maPortions.at(mnNextPortion); + mnNextPortion++; + return uno::Any( xRange ); +} + +SvxUnoTextCursor::SvxUnoTextCursor( const SvxUnoTextBase& rText ) noexcept +: SvxUnoTextRangeBase(rText), + mxParentText( const_cast<SvxUnoTextBase*>(&rText) ) +{ +} + +SvxUnoTextCursor::SvxUnoTextCursor( const SvxUnoTextCursor& rCursor ) noexcept +: SvxUnoTextRangeBase(rCursor) +, text::XTextCursor() +, lang::XTypeProvider() +, cppu::OWeakAggObject() +, mxParentText(rCursor.mxParentText) +{ +} + +SvxUnoTextCursor::~SvxUnoTextCursor() noexcept +{ +} + +// Comment out automatically - [getIdlClass(es) or queryInterface] +// Please use the XTypeProvider! +//sal_Bool SvxUnoTextCursor::queryInterface( uno::Uik aUIK, Reference< uno::XInterface > & xRef) +uno::Any SAL_CALL SvxUnoTextCursor::queryAggregation( const uno::Type & rType ) +{ + if( rType == cppu::UnoType<text::XTextRange>::get()) + return uno::Any(uno::Reference< text::XTextRange >(static_cast<SvxUnoTextRangeBase *>(this))); + else QUERYINT( text::XTextCursor ); + else QUERYINT( beans::XMultiPropertyStates ); + else QUERYINT( beans::XPropertySet ); + else QUERYINT( beans::XMultiPropertySet ); + else QUERYINT( beans::XPropertyState ); + else QUERYINT( text::XTextRangeCompare ); + else QUERYINT( lang::XServiceInfo ); + else QUERYINT( lang::XTypeProvider ); + else QUERYINT( lang::XUnoTunnel ); + else + return OWeakAggObject::queryAggregation( rType ); +} + +uno::Any SAL_CALL SvxUnoTextCursor::queryInterface( const uno::Type & rType ) +{ + return OWeakAggObject::queryInterface(rType); +} + +void SAL_CALL SvxUnoTextCursor::acquire() noexcept +{ + OWeakAggObject::acquire(); +} + +void SAL_CALL SvxUnoTextCursor::release() noexcept +{ + OWeakAggObject::release(); +} + +// XTypeProvider +uno::Sequence< uno::Type > SAL_CALL SvxUnoTextCursor::getTypes() +{ + static const uno::Sequence< uno::Type > TYPES { + cppu::UnoType<text::XTextRange>::get(), + cppu::UnoType<text::XTextCursor>::get(), + cppu::UnoType<beans::XPropertySet>::get(), + cppu::UnoType<beans::XMultiPropertySet>::get(), + cppu::UnoType<beans::XMultiPropertyStates>::get(), + cppu::UnoType<beans::XPropertyState>::get(), + cppu::UnoType<text::XTextRangeCompare>::get(), + cppu::UnoType<lang::XServiceInfo>::get(), + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<lang::XUnoTunnel>::get() }; + return TYPES; +} + +uno::Sequence< sal_Int8 > SAL_CALL SvxUnoTextCursor::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// text::XTextCursor +void SAL_CALL SvxUnoTextCursor::collapseToStart() +{ + SolarMutexGuard aGuard; + CollapseToStart(); +} + +void SAL_CALL SvxUnoTextCursor::collapseToEnd() +{ + SolarMutexGuard aGuard; + CollapseToEnd(); +} + +sal_Bool SAL_CALL SvxUnoTextCursor::isCollapsed() +{ + SolarMutexGuard aGuard; + return IsCollapsed(); +} + +sal_Bool SAL_CALL SvxUnoTextCursor::goLeft( sal_Int16 nCount, sal_Bool bExpand ) +{ + SolarMutexGuard aGuard; + return GoLeft( nCount, bExpand ); +} + +sal_Bool SAL_CALL SvxUnoTextCursor::goRight( sal_Int16 nCount, sal_Bool bExpand ) +{ + SolarMutexGuard aGuard; + return GoRight( nCount, bExpand ); +} + +void SAL_CALL SvxUnoTextCursor::gotoStart( sal_Bool bExpand ) +{ + SolarMutexGuard aGuard; + GotoStart( bExpand ); +} + +void SAL_CALL SvxUnoTextCursor::gotoEnd( sal_Bool bExpand ) +{ + SolarMutexGuard aGuard; + GotoEnd( bExpand ); +} + +void SAL_CALL SvxUnoTextCursor::gotoRange( const uno::Reference< text::XTextRange >& xRange, sal_Bool bExpand ) +{ + if( !xRange.is() ) + return; + + SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( xRange ); + + if( !pRange ) + return; + + ESelection aNewSel = pRange->GetSelection(); + + if( bExpand ) + { + const ESelection& rOldSel = GetSelection(); + aNewSel.nStartPara = rOldSel.nStartPara; + aNewSel.nStartPos = rOldSel.nStartPos; + } + + SetSelection( aNewSel ); +} + +// text::XTextRange (rest in SvxTextRange) +uno::Reference< text::XText > SAL_CALL SvxUnoTextCursor::getText() +{ + return mxParentText; +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextCursor::getStart() +{ + return SvxUnoTextRangeBase::getStart(); +} + +uno::Reference< text::XTextRange > SAL_CALL SvxUnoTextCursor::getEnd() +{ + return SvxUnoTextRangeBase::getEnd(); +} + +OUString SAL_CALL SvxUnoTextCursor::getString() +{ + return SvxUnoTextRangeBase::getString(); +} + +void SAL_CALL SvxUnoTextCursor::setString( const OUString& aString ) +{ + SvxUnoTextRangeBase::setString(aString); +} +// lang::XServiceInfo +OUString SAL_CALL SvxUnoTextCursor::getImplementationName() +{ + return "SvxUnoTextCursor"; +} + +sal_Bool SAL_CALL SvxUnoTextCursor::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService( this, ServiceName ); +} + +uno::Sequence< OUString > SAL_CALL SvxUnoTextCursor::getSupportedServiceNames() +{ + return comphelper::concatSequences( + SvxUnoTextRangeBase::getSupportedServiceNames(), + std::initializer_list<std::u16string_view>{ u"com.sun.star.style.ParagraphProperties", + u"com.sun.star.style.ParagraphPropertiesComplex", + u"com.sun.star.style.ParagraphPropertiesAsian", + u"com.sun.star.text.TextCursor" }); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/editeng/source/uno/unoviwou.cxx b/editeng/source/uno/unoviwou.cxx new file mode 100644 index 0000000000..19f38794e8 --- /dev/null +++ b/editeng/source/uno/unoviwou.cxx @@ -0,0 +1,128 @@ +/* -*- 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/outdev.hxx> +#include <vcl/window.hxx> + +#include <editeng/unoviwou.hxx> +#include <editeng/outliner.hxx> + +SvxDrawOutlinerViewForwarder::SvxDrawOutlinerViewForwarder( OutlinerView& rOutl ) : + mrOutlinerView ( rOutl ) +{ +} + +SvxDrawOutlinerViewForwarder::SvxDrawOutlinerViewForwarder( OutlinerView& rOutl, const Point& rShapePosTopLeft ) : + mrOutlinerView ( rOutl ), maTextShapeTopLeft( rShapePosTopLeft ) +{ +} + +SvxDrawOutlinerViewForwarder::~SvxDrawOutlinerViewForwarder() +{ +} + +Point SvxDrawOutlinerViewForwarder::GetTextOffset() const +{ + // calc text offset from shape anchor + tools::Rectangle aOutputRect( mrOutlinerView.GetOutputArea() ); + + return aOutputRect.TopLeft() - maTextShapeTopLeft; +} + +bool SvxDrawOutlinerViewForwarder::IsValid() const +{ + return true; +} + +Point SvxDrawOutlinerViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const +{ + OutputDevice* pOutDev = mrOutlinerView.GetWindow()->GetOutDev(); + + if( pOutDev ) + { + Point aPoint1( rPoint ); + Point aTextOffset( GetTextOffset() ); + + aPoint1.AdjustX(aTextOffset.X() ); + aPoint1.AdjustY(aTextOffset.Y() ); + + MapMode aMapMode(pOutDev->GetMapMode()); + Point aPoint2( OutputDevice::LogicToLogic( aPoint1, rMapMode, + MapMode(aMapMode.GetMapUnit()))); + aMapMode.SetOrigin(Point()); + return pOutDev->LogicToPixel( aPoint2, aMapMode ); + } + + return Point(); +} + +Point SvxDrawOutlinerViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const +{ + OutputDevice* pOutDev = mrOutlinerView.GetWindow()->GetOutDev(); + + if( pOutDev ) + { + MapMode aMapMode(pOutDev->GetMapMode()); + aMapMode.SetOrigin(Point()); + Point aPoint1( pOutDev->PixelToLogic( rPoint, aMapMode ) ); + Point aPoint2( OutputDevice::LogicToLogic( aPoint1, + MapMode(aMapMode.GetMapUnit()), + rMapMode ) ); + Point aTextOffset( GetTextOffset() ); + + aPoint2.AdjustX( -(aTextOffset.X()) ); + aPoint2.AdjustY( -(aTextOffset.Y()) ); + + return aPoint2; + } + + return Point(); +} + +bool SvxDrawOutlinerViewForwarder::GetSelection( ESelection& rSelection ) const +{ + rSelection = mrOutlinerView.GetSelection(); + return true; +} + +bool SvxDrawOutlinerViewForwarder::SetSelection( const ESelection& rSelection ) +{ + mrOutlinerView.SetSelection( rSelection ); + return true; +} + +bool SvxDrawOutlinerViewForwarder::Copy() +{ + mrOutlinerView.Copy(); + return true; +} + +bool SvxDrawOutlinerViewForwarder::Cut() +{ + mrOutlinerView.Cut(); + return true; +} + +bool SvxDrawOutlinerViewForwarder::Paste() +{ + mrOutlinerView.PasteSpecial(); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |