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 /sw/source/core/unocore/unoflatpara.cxx | |
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 'sw/source/core/unocore/unoflatpara.cxx')
-rw-r--r-- | sw/source/core/unocore/unoflatpara.cxx | 581 |
1 files changed, 581 insertions, 0 deletions
diff --git a/sw/source/core/unocore/unoflatpara.cxx b/sw/source/core/unocore/unoflatpara.cxx new file mode 100644 index 0000000000..0f158e49fc --- /dev/null +++ b/sw/source/core/unocore/unoflatpara.cxx @@ -0,0 +1,581 @@ +/* -*- 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 <unobaseclass.hxx> +#include <unocrsrhelper.hxx> +#include <unoflatpara.hxx> + +#include <o3tl/safeint.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <com/sun/star/text/TextMarkupType.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <unotextmarkup.hxx> +#include <ndtxt.hxx> +#include <doc.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <IDocumentStylePoolAccess.hxx> +#include <viewsh.hxx> +#include <viewimp.hxx> +#include <breakit.hxx> +#include <pam.hxx> +#include <unotextrange.hxx> +#include <pagefrm.hxx> +#include <cntfrm.hxx> +#include <txtfrm.hxx> +#include <rootfrm.hxx> +#include <poolfmt.hxx> +#include <pagedesc.hxx> +#include <GrammarContact.hxx> +#include <viewopt.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/propertysetinfo.hxx> +#include <comphelper/sequence.hxx> +#include <sal/log.hxx> + +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/text/XTextRange.hpp> + +using namespace ::com::sun::star; + +namespace SwUnoCursorHelper { + +uno::Reference<text::XFlatParagraphIterator> +CreateFlatParagraphIterator(SwDoc & rDoc, sal_Int32 const nTextMarkupType, + bool const bAutomatic) +{ + return new SwXFlatParagraphIterator(rDoc, nTextMarkupType, bAutomatic); +} + +} + +SwXFlatParagraph::SwXFlatParagraph( SwTextNode& rTextNode, OUString aExpandText, const ModelToViewHelper& rMap ) + : SwXFlatParagraph_Base(& rTextNode, rMap) + , maExpandText(std::move(aExpandText)) + , maOrigText(rTextNode.GetText()) +{ +} + +SwXFlatParagraph::~SwXFlatParagraph() +{ +} + + +// XPropertySet +uno::Reference< beans::XPropertySetInfo > SAL_CALL +SwXFlatParagraph::getPropertySetInfo() +{ + static const comphelper::PropertyMapEntry s_Entries[] = { + { OUString("FieldPositions"), -1, ::cppu::UnoType<uno::Sequence<sal_Int32>>::get(), beans::PropertyAttribute::READONLY, 0 }, + { OUString("FootnotePositions"), -1, ::cppu::UnoType<uno::Sequence<sal_Int32>>::get(), beans::PropertyAttribute::READONLY, 0 }, + { OUString("SortedTextId"), -1, ::cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 }, + { OUString("DocumentElementsCount"), -1, ::cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 }, + }; + return new comphelper::PropertySetInfo(s_Entries); +} + +void SAL_CALL +SwXFlatParagraph::setPropertyValue(const OUString&, const uno::Any&) +{ + throw lang::IllegalArgumentException("no values can be set", + getXWeak(), 0); +} + +uno::Any SAL_CALL +SwXFlatParagraph::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard g; + + if (rPropertyName == "FieldPositions") + { + return uno::Any( comphelper::containerToSequence( GetConversionMap().getFieldPositions() ) ); + } + else if (rPropertyName == "FootnotePositions") + { + return uno::Any( comphelper::containerToSequence( GetConversionMap().getFootnotePositions() ) ); + } + else if (rPropertyName == "SortedTextId") + { + SwTextNode const*const pCurrentNode = GetTextNode(); + sal_Int32 nIndex = -1; + if ( pCurrentNode ) + nIndex = pCurrentNode->GetIndex().get(); + return uno::Any( nIndex ); + } + else if (rPropertyName == "DocumentElementsCount") + { + SwTextNode const*const pCurrentNode = GetTextNode(); + sal_Int32 nCount = -1; + if ( pCurrentNode ) + nCount = pCurrentNode->GetDoc().GetNodes().Count().get(); + return uno::Any( nCount ); + } + return uno::Any(); +} + +void SAL_CALL +SwXFlatParagraph::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + SAL_WARN("sw.uno", + "SwXFlatParagraph::addPropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXFlatParagraph::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/) +{ + SAL_WARN("sw.uno", + "SwXFlatParagraph::removePropertyChangeListener(): not implemented"); +} + +void SAL_CALL +SwXFlatParagraph::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + SAL_WARN("sw.uno", + "SwXFlatParagraph::addVetoableChangeListener(): not implemented"); +} + +void SAL_CALL +SwXFlatParagraph::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/) +{ + SAL_WARN("sw.uno", + "SwXFlatParagraph::removeVetoableChangeListener(): not implemented"); +} + + +css::uno::Reference< css::container::XStringKeyMap > SAL_CALL SwXFlatParagraph::getMarkupInfoContainer() +{ + return SwXTextMarkup::getMarkupInfoContainer(); +} + +void SAL_CALL SwXFlatParagraph::commitTextRangeMarkup(::sal_Int32 nType, const OUString & aIdentifier, const uno::Reference< text::XTextRange> & xRange, + const css::uno::Reference< css::container::XStringKeyMap > & xMarkupInfoContainer) +{ + SolarMutexGuard aGuard; + SwXTextMarkup::commitTextRangeMarkup( nType, aIdentifier, xRange, xMarkupInfoContainer ); +} + +void SAL_CALL SwXFlatParagraph::commitStringMarkup(::sal_Int32 nType, const OUString & rIdentifier, ::sal_Int32 nStart, ::sal_Int32 nLength, const css::uno::Reference< css::container::XStringKeyMap > & rxMarkupInfoContainer) +{ + SolarMutexGuard aGuard; + SwXTextMarkup::commitStringMarkup( nType, rIdentifier, nStart, nLength, rxMarkupInfoContainer ); +} + +// text::XFlatParagraph: +OUString SAL_CALL SwXFlatParagraph::getText() +{ + return maExpandText; +} + +// text::XFlatParagraph: +void SAL_CALL SwXFlatParagraph::setChecked( ::sal_Int32 nType, sal_Bool bVal ) +{ + SolarMutexGuard aGuard; + + if (!GetTextNode()) + return; + + if ( text::TextMarkupType::SPELLCHECK == nType ) + { + GetTextNode()->SetWrongDirty( + bVal ? sw::WrongState::DONE : sw::WrongState::TODO); + } + else if ( text::TextMarkupType::SMARTTAG == nType ) + GetTextNode()->SetSmartTagDirty( !bVal ); + else if( text::TextMarkupType::PROOFREADING == nType ) + { + GetTextNode()->SetGrammarCheckDirty( !bVal ); + if( bVal ) + sw::finishGrammarCheckFor(*GetTextNode()); + } +} + +// text::XFlatParagraph: +sal_Bool SAL_CALL SwXFlatParagraph::isChecked( ::sal_Int32 nType ) +{ + SolarMutexGuard aGuard; + if (GetTextNode()) + { + if ( text::TextMarkupType::SPELLCHECK == nType ) + return !GetTextNode()->IsWrongDirty(); + else if ( text::TextMarkupType::PROOFREADING == nType ) + return !GetTextNode()->IsGrammarCheckDirty(); + else if ( text::TextMarkupType::SMARTTAG == nType ) + return !GetTextNode()->IsSmartTagDirty(); + } + + return true; +} + +// text::XFlatParagraph: +sal_Bool SAL_CALL SwXFlatParagraph::isModified() +{ + SolarMutexGuard aGuard; + return !GetTextNode() || GetTextNode()->GetText() != maOrigText; +} + +// text::XFlatParagraph: +lang::Locale SAL_CALL SwXFlatParagraph::getLanguageOfText(::sal_Int32 nPos, ::sal_Int32 nLen) +{ + SolarMutexGuard aGuard; + if (!GetTextNode()) + return LanguageTag::convertToLocale( LANGUAGE_NONE ); + + const lang::Locale aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos, nLen) ) ); + return aLocale; +} + +// text::XFlatParagraph: +lang::Locale SAL_CALL SwXFlatParagraph::getPrimaryLanguageOfText(::sal_Int32 nPos, ::sal_Int32 nLen) +{ + SolarMutexGuard aGuard; + + if (!GetTextNode()) + return LanguageTag::convertToLocale( LANGUAGE_NONE ); + + const lang::Locale aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos, nLen) ) ); + return aLocale; +} + +// text::XFlatParagraph: +void SAL_CALL SwXFlatParagraph::changeText(::sal_Int32 nPos, ::sal_Int32 nLen, const OUString & aNewText, const css::uno::Sequence< css::beans::PropertyValue > & aAttributes) +{ + SolarMutexGuard aGuard; + + if (!GetTextNode()) + return; + + SwTextNode *const pOldTextNode = GetTextNode(); + + if (nPos < 0 || pOldTextNode->Len() < nPos || nLen < 0 || o3tl::make_unsigned(pOldTextNode->Len()) < static_cast<sal_uInt32>(nPos) + nLen) + { + throw lang::IllegalArgumentException(); + } + + SwPaM aPaM( *GetTextNode(), nPos, *GetTextNode(), nPos+nLen ); + + UnoActionContext aAction( &GetTextNode()->GetDoc() ); + + const rtl::Reference<SwXTextRange> xRange = + SwXTextRange::CreateXTextRange( + GetTextNode()->GetDoc(), *aPaM.GetPoint(), aPaM.GetMark() ); + if ( xRange.is() ) + { + for ( const auto& rAttribute : aAttributes ) + xRange->setPropertyValue( rAttribute.Name, rAttribute.Value ); + } + + IDocumentContentOperations& rIDCO = pOldTextNode->getIDocumentContentOperations(); + rIDCO.ReplaceRange( aPaM, aNewText, false ); + + ClearTextNode(); // TODO: is this really needed? +} + +// text::XFlatParagraph: +void SAL_CALL SwXFlatParagraph::changeAttributes(::sal_Int32 nPos, ::sal_Int32 nLen, const css::uno::Sequence< css::beans::PropertyValue > & aAttributes) +{ + SolarMutexGuard aGuard; + + if (!GetTextNode()) + return; + + if (nPos < 0 || GetTextNode()->Len() < nPos || nLen < 0 || o3tl::make_unsigned(GetTextNode()->Len()) < static_cast<sal_uInt32>(nPos) + nLen) + { + throw lang::IllegalArgumentException(); + } + + SwPaM aPaM( *GetTextNode(), nPos, *GetTextNode(), nPos+nLen ); + + UnoActionContext aAction( &GetTextNode()->GetDoc() ); + + const rtl::Reference<SwXTextRange> xRange = + SwXTextRange::CreateXTextRange( + GetTextNode()->GetDoc(), *aPaM.GetPoint(), aPaM.GetMark() ); + if ( xRange.is() ) + { + for ( const auto& rAttribute : aAttributes ) + xRange->setPropertyValue( rAttribute.Name, rAttribute.Value ); + } + + ClearTextNode(); // TODO: is this really needed? +} + +// text::XFlatParagraph: +css::uno::Sequence< ::sal_Int32 > SAL_CALL SwXFlatParagraph::getLanguagePortions() +{ + return css::uno::Sequence< ::sal_Int32>(); +} + +SwXFlatParagraphIterator::SwXFlatParagraphIterator( SwDoc& rDoc, sal_Int32 nType, bool bAutomatic ) + : mpDoc( &rDoc ), + mnType( nType ), + mbAutomatic( bAutomatic ), + mnCurrentNode( 0 ), + mnEndNode( rDoc.GetNodes().Count() ) +{ + //mnStartNode = mnCurrentNode = get node from current cursor TODO! + + // register as listener and get notified when document is closed + StartListening(mpDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_STANDARD )->GetNotifier()); +} + +SwXFlatParagraphIterator::~SwXFlatParagraphIterator() +{ + SolarMutexGuard aGuard; + EndListeningAll(); +} + +void SwXFlatParagraphIterator::Notify( const SfxHint& rHint ) +{ + if(rHint.GetId() == SfxHintId::Dying) + { + SolarMutexGuard aGuard; + mpDoc = nullptr; + } +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getFirstPara() +{ + return getNextPara(); // TODO +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getNextPara() +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XFlatParagraph > xRet; + if (!mpDoc) + return xRet; + + SwTextNode* pRet = nullptr; + if ( mbAutomatic ) + { + SwViewShell* pViewShell = mpDoc->getIDocumentLayoutAccess().GetCurrentViewShell(); + + SwPageFrame* pCurrentPage = pViewShell ? pViewShell->Imp()->GetFirstVisPage(pViewShell->GetOut()) : nullptr; + SwPageFrame* pStartPage = pCurrentPage; + SwPageFrame* pStopPage = nullptr; + + while ( pCurrentPage && pCurrentPage != pStopPage ) + { + if (mnType != text::TextMarkupType::SPELLCHECK || pCurrentPage->IsInvalidSpelling() ) + { + // this method is supposed to return an empty paragraph in case Online Checking is disabled + if ( ( mnType == text::TextMarkupType::PROOFREADING || mnType == text::TextMarkupType::SPELLCHECK ) + && !pViewShell->GetViewOptions()->IsOnlineSpell() ) + return xRet; + + // search for invalid content: + SwContentFrame* pCnt = pCurrentPage->ContainsContent(); + + while( pCnt && pCurrentPage->IsAnLower( pCnt ) ) + { + if (pCnt->IsTextFrame()) + { + SwTextFrame const*const pText(static_cast<SwTextFrame const*>(pCnt)); + if (sw::MergedPara const*const pMergedPara = pText->GetMergedPara() + ) + { + SwTextNode * pTextNode(nullptr); + for (auto const& e : pMergedPara->extents) + { + if (e.pNode != pTextNode) + { + pTextNode = e.pNode; + if ((mnType == text::TextMarkupType::SPELLCHECK + && pTextNode->IsWrongDirty()) || + (mnType == text::TextMarkupType::PROOFREADING + && pTextNode->IsGrammarCheckDirty())) + { + pRet = pTextNode; + break; + } + } + } + } + else + { + SwTextNode const*const pTextNode(pText->GetTextNodeFirst()); + if ((mnType == text::TextMarkupType::SPELLCHECK + && pTextNode->IsWrongDirty()) || + (mnType == text::TextMarkupType::PROOFREADING + && pTextNode->IsGrammarCheckDirty())) + + { + pRet = const_cast<SwTextNode*>(pTextNode); + } + } + + if (pRet) + { + break; + } + } + + pCnt = pCnt->GetNextContentFrame(); + } + } + + if ( pRet ) + break; + + // if there is no invalid text node on the current page, + // we validate the page + pCurrentPage->ValidateSpelling(); + + // proceed with next page, wrap at end of document if required: + pCurrentPage = static_cast<SwPageFrame*>(pCurrentPage->GetNext()); + + if ( !pCurrentPage && !pStopPage ) + { + pStopPage = pStartPage; + pCurrentPage = static_cast<SwPageFrame*>(pViewShell->GetLayout()->Lower()); + } + } + } + else // non-automatic checking + { + const SwNodes& rNodes = mpDoc->GetNodes(); + const SwNodeOffset nMaxNodes = rNodes.Count(); + + while ( mnCurrentNode < mnEndNode && mnCurrentNode < nMaxNodes ) + { + SwNode* pNd = rNodes[ mnCurrentNode ]; + + ++mnCurrentNode; + + pRet = pNd->GetTextNode(); + if ( pRet ) + break; + + if ( mnCurrentNode == mnEndNode ) + { + mnCurrentNode = SwNodeOffset(0); + mnEndNode = SwNodeOffset(0); + } + } + } + + if ( pRet ) + { + // Expand the string: + const ModelToViewHelper aConversionMap(*pRet, mpDoc->getIDocumentLayoutAccess().GetCurrentLayout()); + const OUString& aExpandText = aConversionMap.getViewText(); + + xRet = new SwXFlatParagraph( *pRet, aExpandText, aConversionMap ); + } + + return xRet; +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getLastPara() +{ + return getNextPara(); +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getParaAfter(const uno::Reference< text::XFlatParagraph > & xPara) +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XFlatParagraph > xRet; + if (!mpDoc) + return xRet; + + SwXFlatParagraph* const pFlatParagraph(dynamic_cast<SwXFlatParagraph*>(xPara.get())); + SAL_WARN_IF(!pFlatParagraph, "sw.core", "invalid argument"); + if ( !pFlatParagraph ) + return xRet; + + SwTextNode const*const pCurrentNode = pFlatParagraph->GetTextNode(); + + if ( !pCurrentNode ) + return xRet; + + SwTextNode* pNextTextNode = nullptr; + const SwNodes& rNodes = pCurrentNode->GetDoc().GetNodes(); + + for( SwNodeOffset nCurrentNode = pCurrentNode->GetIndex() + 1; nCurrentNode < rNodes.Count(); ++nCurrentNode ) + { + SwNode* pNd = rNodes[ nCurrentNode ]; + pNextTextNode = pNd->GetTextNode(); + if ( pNextTextNode ) + break; + } + + if ( pNextTextNode ) + { + // Expand the string: + const ModelToViewHelper aConversionMap(*pNextTextNode, mpDoc->getIDocumentLayoutAccess().GetCurrentLayout()); + const OUString& aExpandText = aConversionMap.getViewText(); + + xRet = new SwXFlatParagraph( *pNextTextNode, aExpandText, aConversionMap ); + } + + return xRet; +} + +uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getParaBefore(const uno::Reference< text::XFlatParagraph > & xPara ) +{ + SolarMutexGuard aGuard; + + uno::Reference< text::XFlatParagraph > xRet; + if (!mpDoc) + return xRet; + + SwXFlatParagraph* const pFlatParagraph(dynamic_cast<SwXFlatParagraph*>(xPara.get())); + SAL_WARN_IF(!pFlatParagraph, "sw.core", "invalid argument"); + if ( !pFlatParagraph ) + return xRet; + + SwTextNode const*const pCurrentNode = pFlatParagraph->GetTextNode(); + + if ( !pCurrentNode ) + return xRet; + + SwTextNode* pPrevTextNode = nullptr; + const SwNodes& rNodes = pCurrentNode->GetDoc().GetNodes(); + + for( SwNodeOffset nCurrentNode = pCurrentNode->GetIndex() - 1; nCurrentNode > SwNodeOffset(0); --nCurrentNode ) + { + SwNode* pNd = rNodes[ nCurrentNode ]; + pPrevTextNode = pNd->GetTextNode(); + if ( pPrevTextNode ) + break; + } + + if ( pPrevTextNode ) + { + // Expand the string: + const ModelToViewHelper aConversionMap(*pPrevTextNode, mpDoc->getIDocumentLayoutAccess().GetCurrentLayout()); + const OUString& aExpandText = aConversionMap.getViewText(); + + xRet = new SwXFlatParagraph( *pPrevTextNode, aExpandText, aConversionMap ); + } + + return xRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |