/* -*- 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 <hintids.hxx>
#include <osl/diagnose.h>
#include <vcl/commandevent.hxx>
#include <unotools/charclass.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/string.hxx>
#include <unotools/transliterationwrapper.hxx>
#include <fmtsrnd.hxx>
#include <fmtinfmt.hxx>
#include <txtinet.hxx>
#include <frmfmt.hxx>
#include <charfmt.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentLinksAdministration.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <IDocumentStatistics.hxx>
#include <IDocumentState.hxx>
#include <editsh.hxx>
#include <frame.hxx>
#include <cntfrm.hxx>
#include <pam.hxx>
#include <ndtxt.hxx>
#include <flyfrm.hxx>
#include <swundo.hxx>
#include <calc.hxx>
#include <ndgrf.hxx>
#include <ndole.hxx>
#include <txtfrm.hxx>
#include <rootfrm.hxx>
#include <extinput.hxx>
#include <scriptinfo.hxx>
#include <unocrsrhelper.hxx>
#include <section.hxx>
#include <numrule.hxx>
#include <SwNodeNum.hxx>
#include <unocrsr.hxx>
#include <calbck.hxx>
using namespace com::sun::star;
void SwEditShell::Insert( sal_Unicode c, bool bOnlyCurrCursor )
{
StartAllAction();
for(SwPaM& rPaM : GetCursor()->GetRingContainer())
{
const bool bSuccess = GetDoc()->getIDocumentContentOperations().InsertString(rPaM, OUString(c));
OSL_ENSURE( bSuccess, "Doc->Insert() failed." );
SaveTableBoxContent( rPaM.GetPoint() );
if( bOnlyCurrCursor )
break;
}
EndAllAction();
}
void SwEditShell::Insert2(const OUString &rStr, const bool bForceExpandHints )
{
StartAllAction();
{
const SwInsertFlags nInsertFlags =
bForceExpandHints
? (SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND)
: SwInsertFlags::EMPTYEXPAND;
for(SwPaM& rCurrentCursor : getShellCursor( true )->GetRingContainer())
{
//OPT: GetSystemCharSet
GetDoc()->getIDocumentContentOperations().SetIME(false);
const bool bSuccess =
GetDoc()->getIDocumentContentOperations().InsertString(rCurrentCursor, rStr, nInsertFlags);
OSL_ENSURE( bSuccess, "Doc->Insert() failed." );
if (bSuccess)
{
GetDoc()->UpdateRsid( rCurrentCursor, rStr.getLength() );
// Set paragraph rsid if beginning of paragraph
SwTextNode *const pTextNode =
rCurrentCursor.GetPoint()->GetNode().GetTextNode();
if( pTextNode && pTextNode->Len() == 1)
GetDoc()->UpdateParRsid( pTextNode );
}
SaveTableBoxContent( rCurrentCursor.GetPoint() );
}
}
// calculate cursor bidi level
SwCursor* pTmpCursor = GetCursor_();
const bool bDoNotSetBidiLevel = ! pTmpCursor ||
( dynamic_cast<SwUnoCursor*>(pTmpCursor) != nullptr );
if ( ! bDoNotSetBidiLevel )
{
SwNode& rNode = pTmpCursor->GetPoint()->GetNode();
if ( rNode.IsTextNode() )
{
sal_Int32 nPrevPos = pTmpCursor->GetPoint()->GetContentIndex();
if ( nPrevPos )
--nPrevPos;
SwTextFrame const* pFrame;
SwScriptInfo *const pSI = SwScriptInfo::GetScriptInfo(
static_cast<SwTextNode&>(rNode), &pFrame, true);
sal_uInt8 nLevel = 0;
if ( ! pSI )
{
// seems to be an empty paragraph.
Point aPt;
std::pair<Point, bool> const tmp(aPt, false);
pFrame = static_cast<SwTextFrame*>(
static_cast<SwTextNode&>(rNode).getLayoutFrame(
GetLayout(), pTmpCursor->GetPoint(), &tmp));
SwScriptInfo aScriptInfo;
aScriptInfo.InitScriptInfo(static_cast<SwTextNode&>(rNode),
pFrame->GetMergedPara(), pFrame->IsRightToLeft());
TextFrameIndex const iPrevPos(pFrame->MapModelToView(
&static_cast<SwTextNode&>(rNode), nPrevPos));
nLevel = aScriptInfo.DirType( iPrevPos );
}
else
{
if (TextFrameIndex(COMPLETE_STRING) != pSI->GetInvalidityA())
{
// mystery why this doesn't use the other overload?
pSI->InitScriptInfo(static_cast<SwTextNode&>(rNode), pFrame->GetMergedPara());
}
TextFrameIndex const iPrevPos(pFrame->MapModelToView(
&static_cast<SwTextNode&>(rNode), nPrevPos));
nLevel = pSI->DirType(iPrevPos);
}
pTmpCursor->SetCursorBidiLevel( nLevel );
}
}
SetInFrontOfLabel( false ); // #i27615#
EndAllAction();
}
void SwEditShell::Overwrite(const OUString &rStr)
{
StartAllAction();
for(SwPaM& rPaM : GetCursor()->GetRingContainer())
{
if( !GetDoc()->getIDocumentContentOperations().Overwrite(rPaM, rStr ) )
{
OSL_FAIL( "Doc->getIDocumentContentOperations().Overwrite(Str) failed." );
}
SaveTableBoxContent( rPaM.GetPoint() );
}
EndAllAction();
}
void SwEditShell::SplitNode( bool bAutoFormat, bool bCheckTableStart )
{
StartAllAction();
GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
for(SwPaM& rPaM : GetCursor()->GetRingContainer())
{
// Here, a table cell becomes a normal text cell.
GetDoc()->ClearBoxNumAttrs( rPaM.GetPoint()->GetNode() );
GetDoc()->getIDocumentContentOperations().SplitNode( *rPaM.GetPoint(), bCheckTableStart );
}
GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
if( bAutoFormat )
AutoFormatBySplitNode();
ClearTableBoxContent();
EndAllAction();
}
bool SwEditShell::AppendTextNode()
{
bool bRet = false;
StartAllAction();
GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
for(SwPaM& rPaM : GetCursor()->GetRingContainer())
{
GetDoc()->ClearBoxNumAttrs( rPaM.GetPoint()->GetNode() );
bRet = GetDoc()->getIDocumentContentOperations().AppendTextNode( *rPaM.GetPoint()) || bRet;
}
GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
ClearTableBoxContent();
EndAllAction();
return bRet;
}
// the returned SwGrfNode pointer is used in GetGraphic() and GetGraphicSize()
SwGrfNode * SwEditShell::GetGrfNode_() const
{
SwGrfNode *pGrfNode = nullptr;
SwPaM* pCursor = GetCursor();
if( !pCursor->HasMark() ||
pCursor->GetPoint()->GetNode() == pCursor->GetMark()->GetNode() )
pGrfNode = pCursor->GetPoint()->GetNode().GetGrfNode();
return pGrfNode;
}
// returns a Graphic pointer if CurrentCursor->GetPoint() points to a SwGrfNode and
// GetMark is not set or points to the same Graphic
const Graphic* SwEditShell::GetGraphic( bool bWait ) const
{
SwGrfNode* pGrfNode = GetGrfNode_();
const Graphic* pGrf( nullptr );
if ( pGrfNode )
{
pGrf = &(pGrfNode->GetGrf(bWait && GraphicType::Default == pGrfNode->GetGrf().GetType()));
}
return pGrf;
}
bool SwEditShell::IsLinkedGrfSwapOut() const
{
SwGrfNode *pGrfNode = GetGrfNode_();
return pGrfNode &&
pGrfNode->IsLinkedFile() &&
GraphicType::Default == pGrfNode->GetGrfObj().GetType();
}
const GraphicObject* SwEditShell::GetGraphicObj() const
{
SwGrfNode* pGrfNode = GetGrfNode_();
return pGrfNode ? &(pGrfNode->GetGrfObj()) : nullptr;
}
const GraphicAttr* SwEditShell::GetGraphicAttr( GraphicAttr& rGA ) const
{
SwGrfNode* pGrfNode = GetGrfNode_();
const SwFrame* pFrame = GetCurrFrame(false);
return pGrfNode ? &(pGrfNode->GetGraphicAttr( rGA, pFrame )) : nullptr;
}
GraphicType SwEditShell::GetGraphicType() const
{
SwGrfNode *pGrfNode = GetGrfNode_();
return pGrfNode ? pGrfNode->GetGrfObj().GetType() : GraphicType::NONE;
}
// returns the size of a graphic in <rSz> if CurrentCursor->GetPoint() points to a SwGrfNode and
// GetMark is not set or points to the same graphic
bool SwEditShell::GetGrfSize(Size& rSz) const
{
SwNoTextNode* pNoTextNd;
SwPaM* pCurrentCursor = GetCursor();
if( ( !pCurrentCursor->HasMark()
|| pCurrentCursor->GetPoint()->GetNode() == pCurrentCursor->GetMark()->GetNode() )
&& nullptr != ( pNoTextNd = pCurrentCursor->GetPointNode().GetNoTextNode() ) )
{
rSz = pNoTextNd->GetTwipSize();
return true;
}
return false;
}
/// Read again if graphic is not OK and replace old one
void SwEditShell::ReRead( const OUString& rGrfName, const OUString& rFltName,
const Graphic* pGraphic )
{
StartAllAction();
mxDoc->getIDocumentContentOperations().ReRead( *GetCursor(), rGrfName, rFltName, pGraphic );
EndAllAction();
}
/// Returns the name and the filter name of a graphic if the pointer is on a graphic.
/// If a String-pointer is != 0 then return corresponding name.
void SwEditShell::GetGrfNms( OUString* pGrfName, OUString* pFltName ) const
{
OSL_ENSURE( pGrfName || pFltName, "No parameters" );
SwGrfNode *pGrfNode = GetGrfNode_();
if( pGrfNode && pGrfNode->IsLinkedFile() )
pGrfNode->GetFileFilterNms( pGrfName, pFltName );
}
const tools::PolyPolygon *SwEditShell::GetGraphicPolygon() const
{
SwNoTextNode *pNd = GetCursor()->GetPointNode().GetNoTextNode();
return pNd->HasContour();
}
void SwEditShell::SetGraphicPolygon( const tools::PolyPolygon *pPoly )
{
SwNoTextNode *pNd = GetCursor()->GetPointNode().GetNoTextNode();
StartAllAction();
pNd->SetContour( pPoly );
SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pNd->getLayoutFrame(GetLayout())->GetUpper());
const SwFormatSurround &rSur = pFly->GetFormat()->GetSurround();
pFly->GetFormat()->CallSwClientNotify(sw::LegacyModifyHint(&rSur, &rSur));
GetDoc()->getIDocumentState().SetModified();
EndAllAction();
}
void SwEditShell::ClearAutomaticContour()
{
SwNoTextNode *pNd = GetCursor()->GetPointNode().GetNoTextNode();
assert(pNd && "is no NoTextNode!");
if( pNd->HasAutomaticContour() )
{
StartAllAction();
pNd->SetContour( nullptr );
SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pNd->getLayoutFrame(GetLayout())->GetUpper());
const SwFormatSurround &rSur = pFly->GetFormat()->GetSurround();
pFly->GetFormat()->CallSwClientNotify(sw::LegacyModifyHint(&rSur, &rSur));
GetDoc()->getIDocumentState().SetModified();
EndAllAction();
}
}
/** Get OLE object at pointer.
*
* Returns a pointer to a SvInPlaceObjectRef if CurrentCursor->GetPoint() points to a SwOLENode and
* GetMark is not set or points to the same object reference. Gets this pointer from the Doc
* if the object should be searched by name.
*/
svt::EmbeddedObjectRef& SwEditShell::GetOLEObject() const
{
OSL_ENSURE( CNT_OLE == GetCntType(), "GetOLEObj: no OLENode." );
OSL_ENSURE( !GetCursor()->HasMark() ||
(GetCursor()->HasMark() &&
GetCursor()->GetPoint()->GetNode() == GetCursor()->GetMark()->GetNode()),
"GetOLEObj: no OLENode." );
SwOLENode *pOLENode = GetCursor()->GetPointNode().GetOLENode();
OSL_ENSURE( pOLENode, "GetOLEObj: no OLENode." );
SwOLEObj& rOObj = pOLENode->GetOLEObj();
return rOObj.GetObject();
}
bool SwEditShell::HasOLEObj( std::u16string_view rName ) const
{
SwStartNode *pStNd;
SwNodeIndex aIdx( *GetNodes().GetEndOfAutotext().StartOfSectionNode(), 1 );
while ( nullptr != (pStNd = aIdx.GetNode().GetStartNode()) )
{
++aIdx;
SwNode& rNd = aIdx.GetNode();
if( rNd.IsOLENode() &&
rName == static_cast<SwOLENode&>(rNd).GetChartTableName() &&
static_cast<SwOLENode&>(rNd).getLayoutFrame( GetLayout() ) )
return true;
aIdx.Assign( *pStNd->EndOfSectionNode(), + 1 );
}
return false;
}
void SwEditShell::SetChartName( const OUString &rName )
{
SwOLENode *pONd = GetCursor()->GetPointNode().GetOLENode();
OSL_ENSURE( pONd, "ChartNode not found" );
pONd->SetChartTableName( rName );
}
void SwEditShell::UpdateCharts( const OUString& rName )
{
GetDoc()->UpdateCharts( rName );
}
/// change table name
void SwEditShell::SetTableName( SwFrameFormat& rTableFormat, const OUString &rNewName )
{
GetDoc()->SetTableName( rTableFormat, rNewName );
}
/// request current word
OUString SwEditShell::GetCurWord() const
{
const SwPaM& rPaM = *GetCursor();
const SwTextNode* pNd = rPaM.GetPointNode().GetTextNode();
if (!pNd)
{
return OUString();
}
SwTextFrame const*const pFrame(static_cast<SwTextFrame*>(pNd->getLayoutFrame(GetLayout())));
if (pFrame)
{
return pFrame->GetCurWord(*rPaM.GetPoint());
}
return OUString();
}
void SwEditShell::UpdateDocStat( )
{
StartAllAction();
GetDoc()->getIDocumentStatistics().UpdateDocStat( false, true );
EndAllAction();
}
const SwDocStat& SwEditShell::GetUpdatedDocStat()
{
StartAllAction();
const SwDocStat &rRet = GetDoc()->getIDocumentStatistics().GetUpdatedDocStat( false, true );
EndAllAction();
return rRet;
}
/// get the reference of a given name in the Doc
const SwFormatRefMark* SwEditShell::GetRefMark( std::u16string_view rName ) const
{
return GetDoc()->GetRefMark( rName );
}
/// get the names of all references in a Doc
sal_uInt16 SwEditShell::GetRefMarks( std::vector<OUString>* pStrings ) const
{
return GetDoc()->GetRefMarks( pStrings );
}
OUString SwEditShell::GetDropText( const sal_Int32 nChars ) const
{
/*
* pb: made changes for #i74939#
*
* always return a string even though there is a selection
*/
OUString aText;
SwPaM* pCursor = GetCursor();
if ( IsMultiSelection() )
{
// if a multi selection exists, search for the first line
// -> it is the cursor with the lowest index
SwNodeOffset nIndex = pCursor->GetMark()->GetNodeIndex();
bool bPrev = true;
SwPaM* pLast = pCursor;
SwPaM* pTemp = pCursor;
while ( bPrev )
{
SwPaM* pPrev2 = pTemp->GetPrev();
bPrev = ( pPrev2 && pPrev2 != pLast );
if ( bPrev )
{
pTemp = pPrev2;
SwNodeOffset nTemp = pPrev2->GetMark()->GetNodeIndex();
if ( nTemp < nIndex )
{
nIndex = nTemp;
pCursor = pPrev2;
}
}
}
}
SwTextNode const*const pTextNd = pCursor->GetMarkNode().GetTextNode();
if( pTextNd )
{
SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(
pTextNd->getLayoutFrame(GetLayout())));
SAL_WARN_IF(!pTextFrame, "sw.core", "GetDropText cursor has no frame?");
if (pTextFrame)
{
TextFrameIndex const nDropLen(pTextFrame->GetDropLen(TextFrameIndex(nChars)));
aText = pTextFrame->GetText().copy(0, sal_Int32(nDropLen));
}
}
return aText;
}
void SwEditShell::ReplaceDropText( const OUString &rStr, SwPaM* pPaM )
{
SwPaM* pCursor = pPaM ? pPaM : GetCursor();
if( !(pCursor->GetPoint()->GetNode() == pCursor->GetMark()->GetNode() &&
pCursor->GetPointNode().GetTextNode()->IsTextNode()) )
return;
StartAllAction();
const SwNode& rNd = pCursor->GetPoint()->GetNode();
SwPaM aPam( rNd, rStr.getLength(), rNd, 0 );
SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(
rNd.GetTextNode()->getLayoutFrame(GetLayout())));
if (pTextFrame)
{
*aPam.GetPoint() = pTextFrame->MapViewToModelPos(TextFrameIndex(0));
*aPam.GetMark() = pTextFrame->MapViewToModelPos(TextFrameIndex(
std::min(rStr.getLength(), pTextFrame->GetText().getLength())));
}
if( !GetDoc()->getIDocumentContentOperations().Overwrite( aPam, rStr ) )
{
OSL_FAIL( "Doc->getIDocumentContentOperations().Overwrite(Str) failed." );
}
EndAllAction();
}
OUString SwEditShell::Calculate()
{
OUStringBuffer aFormel; // the final formula
SwCalc aCalc( *GetDoc() );
const CharClass& rCC = GetAppCharClass();
for(SwPaM& rCurrentPaM : GetCursor()->GetNext()->GetRingContainer())
{
SwTextNode* pTextNd = rCurrentPaM.GetPointNode().GetTextNode();
if(pTextNd)
{
const SwPosition *pStart = rCurrentPaM.Start(), *pEnd = rCurrentPaM.End();
const sal_Int32 nStt = pStart->GetContentIndex();
OUString aStr = pTextNd->GetExpandText(GetLayout(),
nStt, pEnd->GetContentIndex() - nStt);
aStr = rCC.lowercase( aStr );
bool bValidFields = false;
sal_Int32 nPos = 0;
while( nPos < aStr.getLength() )
{
sal_Unicode ch = aStr[ nPos++ ];
if( rCC.isLetter( aStr, nPos-1 ) || ch == '_' )
{
sal_Int32 nTmpStt = nPos-1;
while( nPos < aStr.getLength() &&
0 != ( ch = aStr[ nPos++ ]) &&
(rCC.isLetterNumeric( aStr, nPos - 1 ) ||
ch == '_'|| ch == '.' ))
;
if( nPos < aStr.getLength() )
--nPos;
OUString sVar = aStr.copy( nTmpStt, nPos - nTmpStt );
if( !::FindOperator( sVar ) &&
(aCalc.GetVarTable().find(sVar) != aCalc.GetVarTable().end() ||
aCalc.VarLook( sVar )) )
{
if( !bValidFields )
{
GetDoc()->getIDocumentFieldsAccess().FieldsToCalc( aCalc,
pStart->GetNodeIndex(),
pStart->GetContentIndex() );
bValidFields = true;
}
aFormel.append("(" + aCalc.GetStrResult( aCalc.VarLook( sVar )->nValue ) + ")");
}
else
aFormel.append(sVar);
}
else
aFormel.append(ch);
}
}
}
return aCalc.GetStrResult( aCalc.Calculate(aFormel.makeStringAndClear()) );
}
sfx2::LinkManager& SwEditShell::GetLinkManager()
{
return mxDoc->getIDocumentLinksAdministration().GetLinkManager();
}
void *SwEditShell::GetIMapInventor() const
{
// The node on which the cursor points should be sufficient as a unique identifier
return static_cast<void*>(&(GetCursor()->GetPointNode()));
}
// #i73788#
Graphic SwEditShell::GetIMapGraphic() const
{
// returns always a graphic if the cursor is in a Fly
CurrShell aCurr( const_cast<SwEditShell*>(this) );
Graphic aRet;
SwPaM* pCursor = GetCursor();
if ( !pCursor->HasMark() )
{
SwNode& rNd =pCursor->GetPointNode();
if( rNd.IsGrfNode() )
{
SwGrfNode & rGrfNode(static_cast<SwGrfNode&>(rNd));
aRet = rGrfNode.GetGrf(GraphicType::Default == rGrfNode.GetGrf().GetType());
}
else if ( rNd.IsOLENode() )
{
if (const Graphic* pGraphic = static_cast<SwOLENode&>(rNd).GetGraphic())
aRet = *pGraphic;
}
else
{
SwFlyFrame* pFlyFrame = rNd.GetContentNode()->getLayoutFrame( GetLayout() )->FindFlyFrame();
if(pFlyFrame)
aRet = pFlyFrame->GetFormat()->MakeGraphic();
}
}
return aRet;
}
bool SwEditShell::InsertURL( const SwFormatINetFormat& rFormat, const OUString& rStr, bool bKeepSelection )
{
// URL and hint text (directly or via selection) necessary
if( rFormat.GetValue().isEmpty() || ( rStr.isEmpty() && !HasSelection() ) )
return false;
StartAllAction();
GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_INSERT_URLTXT, nullptr);
bool bInsText = true;
if( !rStr.isEmpty() )
{
SwPaM* pCursor = GetCursor();
if( pCursor->HasMark() && *pCursor->GetPoint() != *pCursor->GetMark() )
{
// Selection existent, multi selection?
bool bDelText = true;
if( !pCursor->IsMultiSelection() )
{
// simple selection -> check the text
const OUString sText(comphelper::string::stripEnd(GetSelText(), ' '));
if( sText == rStr )
bDelText = bInsText = false;
}
else if( rFormat.GetValue() == rStr ) // Are Name and URL equal?
bDelText = bInsText = false;
if( bDelText )
Delete(true);
}
else if( pCursor->IsMultiSelection() && rFormat.GetValue() == rStr )
bInsText = false;
if( bInsText )
{
Insert2( rStr );
SetMark();
ExtendSelection( false, rStr.getLength() );
}
}
else
bInsText = false;
SetAttrItem( rFormat );
if (bInsText && !IsCursorPtAtEnd())
SwapPam();
if(!bKeepSelection)
ClearMark();
if( bInsText )
DontExpandFormat();
GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::UI_INSERT_URLTXT, nullptr );
EndAllAction();
return true;
}
void SwEditShell::GetINetAttrs(SwGetINetAttrs& rArr, bool bIncludeInToxContent)
{
rArr.clear();
const SwCharFormats* pFormats = GetDoc()->GetCharFormats();
for( auto n = pFormats->size(); 1 < n; )
{
SwIterator<SwTextINetFormat,SwCharFormat> aIter(*(*pFormats)[--n]);
for( SwTextINetFormat* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
{
SwTextNode const*const pTextNd(pFnd->GetpTextNode());
SwTextFrame const*const pFrame(pTextNd
? static_cast<SwTextFrame const*>(pTextNd->getLayoutFrame(GetLayout()))
: nullptr);
if (nullptr != pTextNd && nullptr != pFrame
&& pTextNd->GetNodes().IsDocNodes()
// check it's not fully deleted
&& pFrame->MapModelToView(pTextNd, pFnd->GetStart())
!= pFrame->MapModelToView(pTextNd, *pFnd->GetEnd()))
{
// tdf#52113, tdf#148312 Don't include table of contents hyperlinks in the
// Navigator content tree Hyperlinks entries
if (!bIncludeInToxContent)
{
if(const SwSectionNode* pSectNd = pTextNd->FindSectionNode())
{
SectionType eType = pSectNd->GetSection().GetType();
if(SectionType::ToxContent == eType)
continue;
}
}
SwTextINetFormat& rAttr = *pFnd;
OUString sText( pTextNd->GetExpandText(GetLayout(),
rAttr.GetStart(), *rAttr.GetEnd() - rAttr.GetStart()) );
sText = sText.replaceAll("\x0a", "");
sText = comphelper::string::strip(sText, ' ');
if( !sText.isEmpty() )
{
rArr.emplace_back(sText, rAttr);
}
}
}
}
}
/// If the cursor is in an INetAttribute then it will be deleted completely (incl. hint text, the
/// latter is needed for drag & drop)
void SwEditShell::DelINetAttrWithText()
{
bool bRet = SelectTextAttr( RES_TXTATR_INETFMT, false );
if( bRet )
DeleteSel(*GetCursor(), true);
}
/// Set the DontExpand flag at the text character attributes
bool SwEditShell::DontExpandFormat()
{
bool bRet = false;
if( !IsTableMode() && GetDoc()->DontExpandFormat( *GetCursor()->GetPoint() ))
{
bRet = true;
CallChgLnk();
}
return bRet;
}
SvNumberFormatter* SwEditShell::GetNumberFormatter()
{
return GetDoc()->GetNumberFormatter();
}
bool SwEditShell::ConvertFieldsToText()
{
StartAllAction();
bool bRet = GetDoc()->ConvertFieldsToText(*GetLayout());
EndAllAction();
return bRet;
}
void SwEditShell::SetNumberingRestart()
{
StartAllAction();
Push();
// iterate over all text contents - body, frames, header, footer, footnote text
SwPaM* pCursor = GetCursor();
for(int i = 0; i < 2; i++)
{
if(!i)
MakeFindRange(SwDocPositions::Start, SwDocPositions::End, pCursor); // body content
else
MakeFindRange(SwDocPositions::OtherStart, SwDocPositions::OtherEnd, pCursor); // extra content
SwPosition* pSttPos = pCursor->Start(), *pEndPos = pCursor->End();
SwNodeOffset nCurrNd = pSttPos->GetNodeIndex();
SwNodeOffset nEndNd = pEndPos->GetNodeIndex();
if( nCurrNd <= nEndNd )
{
SwContentFrame* pContentFrame;
bool bGoOn = true;
// iterate over all paragraphs
while( bGoOn )
{
SwNode* pNd = GetDoc()->GetNodes()[ nCurrNd ];
switch( pNd->GetNodeType() )
{
case SwNodeType::Text:
pContentFrame = static_cast<SwTextNode*>(pNd)->getLayoutFrame( GetLayout() );
if( nullptr != pContentFrame )
{
// skip hidden frames - ignore protection!
if( !pContentFrame->IsHiddenNow() )
{
// if the node is numbered and the starting value of the numbering equals the
// start value of the numbering rule then set this value as hard starting value
// get the node num
// OD 2005-11-09
SwTextNode* pTextNd( pNd->GetTextNode() );
SwNumRule* pNumRule( pTextNd->GetNumRule() );
// sw_redlinehide: not sure what this should do, only called from mail-merge
bool bIsNodeNum =
( pNumRule && pTextNd->GetNum() &&
( pTextNd->HasNumber() || pTextNd->HasBullet() ) &&
pTextNd->IsCountedInList() &&
!pTextNd->IsListRestart() );
if (bIsNodeNum)
{
int nListLevel = pTextNd->GetActualListLevel();
if (nListLevel < 0)
nListLevel = 0;
if (nListLevel >= MAXLEVEL)
nListLevel = MAXLEVEL - 1;
bIsNodeNum = pTextNd->GetNum()->GetNumber() ==
pNumRule->Get( o3tl::narrowing<sal_uInt16>(nListLevel) ).GetStart();
}
if (bIsNodeNum)
{
// now set the start value as attribute
SwPosition aCurrentNode(*pNd);
GetDoc()->SetNumRuleStart( aCurrentNode );
}
}
}
break;
case SwNodeType::Section:
// skip hidden sections - ignore protection!
if(static_cast<SwSectionNode*>(pNd)->GetSection().IsHidden() )
nCurrNd = pNd->EndOfSectionIndex();
break;
default: break;
}
bGoOn = nCurrNd < nEndNd;
++nCurrNd;
}
}
}
Pop(PopMode::DeleteCurrent);
EndAllAction();
}
sal_Int32 SwEditShell::GetLineCount()
{
sal_Int32 nRet = 0;
CalcLayout();
SwPaM* pPam = GetCursor();
SwNodeIndex aStart( pPam->GetPoint()->GetNode() );
SwContentNode* pCNd;
SwContentFrame *pContentFrame = nullptr;
aStart = SwNodeOffset(0);
while (nullptr != (pCNd = SwNodes::GoNextSection(
&aStart, true, false )) )
{
if( nullptr != ( pContentFrame = pCNd->getLayoutFrame( GetLayout() ) ) && pContentFrame->IsTextFrame() )
{
SwTextFrame *const pFrame(static_cast<SwTextFrame*>(pContentFrame));
nRet = nRet + pFrame->GetLineCount(TextFrameIndex(COMPLETE_STRING));
if (GetLayout()->HasMergedParas())
{
if (auto const*const pMerged = pFrame->GetMergedPara())
{
aStart = *pMerged->pLastNode;
}
}
}
}
return nRet;
}
tools::Long SwEditShell::CompareDoc( const SwDoc& rDoc )
{
StartAllAction();
tools::Long nRet = GetDoc()->CompareDoc( rDoc );
EndAllAction();
return nRet;
}
tools::Long SwEditShell::MergeDoc( const SwDoc& rDoc )
{
StartAllAction();
tools::Long nRet = GetDoc()->MergeDoc( rDoc );
EndAllAction();
return nRet;
}
const SwFootnoteInfo& SwEditShell::GetFootnoteInfo() const
{
return GetDoc()->GetFootnoteInfo();
}
void SwEditShell::SetFootnoteInfo(const SwFootnoteInfo& rInfo)
{
StartAllAction();
CurrShell aCurr( this );
GetDoc()->SetFootnoteInfo(rInfo);
CallChgLnk();
EndAllAction();
}
const SwEndNoteInfo& SwEditShell::GetEndNoteInfo() const
{
return GetDoc()->GetEndNoteInfo();
}
void SwEditShell::SetEndNoteInfo(const SwEndNoteInfo& rInfo)
{
StartAllAction();
CurrShell aCurr( this );
GetDoc()->SetEndNoteInfo(rInfo);
EndAllAction();
}
const SwLineNumberInfo& SwEditShell::GetLineNumberInfo() const
{
return GetDoc()->GetLineNumberInfo();
}
void SwEditShell::SetLineNumberInfo(const SwLineNumberInfo& rInfo)
{
StartAllAction();
CurrShell aCurr( this );
GetDoc()->SetLineNumberInfo(rInfo);
AddPaintRect( GetLayout()->getFrameArea() );
EndAllAction();
}
sal_uInt16 SwEditShell::GetLinkUpdMode() const
{
return getIDocumentSettingAccess().getLinkUpdateMode( false );
}
void SwEditShell::SetLinkUpdMode( sal_uInt16 nMode )
{
getIDocumentSettingAccess().setLinkUpdateMode( nMode );
}
// Interface for TextInputData - (for text input of japanese/chinese characters)
void SwEditShell::CreateExtTextInput(LanguageType eInputLanguage)
{
SwExtTextInput* pRet = GetDoc()->CreateExtTextInput( *GetCursor() );
pRet->SetLanguage(eInputLanguage);
pRet->SetOverwriteCursor( SwCursorShell::IsOverwriteCursor() );
}
OUString SwEditShell::DeleteExtTextInput( bool bInsText )
{
const SwPosition& rPos = *GetCursor()->GetPoint();
SwExtTextInput* pDel = GetDoc()->GetExtTextInput( rPos.GetNode(),
rPos.GetContentIndex() );
if( !pDel )
{
//JP 25.10.2001: under UNIX the cursor is moved before the Input-
// Engine event comes in. So take any - normally there
// exist only one at the time. -- Task 92016
pDel = GetDoc()->GetExtTextInput();
}
OUString sRet;
if( pDel )
{
OUString sTmp;
SwUnoCursorHelper::GetTextFromPam(*pDel, sTmp);
sRet = sTmp;
CurrShell aCurr( this );
StartAllAction();
pDel->SetInsText( bInsText );
SetOverwriteCursor( pDel->IsOverwriteCursor() );
const SwPosition aPos( *pDel->GetPoint() );
GetDoc()->DeleteExtTextInput( pDel );
// In this case, the "replace" function did not set the cursor
// to the original position. Therefore we have to do this manually.
if ( ! bInsText && IsOverwriteCursor() )
*GetCursor()->GetPoint() = aPos;
EndAllAction();
}
return sRet;
}
void SwEditShell::SetExtTextInputData( const CommandExtTextInputData& rData )
{
SwPaM* pCurrentCursor = GetCursor();
const SwPosition& rPos = *pCurrentCursor->GetPoint();
SwExtTextInput* pInput = GetDoc()->GetExtTextInput( rPos.GetNode() );
if( !pInput )
return;
StartAllAction();
CurrShell aCurr( this );
if( !rData.IsOnlyCursorChanged() )
pInput->SetInputData( rData );
// position cursor
const SwPosition& rStt = *pInput->Start();
const sal_Int32 nNewCursorPos = rStt.GetContentIndex() + rData.GetCursorPos();
// ugly but works
ShowCursor();
const sal_Int32 nDiff = nNewCursorPos - rPos.GetContentIndex();
if( nDiff != 0)
{
bool bLeft = nDiff < 0;
sal_Int32 nMaxGuard = std::abs(nDiff);
while (true)
{
auto nOldPos = pCurrentCursor->GetPoint()->GetContentIndex();
if (bLeft)
Left(1, SwCursorSkipMode::Chars);
else
Right(1, SwCursorSkipMode::Chars);
auto nNewPos = pCurrentCursor->GetPoint()->GetContentIndex();
// expected success
if (nNewPos == nNewCursorPos)
break;
if (nNewPos == nOldPos)
{
// if there was no movement, we have failed for some reason
SAL_WARN("sw.core", "IM cursor move failed");
break;
}
if (--nMaxGuard == 0)
{
// if it takes more cursor moves than there are utf-16 chars to move past
// something has probably gone wrong
SAL_WARN("sw.core", "IM abandoning cursor positioning");
break;
}
}
}
SetOverwriteCursor( rData.IsCursorOverwrite() );
EndAllAction();
if( !rData.IsCursorVisible() ) // must be called after the EndAction
HideCursor();
}
void SwEditShell::TransliterateText( TransliterationFlags nType )
{
utl::TransliterationWrapper aTrans( ::comphelper::getProcessComponentContext(), nType );
StartAllAction();
CurrShell aCurr( this );
SwPaM* pCursor = GetCursor();
if( pCursor->GetNext() != pCursor )
{
GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
for(const SwPaM& rPaM : GetCursor()->GetRingContainer())
{
if( rPaM.HasMark() )
GetDoc()->getIDocumentContentOperations().TransliterateText( rPaM, aTrans );
}
GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
}
else
GetDoc()->getIDocumentContentOperations().TransliterateText( *pCursor, aTrans );
EndAllAction();
}
void SwEditShell::CountWords( SwDocStat& rStat ) const
{
for(const SwPaM& rPaM : GetCursor()->GetRingContainer())
{
if( rPaM.HasMark() )
SwDoc::CountWords( rPaM, rStat );
}
}
void SwEditShell::ApplyViewOptions( const SwViewOption &rOpt )
{
SwCursorShell::StartAction();
SwViewShell::ApplyViewOptions( rOpt );
SwEditShell::EndAction();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V530 The return value of function 'Assign' is required to be utilized.
↑ V530 The return value of function 'append' is required to be utilized.
↑ V728 An excessive check can be simplified. The '||' operator is surrounded by opposite expressions '!GetCursor()->HasMark()' and 'GetCursor()->HasMark()'.