/* -*- 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 .
*/
void lcl_CollectFrameAtNodeWithLayout(const SwContentFrame* pCFrame,
FrameClientSortList_t& rFrames, const RndStdIds nAnchorType)
{ auto pObjs = pCFrame->GetDrawObjs(); if(!pObjs) return; for(constauto pAnchoredObj : *pObjs)
{
SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat(); // Filter out textboxes, which are not interesting at a UNO level. if(SwTextBoxHelper::isTextBox(pFormat, RES_FLYFRMFMT)) continue;
if (nAnchorType == RndStdIds::FLY_AT_PARA)
{ auto pFlyAtContentFrame = dynamic_cast<SwFlyAtContentFrame*>(pAnchoredObj); if (pFlyAtContentFrame && pFlyAtContentFrame->IsFollow())
{ // We're collecting frame formats, ignore non-master fly frames to prevent // duplication. continue;
}
}
UnoActionContext::~UnoActionContext() COVERITY_NOEXCEPT_FALSE
{ // Doc may already have been removed here if (m_pDoc)
{
SwRootFrame *const pRootFrame = m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); if (pRootFrame)
{
pRootFrame->EndAllAction();
}
}
}
UnoActionRemoveContext::UnoActionRemoveContext(SwUnoTableCursor const& rCursor)
: m_pDoc(lcl_IsNewStyleTable(rCursor))
{ // this insanity is only necessary for old-style tables // because SwRootFrame::MakeTableCursors() creates the table cursor for these if (m_pDoc)
{
lcl_RemoveImpl(m_pDoc);
}
}
UnoActionRemoveContext::~UnoActionRemoveContext() COVERITY_NOEXCEPT_FALSE
{ if (m_pDoc)
{
SwRootFrame *const pRootFrame = m_pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); if (pRootFrame)
{
pRootFrame->UnoRestoreAllActions();
}
}
}
// the first node inserts the values into the get set // all other nodes merge their values into the get set for (SwNodeOffset n = nSttNd; n <= nEndNd; ++n)
{
SwNode *const pNd = rPam.GetDoc().GetNodes()[ n ]; switch (pNd->GetNodeType())
{ case SwNodeType::Text:
{ const sal_Int32 nStart = (n == nSttNd)
? rStart.GetContentIndex() : 0; const sal_Int32 nEnd = (n == nEndNd)
? rEnd.GetContentIndex()
: pNd->GetTextNode()->GetText().getLength();
pNd->GetTextNode()->GetParaAttr(*pSet, nStart, nEnd, bOnlyTextAttr, bGetFromChrFormat);
} break;
case SwNodeType::Grf: case SwNodeType::Ole: static_cast<SwContentNode*>(pNd)->GetAttr( *pSet ); break;
default: continue; // skip this node
}
if (pSet != &rSet)
{
rSet.MergeValues( aSet );
} else
{
pSet = &aSet;
}
if (aSet.Count())
{
aSet.ClearItem();
}
}
}
}
namespace {
struct SwXParagraphEnumerationImpl final : public SwXParagraphEnumeration
{
uno::Reference< text::XText > const m_xParentText; const CursorType m_eCursorType; /// Start node of the cell _or_ table the enumeration belongs to. /// Used to restrict the movement of the UNO cursor to the cell and its /// embedded tables.
SwStartNode const*const m_pOwnStartNode;
SwTable const*const m_pOwnTable; const SwNodeOffset m_nEndIndex;
sal_Int32 m_nFirstParaStart;
sal_Int32 m_nLastParaEnd; bool m_bFirstParagraph;
uno::Reference< text::XTextContent > m_xNextPara;
sw::UnoCursorPointer m_pCursor;
SwXParagraphEnumerationImpl(
uno::Reference< text::XText > xParent, const std::shared_ptr<SwUnoCursor>& pCursor, const CursorType eType,
SwStartNode const*const pStartNode, SwTable const*const pTable)
: m_xParentText(std::move( xParent ))
, m_eCursorType( eType ) // remember table and start node for later travelling // (used in export of tables in tables)
, m_pOwnStartNode( pStartNode ) // for import of tables in tables we have to remember the actual // table and start node of the current position in the enumeration.
, m_pOwnTable( pTable )
, m_nEndIndex( pCursor->End()->GetNodeIndex() )
, m_nFirstParaStart( -1 )
, m_nLastParaEnd( -1 )
, m_bFirstParagraph( true )
, m_pCursor(pCursor)
{
OSL_ENSURE(m_xParentText.is(), "SwXParagraphEnumeration: no parent?");
assert( !((CursorType::SelectionInTable == eType)
|| (CursorType::TableText == eType))
|| (m_pOwnTable && m_pOwnStartNode));
/** * Determines if the last element in the enumeration should be ignored or * not.
*/ bool IgnoreLastElement(SwUnoCursor& rCursor, bool bMovedFromTable);
};
//!! compare to SwShellTableCursor::FillRects() in viscrs.cxx static SwTableNode *
lcl_FindTopLevelTable(
SwTableNode *const pTableNode, SwTable const*const pOwnTable)
{ // find top-most table in current context (section) level
SwTableNode * pLast = pTableNode; for (SwTableNode* pTmp = pLast;
pTmp != nullptr && &pTmp->GetTable() != pOwnTable; /* we must not go up higher than the own table! */
pTmp = pTmp->StartOfSectionNode()->FindTableNode() )
{
pLast = pTmp;
} return pLast;
}
staticbool
lcl_CursorIsInSection(
SwUnoCursor const*const pUnoCursor, SwStartNode const*const pOwnStartNode)
{ // returns true if the cursor is in the section (or in a sub section!) // represented by pOwnStartNode
bool SwXParagraphEnumerationImpl::IgnoreLastElement(SwUnoCursor& rCursor, bool bMovedFromTable)
{ // Ignore the last element of a selection enumeration if this is a stub // paragraph (directly after table, selection ends at paragraph start).
if (rCursor.Start()->GetNodeIndex() != m_nEndIndex) returnfalse;
if (m_eCursorType != CursorType::Selection) returnfalse;
// check for exceeding selections if (!m_bFirstParagraph &&
((CursorType::Selection == m_eCursorType) ||
(CursorType::SelectionInTable == m_eCursorType)))
{
SwPosition* pStart = rUnoCursor.Start(); auto aNewCursor(rUnoCursor.GetDoc().CreateUnoCursor(*pStart)); // one may also go into tables here if (CursorType::SelectionInTable != m_eCursorType)
{
aNewCursor->SetRemainInSection( false );
}
// os 2005-01-14: This part is only necessary to detect movements out // of a selection; if there is no selection we don't have to care
SwTableNode *const pTableNode = aNewCursor->GetPointNode().FindTableNode(); bool bMovedFromTable = false; if (CursorType::SelectionInTable != m_eCursorType && pTableNode)
{
aNewCursor->GetPoint()->Assign( pTableNode->EndOfSectionIndex() );
aNewCursor->Move(fnMoveForward, GoInNode);
bMovedFromTable = true;
} else
{
aNewCursor->MovePara(GoNextPara, fnParaStart);
} if (m_nEndIndex < aNewCursor->Start()->GetNodeIndex())
{ return nullptr;
}
if (IgnoreLastElement(*aNewCursor, bMovedFromTable))
{ return nullptr;
}
}
bool bInTable = false; if (!m_bFirstParagraph)
{
rUnoCursor.SetRemainInSection( false ); // what to do if already in a table?
SwTableNode * pTableNode = rUnoCursor.GetPointNode().FindTableNode();
pTableNode = lcl_FindTopLevelTable( pTableNode, m_pOwnTable ); if (pTableNode && (&pTableNode->GetTable() != m_pOwnTable))
{ // this is a foreign table: go to end
rUnoCursor.GetPoint()->Assign( pTableNode->EndOfSectionIndex() ); if (!rUnoCursor.Move(fnMoveForward, GoInNode))
{ return nullptr;
}
bInTable = true;
}
}
uno::Reference< text::XTextContent > xRef; // the cursor must remain in the current section or a subsection // before AND after the movement... if (lcl_CursorIsInSection( &rUnoCursor, m_pOwnStartNode ) &&
(m_bFirstParagraph || bInTable ||
(rUnoCursor.MovePara(GoNextPara, fnParaStart) &&
lcl_CursorIsInSection( &rUnoCursor, m_pOwnStartNode ))))
{ if (m_eCursorType == CursorType::Selection || m_eCursorType == CursorType::SelectionInTable)
{ // This is a selection, check if the cursor would go past the end // of the selection. if (rUnoCursor.Start()->GetNodeIndex() > m_nEndIndex) return nullptr;
}
SwXTextRange::SwXTextRange(SwSectionFormat& rSectionFormat)
: m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR))
, m_eRangePosition(RANGE_IS_SECTION)
, m_isRangeInCell(false)
, m_rDoc(rSectionFormat.GetDoc())
, m_pTableOrSectionFormat(&rSectionFormat)
, m_pMark(nullptr)
, moSvtListener(std::in_place, *this)
{
moSvtListener->StartListening(rSectionFormat.GetNotifier()); // no SetPositions here for now
}
SwXTextRange::~SwXTextRange()
{ // have to destruct SvtListener with SolarMutex held
SolarMutexGuard aGuard;
InvalidateImpl(); // delete bookmark under SolarMutex
moSvtListener.reset();
}
staticvoid DeleteTable(SwDoc & rDoc, SwTable& rTable)
{
SwSelBoxes aSelBoxes; for (auto& rBox : rTable.GetTabSortBoxes())
{
aSelBoxes.insert(rBox);
} // note: if the table is the content in the section, this will create // a new text node - that's desirable here
rDoc.DeleteRowCol(aSelBoxes, SwDoc::RowColMode::DeleteProtected);
}
void SwXTextRange::DeleteAndInsert(
std::u16string_view aText, ::sw::DeleteAndInsertMode const eMode)
{ if (RANGE_IS_TABLE == m_eRangePosition)
{ // setString on table not allowed throw uno::RuntimeException(u"not possible for table"_ustr);
}
OUString sRet; // for tables there is no bookmark, thus also no text // one could export the table as ASCII here maybe?
SwPaM aPaM(GetDoc().GetNodes()); if (GetPositions(aPaM, sw::TextRangeMode::AllowNonTextNode) && aPaM.HasMark())
{
SwUnoCursorHelper::GetTextFromPam(aPaM, sRet);
} return sRet;
}
// if it's a text then create a temporary cursor there and re-use // the pCursor variable // #i108489#: Reference in outside scope to keep cursor alive
rtl::Reference< SwXTextCursor > xTextCursor;
OTextCursorHelper* pCursor; if (pHeadText)
{ // if it is a header / footer text, and eMode == TextRangeMode::AllowTableNode // then set the cursor to the beginning of the text // if it is started with a table then set into the table
xTextCursor = pHeadText->CreateTextCursor(true);
xTextCursor->gotoEnd(true);
pCursor = xTextCursor.get();
pCursor->GetPaM()->Normalize();
} elseif (SwXText* pText = dynamic_cast<SwXText*>(xTextRange.get()))
{
xTextCursor = pText->createXTextCursor();
xTextCursor->gotoEnd(true);
pCursor = xTextCursor.get();
} else
{
pCursor = dynamic_cast<OTextCursorHelper*>(xTextRange.get());
}
SwDoc* pDoc = nullptr; const SwPaM* pUnoCursor = nullptr; if (pCursor)
{
pDoc = pCursor->GetDoc();
pUnoCursor = pCursor->GetPaM();
} elseif (SwXTextPortion* pPortion = dynamic_cast<SwXTextPortion*>(xTextRange.get()))
{
pDoc = &pPortion->GetCursor().GetDoc();
pUnoCursor = &pPortion->GetCursor();
} return XTextRangeToSwPaMImpl(rToFill, pDoc, pUnoCursor);
}
staticbool XTextRangeToSwPaMImpl( SwUnoInternalPaM & rToFill, const SwDoc* pDoc, const SwPaM* pUnoCursor)
{ bool bRet = false; if (pUnoCursor && pDoc == &rToFill.GetDoc())
{
OSL_ENSURE(!pUnoCursor->IsMultiSelection(), "what to do about rings?");
bRet = true;
*rToFill.GetPoint() = *pUnoCursor->GetPoint(); if (pUnoCursor->HasMark())
{
rToFill.SetMark();
*rToFill.GetMark() = *pUnoCursor->GetMark();
} else
rToFill.DeleteMark();
} return bRet;
}
if (!m_pMark)
{ throw uno::RuntimeException(u"range has no mark (table?)"_ustr);
} const SwPosition aPos(GetDoc().GetNodes().GetEndOfContent()); constauto pNewCursor(m_rDoc.CreateUnoCursor(aPos)); if (!GetPositions(*pNewCursor))
{ throw uno::RuntimeException(u"range has no positions"_ustr);
}
if (!m_pMark)
{ throw uno::RuntimeException(u"range has no mark (table?)"_ustr);
} const SwPosition aPos(GetDoc().GetNodes().GetEndOfContent()); auto pNewCursor(m_rDoc.CreateUnoCursor(aPos)); if (!GetPositions(*pNewCursor))
{ throw uno::RuntimeException(u"range has no positions"_ustr);
} if (!m_xParentText.is())
{
getText();
}
if (!m_pMark)
{ throw uno::RuntimeException(u"range has no mark (table?)"_ustr);
}
SwPaM aPaM(GetDoc().GetNodes());
SwXTextRange::GetPositions(aPaM);
SwUnoCursorHelper::makeRedline( aPaM, rRedlineType, rRedlineProperties );
}
namespace {
struct SwXTextRangesImpl final : public SwXTextRanges
{
/* * Text positions * Up to the first access to a text position, only a SwCursor is stored. * Afterwards, an array with uno::Reference<XTextPosition> will be created.
*/
SwXParaFrameEnumerationImpl::SwXParaFrameEnumerationImpl( const SwPaM& rPaM, constenum ParaFrameMode eParaFrameMode,
SwFrameFormat* const pFormat)
: m_pUnoCursor(rPaM.GetDoc().CreateUnoCursor(*rPaM.GetPoint()))
{ if (rPaM.HasMark())
{
GetCursor().SetMark();
*GetCursor().GetMark() = *rPaM.GetMark();
} if (PARAFRAME_PORTION_PARAGRAPH == eParaFrameMode)
{
FrameClientSortList_t vFrames;
::CollectFrameAtNode(rPaM.GetPoint()->GetNode(), vFrames, false);
std::transform(vFrames.begin(), vFrames.end(),
std::back_inserter(m_vFrames),
[] (FrameClientSortListEntry& rEntry) { return std::move(rEntry.pFrameClient); });
} elseif (pFormat)
{
m_vFrames.push_back(std::make_unique<sw::FrameClient>(pFormat));
} elseif ((PARAFRAME_PORTION_CHAR == eParaFrameMode) ||
(PARAFRAME_PORTION_TEXTRANGE == eParaFrameMode))
{ if (PARAFRAME_PORTION_TEXTRANGE == eParaFrameMode)
{ //get all frames that are bound at paragraph or at character for(const SwPosFlyFrame& rFlyFrame : rPaM.GetDoc().GetAllFlyFormats(&GetCursor(), false, true))
{ constauto pFrameFormat = const_cast<SwFrameFormat*>(&rFlyFrame.GetFormat());
m_vFrames.push_back(std::make_unique<sw::FrameClient>(pFrameFormat));
}
}
FillFrame();
}
}
// Search for a FLYCNT text attribute at the cursor point and fill the frame // into the array void SwXParaFrameEnumerationImpl::FillFrame()
{ if(!m_pUnoCursor->GetPointNode().IsTextNode()) return; // search for objects at the cursor - anchored at/as char constauto pTextAttr = m_pUnoCursor->GetPointNode().GetTextNode()->GetTextAttrForCharAt(
m_pUnoCursor->GetPoint()->GetContentIndex(), RES_TXTATR_FLYCNT); if(!pTextAttr) return; const SwFormatFlyCnt& rFlyCnt = pTextAttr->GetFlyCnt();
SwFrameFormat* const pFrameFormat = rFlyCnt.GetFrameFormat();
m_vFrames.push_back(std::make_unique<sw::FrameClient>(pFrameFormat));
}
bool SwXParaFrameEnumerationImpl::CreateNextObject()
{ if (m_vFrames.empty()) returnfalse;
uno::Reference<text::XTextContent> xRet;
SwFrameFormat* const pFormat = static_cast<SwFrameFormat*>(pClient->GetRegisteredIn()); // the format should be valid here, otherwise the client // would have been removed by PurgeFrameClients // check for a shape first if(pFormat->Which() == RES_DRAWFRMFMT)
{
SdrObject* pObject(nullptr);
pFormat->CallSwClientNotify(sw::FindSdrObjectHint(pObject)); if(pObject)
xRet.set(pObject->getUnoShape(), uno::UNO_QUERY);
} else
{ const SwNodeIndex* pIdx = pFormat->GetContent().GetContentIdx();
assert(pIdx && "where is the index?");
SwNode const* const pNd = pIdx->GetNodes()[pIdx->GetIndex() + 1];
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.