summaryrefslogtreecommitdiffstats
path: root/sw/source/uibase/wrtsh
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/uibase/wrtsh')
-rw-r--r--sw/source/uibase/wrtsh/delete.cxx665
-rw-r--r--sw/source/uibase/wrtsh/move.cxx773
-rw-r--r--sw/source/uibase/wrtsh/navmgr.cxx221
-rw-r--r--sw/source/uibase/wrtsh/select.cxx1057
-rw-r--r--sw/source/uibase/wrtsh/wrtsh1.cxx2731
-rw-r--r--sw/source/uibase/wrtsh/wrtsh2.cxx686
-rw-r--r--sw/source/uibase/wrtsh/wrtsh3.cxx392
-rw-r--r--sw/source/uibase/wrtsh/wrtsh4.cxx253
-rw-r--r--sw/source/uibase/wrtsh/wrtundo.cxx151
9 files changed, 6929 insertions, 0 deletions
diff --git a/sw/source/uibase/wrtsh/delete.cxx b/sw/source/uibase/wrtsh/delete.cxx
new file mode 100644
index 0000000000..e7a09d0165
--- /dev/null
+++ b/sw/source/uibase/wrtsh/delete.cxx
@@ -0,0 +1,665 @@
+/* -*- 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 <wrtsh.hxx>
+#include <swcrsr.hxx>
+#include <editeng/lrspitem.hxx>
+#include <view.hxx>
+#include <drawbase.hxx>
+#include <unobaseclass.hxx>
+#include <fmtanchr.hxx>
+#include <flyfrm.hxx>
+#include <ndtxt.hxx>
+#include <txtfld.hxx>
+#include <docufld.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <i18nutil/unicode.hxx>
+#include <o3tl/temporary.hxx>
+#include <rtl/character.hxx>
+#include <osl/diagnose.h>
+#include <doc.hxx>
+#include <IDocumentRedlineAccess.hxx>
+
+inline void SwWrtShell::OpenMark()
+{
+ StartAllAction();
+ ResetCursorStack();
+ KillPams();
+ SetMark();
+}
+
+inline void SwWrtShell::CloseMark( bool bOkFlag )
+{
+ if( bOkFlag )
+ UpdateAttr();
+ else
+ SwapPam();
+
+ ClearMark();
+ EndAllAction();
+}
+
+
+
+// #i23725#
+bool SwWrtShell::TryRemoveIndent()
+{
+ bool bResult = false;
+
+ SfxItemSetFixed<RES_MARGIN_FIRSTLINE, RES_MARGIN_FIRSTLINE> aAttrSet(GetAttrPool());
+ GetCurAttr(aAttrSet);
+
+ SvxFirstLineIndentItem firstLine(aAttrSet.Get(RES_MARGIN_FIRSTLINE));
+ SvxTextLeftMarginItem leftMargin(aAttrSet.Get(RES_MARGIN_TEXTLEFT));
+ short aOldFirstLineOfst = firstLine.GetTextFirstLineOffset();
+
+ if (aOldFirstLineOfst > 0)
+ {
+ firstLine.SetTextFirstLineOffset(0);
+ bResult = true;
+ }
+ else if (aOldFirstLineOfst < 0)
+ {
+ // this used to call SetLeft() but this should be the same result
+ firstLine.SetTextFirstLineOffset(0);
+ leftMargin.SetTextLeft(leftMargin.GetTextLeft() + aOldFirstLineOfst);
+ bResult = true;
+ }
+ else if (leftMargin.GetTextLeft() != 0)
+ {
+ leftMargin.SetTextLeft(0);
+ bResult = true;
+ }
+
+ if (bResult)
+ {
+ aAttrSet.Put(firstLine);
+ aAttrSet.Put(leftMargin);
+ SetAttrSet(aAttrSet);
+ }
+
+ return bResult;
+}
+
+/** Description: Erase the line. */
+
+void SwWrtShell::DelLine()
+{
+ SwActContext aActContext(this);
+ ResetCursorStack();
+ // remember the old cursor
+ Push();
+ ClearMark();
+ SwCursorShell::LeftMargin();
+ SetMark();
+ SwCursorShell::RightMargin();
+
+ bool bRet = Delete(false);
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ if( bRet )
+ UpdateAttr();
+}
+
+void SwWrtShell::DelToStartOfLine()
+{
+ OpenMark();
+ SwCursorShell::LeftMargin();
+ bool bRet = Delete(false);
+ CloseMark( bRet );
+}
+
+void SwWrtShell::DelToEndOfLine()
+{
+ OpenMark();
+ SwCursorShell::RightMargin();
+ bool bRet = Delete(false);
+ CloseMark( bRet );
+}
+
+bool SwWrtShell::DelLeft()
+{
+ // If it's a Fly, throw it away
+ SelectionType nSelType = GetSelectionType();
+ const SelectionType nCmp = SelectionType::Frame | SelectionType::Graphic | SelectionType::Ole | SelectionType::DrawObject;
+ if( nCmp & nSelType )
+ {
+ // #108205# Remember object's position.
+ Point aTmpPt = GetObjRect().TopLeft();
+
+ DelSelectedObj();
+
+ // #108205# Set cursor to remembered position.
+ SetCursor(&aTmpPt);
+
+ LeaveSelFrameMode();
+ UnSelectFrame();
+
+ nSelType = GetSelectionType();
+ if ( nCmp & nSelType )
+ {
+ EnterSelFrameMode();
+ GotoNextFly();
+ }
+
+ return true;
+ }
+
+ // If a selection exists, erase this
+ if ( IsSelection() )
+ {
+ if( !IsBlockMode() || HasSelection() )
+ {
+ //OS: Once again Basic: SwActContext must be leaved
+ //before EnterStdMode!
+ {
+ SwActContext aActContext(this);
+ ResetCursorStack();
+ Delete(false);
+ UpdateAttr();
+ }
+ if( IsBlockMode() )
+ {
+ NormalizePam();
+ ClearMark();
+ EnterBlockMode();
+ }
+ else
+ EnterStdMode();
+ return true;
+ }
+ else
+ EnterStdMode();
+ }
+
+ // JP 29.06.95: never erase a table standing in front of it.
+ bool bSwap = false;
+ const SwTableNode * pWasInTableNd = SwCursorShell::IsCursorInTable();
+
+ if( SwCursorShell::IsSttPara())
+ {
+ // Start/EndAllAction to avoid cursor flickering
+ UnoActionContext c(GetDoc());
+ SwCursorShell::Push();
+
+ // #i4032# Don't actually call a 'delete' if we
+ // changed the table cell, compare DelRight().
+ const SwStartNode * pSNdOld = pWasInTableNd ?
+ GetCursor()->GetPointNode().FindTableBoxStartNode() :
+ nullptr;
+
+ // If the cursor is at the beginning of a paragraph, try to step
+ // backwards. On failure we are done.
+ bool bDoSomething = SwCursorShell::Left(1,SwCursorSkipMode::Chars);
+
+ if (bDoSomething)
+ {
+ // If the cursor entered or left a table (or both) we are done.
+ const SwTableNode* pIsInTableNd = SwCursorShell::IsCursorInTable();
+ bDoSomething = pIsInTableNd == pWasInTableNd;
+
+ if (bDoSomething)
+ {
+ const SwStartNode* pSNdNew = pIsInTableNd ?
+ GetCursor()->GetPointNode().FindTableBoxStartNode() :
+ nullptr;
+
+ // #i4032# Don't actually call a 'delete' if we
+ // changed the table cell, compare DelRight().
+ bDoSomething = pSNdOld == pSNdNew;
+ }
+ }
+
+ if (!bDoSomething)
+ {
+ // tdf#115132 Restore previous position and we are done
+ SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
+ return false;
+ }
+
+ SwCursorShell::Pop(SwCursorShell::PopMode::DeleteStack);
+
+ OpenMark();
+ SwCursorShell::Right(1,SwCursorSkipMode::Chars);
+ SwCursorShell::SwapPam();
+ bSwap = true;
+ }
+ else
+ {
+ // If we are just to the right to a fieldmark, then remove it completely
+ const SwPosition* pCurPos = GetCursor()->GetPoint();
+ SwPosition aPrevChar(*pCurPos->GetContentNode(), pCurPos->GetContentIndex() - 1);
+ sw::mark::IFieldmark* pFm = getIDocumentMarkAccess()->getFieldmarkAt(aPrevChar);
+ if (pFm && pFm->GetMarkEnd() == *pCurPos)
+ {
+ mxDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
+ IDocumentMarkAccess::DeleteFieldmarkCommand(*pFm);
+ getIDocumentMarkAccess()->deleteMark(pFm);
+ mxDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
+ return true;
+ }
+
+ OpenMark();
+ SwCursorShell::Left(1, SwCursorSkipMode::Chars);
+
+ // If we are deleting a variation selector, we want to delete the
+ // whole sequence.
+ sal_uInt32 nCode = GetChar(false);
+ if ( rtl::isSurrogate( nCode ) )
+ {
+ OUString sStr = GetSelText();
+ nCode = sStr.iterateCodePoints( &o3tl::temporary(sal_Int32(0)) );
+ }
+
+ if ( unicode::isVariationSelector( nCode ) )
+ {
+ SwCursorShell::Push();
+ SwCursorShell::Left(1, SwCursorSkipMode::Chars);
+ SwCursorShell::Pop( SwCursorShell::PopMode::DeleteStack );
+ }
+ }
+ bool bRet = Delete(true);
+ if( !bRet && bSwap )
+ SwCursorShell::SwapPam();
+ CloseMark( bRet );
+
+ return bRet;
+}
+
+bool SwWrtShell::DelRight(bool const isReplaceHeuristic)
+{
+ // Will be or'ed, if a tableselection exists;
+ // will here be implemented on SelectionType::Table
+ bool bRet = false;
+ SelectionType nSelection = GetSelectionType();
+ if(nSelection & SelectionType::TableCell)
+ nSelection = SelectionType::Table;
+ if(nSelection & SelectionType::Text)
+ nSelection = SelectionType::Text;
+
+ switch( nSelection & ~SelectionType::Ornament & ~SelectionType::Media )
+ {
+ case SelectionType::PostIt:
+ case SelectionType::Text:
+ case SelectionType::Table:
+ case SelectionType::NumberList:
+ // If a selection exists, erase it.
+ if( IsSelection() )
+ {
+ if( !IsBlockMode() || HasSelection() )
+ {
+ //OS: And once again Basic: SwActContext must be
+ //leaved before EnterStdMode !
+ {
+ SwActContext aActContext(this);
+ ResetCursorStack();
+ Delete(isReplaceHeuristic);
+ UpdateAttr();
+ }
+ if( IsBlockMode() )
+ {
+ NormalizePam();
+ ClearMark();
+ EnterBlockMode();
+ }
+ else
+ EnterStdMode();
+ bRet = true;
+ break;
+ }
+ else
+ EnterStdMode();
+ }
+
+ if (SwCursorShell::IsEndPara())
+ {
+ // Start/EndAllAction to avoid cursor flickering
+ UnoActionContext c(GetDoc());
+
+ const SwTableNode* pWasInTableNd = IsCursorInTable();
+ // #108049# Save the startnode of the current cell
+ const SwStartNode* pSNdOld = pWasInTableNd ?
+ GetCursor()->GetPointNode().FindTableBoxStartNode() : nullptr;
+ bool bCheckDelFull = SelectionType::Text & nSelection && SwCursorShell::IsSttPara();
+ bool bDelFull = false;
+ bool bDoNothing = false;
+
+ // #i41424# Introduced a couple of
+ // Push()-Pop() pairs here. The reason for this is that a
+ // Right()-Left() combination does not make sure, that
+ // the cursor will be in its initial state, because there
+ // may be a numbering in front of the next paragraph.
+ SwCursorShell::Push();
+
+ if (SwCursorShell::Right(1, SwCursorSkipMode::Chars))
+ {
+ const SwTableNode* pCurrTableNd = IsCursorInTable();
+ bDelFull = bCheckDelFull && pCurrTableNd && pCurrTableNd != pWasInTableNd;
+ if (!bDelFull && (IsCursorInTable() || (pCurrTableNd != pWasInTableNd)))
+ {
+ // #108049# Save the startnode of the current cell.
+ // May be different to pSNdOld as we have moved.
+ const SwStartNode* pSNdNew = pCurrTableNd ?
+ GetCursor()->GetPointNode().FindTableBoxStartNode() : nullptr;
+
+ // tdf#115132 Only keep cursor position instead of deleting
+ // if we have moved to a different cell
+ bDoNothing = pSNdOld != pSNdNew;
+ }
+ }
+
+ // restore cursor
+ SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
+
+ if (bDelFull)
+ {
+ DelFullPara();
+ UpdateAttr();
+ }
+ if (bDelFull || bDoNothing)
+ break;
+ }
+
+ {
+ // If we are just ahead of a fieldmark, then remove it completely
+ sw::mark::IFieldmark *const pFm = getIDocumentMarkAccess()->getFieldmarkAt(*GetCursor()->GetPoint());
+ if (pFm && pFm->GetMarkStart() == *GetCursor()->GetPoint())
+ {
+ mxDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
+ IDocumentMarkAccess::DeleteFieldmarkCommand(*pFm);
+ getIDocumentMarkAccess()->deleteMark(pFm);
+ mxDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
+ bRet = true;
+ break;
+ }
+ }
+
+ OpenMark();
+ SwCursorShell::Right(1, SwCursorSkipMode::Cells);
+ bRet = Delete(true);
+ CloseMark( bRet );
+ break;
+
+ case SelectionType::Frame:
+ case SelectionType::Graphic:
+ case SelectionType::Ole:
+ case SelectionType::DrawObject:
+ case SelectionType::DrawObjectEditMode:
+ case SelectionType::DbForm:
+ {
+ // Group deletion of the object and its comment together
+ // (also as-character anchor conversion at track changes)
+ mxDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
+
+ // #108205# Remember object's position.
+ Point aTmpPt = GetObjRect().TopLeft();
+
+ // Remember the anchor of the selected object before deletion.
+ std::optional<SwPosition> oAnchor;
+ RndStdIds eAnchorId = RndStdIds::FLY_AT_PARA;
+ SwFlyFrame* pFly = GetSelectedFlyFrame();
+ SwFrameFormat* pFormat = nullptr;
+ if (pFly)
+ {
+ pFormat = pFly->GetFormat();
+ if (pFormat)
+ {
+ eAnchorId = pFormat->GetAnchor().GetAnchorId();
+ // to-character anchor conversion at track changes
+ if ( IsRedlineOn() && (eAnchorId != RndStdIds::FLY_AS_CHAR &&
+ eAnchorId != RndStdIds::FLY_AT_CHAR) )
+ {
+ SfxItemSetFixed<RES_ANCHOR, RES_ANCHOR> aSet(GetAttrPool());
+ GetFlyFrameAttr(aSet);
+ SwFormatAnchor aAnch(RndStdIds::FLY_AT_CHAR);
+ aSet.Put(aAnch);
+ SetFlyFrameAttr(aSet);
+ eAnchorId = pFormat->GetAnchor().GetAnchorId();
+ }
+ if ((eAnchorId == RndStdIds::FLY_AS_CHAR || eAnchorId == RndStdIds::FLY_AT_CHAR)
+ && pFormat->GetAnchor().GetAnchorNode())
+ {
+ oAnchor.emplace(*pFormat->GetAnchor().GetContentAnchor());
+ // set cursor before the anchor point
+ if ( IsRedlineOn() )
+ *GetCurrentShellCursor().GetPoint() = *oAnchor;
+ }
+ }
+ }
+
+ // track changes: create redline at anchor point of the image to record the deletion
+ if ( IsRedlineOn() && oAnchor && SelectionType::Graphic & nSelection && pFormat &&
+ ( eAnchorId == RndStdIds::FLY_AT_CHAR || eAnchorId == RndStdIds::FLY_AS_CHAR ) )
+ {
+ sal_Int32 nRedlineLength = 1;
+ // create a double CH_TXT_TRACKED_DUMMY_CHAR anchor point of the image to record the
+ // deletion, if needed (otherwise use the existing anchor point of the image anchored
+ // *as* character)
+ if ( eAnchorId == RndStdIds::FLY_AT_CHAR )
+ {
+ nRedlineLength = 2;
+ LeaveSelFrameMode();
+ UnSelectFrame();
+ RedlineFlags eOld = GetRedlineFlags();
+ SetRedlineFlags( eOld | RedlineFlags::Ignore );
+ Insert( OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) +
+ OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
+ SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
+ SwCursorShell::Left(1, SwCursorSkipMode::Chars);
+ anchor.SetAnchor(GetCursor()->GetPoint());
+ GetDoc()->SetAttr(anchor, *pFormat);
+ SetRedlineFlags( eOld );
+ SwCursorShell::Left(1, SwCursorSkipMode::Chars);
+ }
+ OpenMark();
+ SwCursorShell::Right(nRedlineLength, SwCursorSkipMode::Chars);
+ bRet = Delete(false);
+ CloseMark( bRet );
+ }
+ else
+ DelSelectedObj();
+
+ if (oAnchor)
+ {
+ SwTextNode* pTextNode = oAnchor->GetNode().GetTextNode();
+ if (pTextNode)
+ {
+ const SwTextField* pField(
+ pTextNode->GetFieldTextAttrAt(oAnchor->GetContentIndex(), ::sw::GetTextAttrMode::Default));
+ if (pField
+ && dynamic_cast<const SwPostItField*>(pField->GetFormatField().GetField()))
+ {
+ // Remove the comment of the deleted object.
+ *GetCurrentShellCursor().GetPoint() = *oAnchor;
+ DelRight();
+ }
+ }
+ }
+
+ mxDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
+
+ // #108205# Set cursor to remembered position.
+ SetCursor(&aTmpPt);
+
+ LeaveSelFrameMode();
+ UnSelectFrame();
+ OSL_ENSURE( !IsFrameSelected(),
+ "<SwWrtShell::DelRight(..)> - <SwWrtShell::UnSelectFrame()> should unmark all objects" );
+ // leave draw mode, if necessary.
+ {
+ if (GetView().GetDrawFuncPtr())
+ {
+ GetView().GetDrawFuncPtr()->Deactivate();
+ GetView().SetDrawFuncPtr(nullptr);
+ }
+ if ( GetView().IsDrawMode() )
+ {
+ GetView().LeaveDrawCreate();
+ }
+ }
+ }
+
+ // <IsFrameSelected()> can't be true - see above.
+ {
+ nSelection = GetSelectionType();
+ if ( SelectionType::Frame & nSelection ||
+ SelectionType::Graphic & nSelection ||
+ SelectionType::Ole & nSelection ||
+ SelectionType::DrawObject & nSelection )
+ {
+ EnterSelFrameMode();
+ GotoNextFly();
+ }
+ }
+ bRet = true;
+ break;
+ default: break;
+ }
+ return bRet;
+}
+
+void SwWrtShell::DelToEndOfPara()
+{
+ SwActContext aActContext(this);
+ ResetCursorStack();
+ Push();
+ SetMark();
+ if( !MovePara(GoCurrPara,fnParaEnd))
+ {
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ return;
+ }
+ bool bRet = Delete(false);
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ if( bRet )
+ UpdateAttr();
+}
+
+void SwWrtShell::DelToStartOfPara()
+{
+ SwActContext aActContext(this);
+ ResetCursorStack();
+ Push();
+ SetMark();
+ if( !MovePara(GoCurrPara,fnParaStart))
+ {
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ return;
+ }
+ bool bRet = Delete(false);
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ if( bRet )
+ UpdateAttr();
+}
+
+// All erase operations should work with Find instead with
+// Nxt-/PrvDelim, because the latter works with Wrap Around
+// -- that's probably not wished.
+
+void SwWrtShell::DelToStartOfSentence()
+{
+ if(IsStartOfDoc())
+ return;
+ OpenMark();
+ bool bRet = BwdSentence_() && Delete(false);
+ CloseMark( bRet );
+}
+
+bool SwWrtShell::DelToEndOfSentence()
+{
+ if(IsEndOfDoc())
+ return false;
+ OpenMark();
+ bool bRet(false);
+ // fdo#60967: special case that is documented in help: delete
+ // paragraph following table if cursor is at end of last cell in table
+ if (IsEndOfTable())
+ {
+ Push();
+ ClearMark();
+ if (SwCursorShell::Right(1,SwCursorSkipMode::Chars))
+ {
+ SetMark();
+ if (!IsEndPara()) // can only be at the end if it's empty
+ { // for an empty paragraph this would actually select the _next_
+ SwCursorShell::MovePara(GoCurrPara, fnParaEnd);
+ }
+ if (!IsEndOfDoc()) // do not delete last paragraph in body text
+ {
+ bRet = DelFullPara();
+ }
+ }
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ }
+ else
+ {
+ bRet = FwdSentence_() && Delete(false);
+ }
+ CloseMark( bRet );
+ return bRet;
+}
+
+void SwWrtShell::DelNxtWord()
+{
+ if(IsEndOfDoc())
+ return;
+ SwActContext aActContext(this);
+ ResetCursorStack();
+ EnterStdMode();
+ SetMark();
+ if(IsEndWrd() && !IsStartWord())
+ NxtWrdForDelete(); // #i92468#
+ if(IsStartWord() || IsEndPara())
+ NxtWrdForDelete(); // #i92468#
+ else
+ EndWrd();
+
+ bool bRet = Delete(false);
+ if( bRet )
+ UpdateAttr();
+ else
+ SwapPam();
+ ClearMark();
+}
+
+void SwWrtShell::DelPrvWord()
+{
+ if(IsStartOfDoc())
+ return;
+ SwActContext aActContext(this);
+ ResetCursorStack();
+ EnterStdMode();
+ SetMark();
+ if ( !IsStartWord() ||
+ !PrvWrdForDelete() ) // #i92468#
+ {
+ if (IsEndWrd() || IsSttPara())
+ PrvWrdForDelete(); // #i92468#
+ else
+ SttWrd();
+ }
+ bool bRet = Delete(false);
+ if( bRet )
+ UpdateAttr();
+ else
+ SwapPam();
+ ClearMark();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/wrtsh/move.cxx b/sw/source/uibase/wrtsh/move.cxx
new file mode 100644
index 0000000000..cda2b32112
--- /dev/null
+++ b/sw/source/uibase/wrtsh/move.cxx
@@ -0,0 +1,773 @@
+/* -*- 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 <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <viewopt.hxx>
+#include <drawbase.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <drawdoc.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdview.hxx>
+
+/**
+ Always:
+ - Reset of the cursor stack
+ - retrigger timer
+ - if applicable: GCAttr
+
+ on selection
+ - SttSelect()
+
+ else
+ - EndSelect()
+ */
+
+const tools::Long nReadOnlyScrollOfst = 10;
+
+namespace {
+
+class ShellMoveCursor
+{
+ SwWrtShell* pSh;
+ bool bAct;
+public:
+ ShellMoveCursor( SwWrtShell* pWrtSh, bool bSel )
+ {
+ bAct = !pWrtSh->ActionPend() && (pWrtSh->GetFrameType(nullptr,false) & FrameTypeFlags::FLY_ANY);
+ pSh = pWrtSh;
+ pSh->MoveCursor( bSel );
+ pWrtSh->GetView().GetViewFrame().GetBindings().Invalidate(SID_HYPERLINK_GETLINK);
+ }
+ ~ShellMoveCursor() COVERITY_NOEXCEPT_FALSE
+ {
+ if( bAct )
+ {
+ // The action is used for scrolling in "single paragraph"
+ // frames with fixed height.
+ pSh->StartAllAction();
+ pSh->EndAllAction();
+ }
+ }
+};
+
+}
+
+void SwWrtShell::MoveCursor( bool bWithSelect )
+{
+ ResetCursorStack();
+ if ( IsGCAttr() )
+ {
+ GCAttr();
+ ClearGCAttr();
+ }
+ if ( bWithSelect )
+ SttSelect();
+ else
+ {
+ EndSelect();
+ (this->*m_fnKillSel)( nullptr, false );
+ }
+}
+
+bool SwWrtShell::SimpleMove( FNSimpleMove FnSimpleMove, bool bSelect )
+{
+ bool bRet;
+ if( bSelect )
+ {
+ SttCursorMove();
+ MoveCursor( true );
+ bRet = (this->*FnSimpleMove)();
+ EndCursorMove();
+ }
+ else
+ {
+ bRet = (this->*FnSimpleMove)();
+ if( bRet )
+ MoveCursor();
+ }
+ return bRet;
+}
+
+bool SwWrtShell::Left( SwCursorSkipMode nMode, bool bSelect,
+ sal_uInt16 nCount, bool bBasicCall, bool bVisual )
+{
+ if ( !bSelect && !bBasicCall && IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly())
+ {
+ Point aTmp( VisArea().Pos() );
+ aTmp.AdjustX( -(VisArea().Width() * nReadOnlyScrollOfst / 100) );
+ m_rView.SetVisArea( aTmp );
+ return true;
+ }
+ else
+ {
+ ShellMoveCursor aTmp( this, bSelect );
+ return SwCursorShell::Left( nCount, nMode, bVisual );
+ }
+}
+
+bool SwWrtShell::Right( SwCursorSkipMode nMode, bool bSelect,
+ sal_uInt16 nCount, bool bBasicCall, bool bVisual )
+{
+ if ( !bSelect && !bBasicCall && IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly() )
+ {
+ Point aTmp( VisArea().Pos() );
+ aTmp.AdjustX(VisArea().Width() * nReadOnlyScrollOfst / 100 );
+ aTmp.setX( m_rView.SetHScrollMax( aTmp.X() ) );
+ m_rView.SetVisArea( aTmp );
+ return true;
+ }
+ else
+ {
+ ShellMoveCursor aTmp( this, bSelect );
+ return SwCursorShell::Right( nCount, nMode, bVisual );
+ }
+}
+
+bool SwWrtShell::Up( bool bSelect, sal_uInt16 nCount, bool bBasicCall )
+{
+ if ( !bSelect && !bBasicCall && IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly())
+ {
+ Point aTmp( VisArea().Pos() );
+ aTmp.AdjustY( -(VisArea().Height() * nReadOnlyScrollOfst / 100) );
+ m_rView.SetVisArea( aTmp );
+ return true;
+ }
+
+ ShellMoveCursor aTmp( this, bSelect );
+ return SwCursorShell::Up(nCount);
+}
+
+bool SwWrtShell::Down( bool bSelect, sal_uInt16 nCount, bool bBasicCall )
+{
+ if ( !bSelect && !bBasicCall && IsCursorReadonly() && !GetViewOptions()->IsSelectionInReadonly())
+ {
+ Point aTmp( VisArea().Pos() );
+ aTmp.AdjustY(VisArea().Height() * nReadOnlyScrollOfst / 100 );
+ aTmp.setY( m_rView.SetVScrollMax( aTmp.Y() ) );
+ m_rView.SetVisArea( aTmp );
+ return true;
+ }
+
+ ShellMoveCursor aTmp( this, bSelect );
+ return SwCursorShell::Down(nCount);
+}
+
+bool SwWrtShell::LeftMargin( bool bSelect, bool bBasicCall )
+{
+ if ( !bSelect && !bBasicCall && IsCursorReadonly() )
+ {
+ Point aTmp( VisArea().Pos() );
+ aTmp.setX( DOCUMENTBORDER );
+ m_rView.SetVisArea( aTmp );
+ return true;
+ }
+ else
+ {
+ ShellMoveCursor aTmp( this, bSelect );
+ return SwCursorShell::LeftMargin();
+ }
+}
+
+bool SwWrtShell::RightMargin( bool bSelect, bool bBasicCall )
+{
+ if ( !bSelect && !bBasicCall && IsCursorReadonly() )
+ {
+ Point aTmp( VisArea().Pos() );
+ aTmp.setX( GetDocSize().Width() - VisArea().Width() + DOCUMENTBORDER );
+ if( DOCUMENTBORDER > aTmp.X() )
+ aTmp.setX( DOCUMENTBORDER );
+ m_rView.SetVisArea( aTmp );
+ return true;
+ }
+ else
+ {
+ ShellMoveCursor aTmp( this, bSelect );
+ return SwCursorShell::RightMargin(bBasicCall);
+ }
+}
+
+bool SwWrtShell::GoStart( bool bKeepArea, bool *pMoveTable,
+ bool bSelect, bool bDontMoveRegion )
+{
+ if ( IsCursorInTable() )
+ {
+ const bool bBoxSelection = HasBoxSelection();
+ if( !m_bBlockMode )
+ {
+ if ( !bSelect )
+ EnterStdMode();
+ else
+ SttSelect();
+ }
+ // Table cell ?
+ if ( !bBoxSelection && (MoveSection( GoCurrSection, fnSectionStart)
+ || bDontMoveRegion))
+ {
+ if ( pMoveTable )
+ *pMoveTable = false;
+ return true;
+ }
+ SwTableNode const*const pTable(getShellCursor(false)->GetPoint()->GetNode().FindTableNode());
+ assert(pTable);
+ if( MoveTable( GotoCurrTable, fnTableStart ) || bDontMoveRegion )
+ {
+ if ( pMoveTable )
+ *pMoveTable = true;
+ return true;
+ }
+ else if (SwCursor const*const pCursor = getShellCursor(false);
+ pTable->GetNodes()[pTable->GetIndex()+1]->EndOfSectionIndex()
+ < pCursor->GetPoint()->GetNode().GetIndex()
+ && pMoveTable != nullptr // only set by SelAll()
+ // problem: cursor isn't inside 1st cell, and didn't move there
+ // workaround: try to move cursor outside of table for SelAll()
+ && MoveOutOfTable())
+ {
+ assert(!*pMoveTable);
+ return true;
+ }
+ else if( bBoxSelection && pMoveTable )
+ {
+ // JP 09.01.96: We have a box selection (or an empty cell)
+ // and we want select (pMoveTable will be
+ // set in SelAll). Then the table must not
+ // be left, otherwise there is no selection
+ // of the entire table possible!
+ *pMoveTable = true;
+ return true;
+ }
+ }
+
+ if( !m_bBlockMode )
+ {
+ if ( !bSelect )
+ EnterStdMode();
+ else
+ SttSelect();
+ }
+ const FrameTypeFlags nFrameType = GetFrameType(nullptr,false);
+ if ( FrameTypeFlags::FLY_ANY & nFrameType )
+ {
+ if( MoveSection( GoCurrSection, fnSectionStart ) )
+ return true;
+ else if ( FrameTypeFlags::FLY_FREE & nFrameType || bDontMoveRegion )
+ return false;
+ }
+ if(( FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER | FrameTypeFlags::FOOTNOTE ) & nFrameType )
+ {
+ if ( MoveSection( GoCurrSection, fnSectionStart ) )
+ return true;
+ else if ( bKeepArea )
+ return true;
+ }
+
+ // first try to move to the start of the current SwSection
+ return SwCursorShell::MoveRegion( GotoCurrRegionAndSkip, fnRegionStart ) ||
+ (pMoveTable != nullptr
+ // move to start of text - if in different table, move out
+ ? MoveStartText()
+ // TODO who needs SttEndDoc for other case?
+ : SwCursorShell::SttEndDoc(true));
+}
+
+bool SwWrtShell::GoEnd(bool bKeepArea, const bool *pMoveTable)
+{
+ if (pMoveTable && *pMoveTable) // only in SelAll()
+ {
+ SwTableNode const*const pTable(getShellCursor(false)->GetPoint()->GetNode().FindTableNode());
+ assert(pTable);
+ if (MoveTable(GotoCurrTable, fnTableEnd))
+ {
+ return true;
+ }
+ else if (SwCursor const*const pCursor = getShellCursor(false);
+ pCursor->GetPoint()->GetNode().GetIndex()
+ < pTable->GetNodes()[pTable->EndOfSectionIndex()-1]->StartOfSectionIndex()
+ // problem: cursor isn't inside 1st cell, and didn't move there
+ // workaround: try to move cursor outside of table for SelAll()
+ && MoveOutOfTable())
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if ( IsCursorInTable() )
+ {
+ if ( MoveSection( GoCurrSection, fnSectionEnd ) ||
+ MoveTable( GotoCurrTable, fnTableEnd ) )
+ return true;
+ }
+ else
+ {
+ const FrameTypeFlags nFrameType = GetFrameType(nullptr,false);
+ if ( FrameTypeFlags::FLY_ANY & nFrameType )
+ {
+ if ( MoveSection( GoCurrSection, fnSectionEnd ) )
+ return true;
+ else if ( FrameTypeFlags::FLY_FREE & nFrameType )
+ return false;
+ }
+ if(( FrameTypeFlags::HEADER | FrameTypeFlags::FOOTER | FrameTypeFlags::FOOTNOTE ) & nFrameType )
+ {
+ if ( MoveSection( GoCurrSection, fnSectionEnd) )
+ return true;
+ else if ( bKeepArea )
+ return true;
+ }
+ }
+ // Regions ???
+ return SwCursorShell::MoveRegion( GotoCurrRegionAndSkip, fnRegionEnd ) ||
+ SwCursorShell::SttEndDoc(false);
+}
+
+bool SwWrtShell::StartOfSection(bool const bSelect)
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ return GoStart(false, nullptr, bSelect );
+}
+
+bool SwWrtShell::EndOfSection(bool const bSelect)
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ return GoEnd();
+}
+
+bool SwWrtShell::SttNxtPg( bool bSelect )
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ return MovePage( GetNextFrame, GetFirstSub );
+}
+
+void SwWrtShell::SttPrvPg( bool bSelect )
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ MovePage( GetPrevFrame, GetFirstSub );
+}
+
+void SwWrtShell::EndNxtPg( bool bSelect )
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ MovePage( GetNextFrame, GetLastSub );
+}
+
+bool SwWrtShell::EndPrvPg( bool bSelect )
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ return MovePage( GetPrevFrame, GetLastSub );
+}
+
+bool SwWrtShell::SttPg( bool bSelect )
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ return MovePage( GetThisFrame, GetFirstSub );
+}
+
+bool SwWrtShell::EndPg( bool bSelect )
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ return MovePage( GetThisFrame, GetLastSub );
+}
+
+bool SwWrtShell::SttPara( bool bSelect )
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ return MovePara( GoCurrPara, fnParaStart );
+}
+
+void SwWrtShell::EndPara( bool bSelect )
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ MovePara(GoCurrPara,fnParaEnd);
+}
+
+// Column-by-jumping.
+// SSelection with or without
+// returns success or failure
+
+void SwWrtShell::StartOfColumn()
+{
+ ShellMoveCursor aTmp( this, false/*bSelect*/);
+ MoveColumn(GetCurrColumn, GetColumnStt);
+}
+
+void SwWrtShell::EndOfColumn()
+{
+ ShellMoveCursor aTmp( this, false/*bSelect*/);
+ MoveColumn(GetCurrColumn, GetColumnEnd);
+}
+
+void SwWrtShell::StartOfNextColumn()
+{
+ ShellMoveCursor aTmp( this, false/*bSelect*/);
+ MoveColumn( GetNextColumn, GetColumnStt);
+}
+
+void SwWrtShell::EndOfNextColumn()
+{
+ ShellMoveCursor aTmp( this, false/*bSelect*/);
+ MoveColumn(GetNextColumn, GetColumnEnd);
+}
+
+void SwWrtShell::StartOfPrevColumn()
+{
+ ShellMoveCursor aTmp( this, false/*bSelect*/);
+ MoveColumn(GetPrevColumn, GetColumnStt);
+}
+
+void SwWrtShell::EndOfPrevColumn()
+{
+ ShellMoveCursor aTmp( this, false/*bSelect*/);
+ MoveColumn(GetPrevColumn, GetColumnEnd);
+}
+
+bool SwWrtShell::PushCursor(SwTwips lOffset, bool bSelect)
+{
+ bool bDiff = false;
+ SwRect aOldRect( GetCharRect() ), aTmpArea( VisArea() );
+
+ // m_bDestOnStack indicates if I could not set the coursor at the current
+ // position, because in this region is no content.
+ if( !m_bDestOnStack )
+ {
+ Point aPt( aOldRect.Center() );
+
+ if( !IsCursorVisible() )
+ // set CursorPos to top-/bottom left pos. So the pagescroll is not
+ // be dependent on the current cursor, but on the visarea.
+ aPt.setY( aTmpArea.Top() + aTmpArea.Height() / 2 );
+
+ aPt.AdjustY(lOffset );
+ m_aDest = GetContentPos(aPt,lOffset > 0);
+ m_aDest.setX( aPt.X() );
+ m_bDestOnStack = true;
+ }
+
+ // If we had a frame selection, it must be removed after the m_fnSetCursor
+ // and we have to remember the position on the stack to return to it later.
+ bool bIsFrameSel = false;
+
+ //Target position is now within the viewable region -->
+ //Place the cursor at the target position; remember that no target
+ //position is longer on the stack.
+ //The new visible region is to be determined beforehand.
+ aTmpArea.Pos().AdjustY(lOffset );
+ if( aTmpArea.Contains(m_aDest) )
+ {
+ if( bSelect )
+ SttSelect();
+ else
+ EndSelect();
+
+ bIsFrameSel = IsFrameSelected();
+ bool bIsObjSel = 0 != IsObjSelected();
+
+ // unselect frame
+ if( bIsFrameSel || bIsObjSel )
+ {
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ if ( bIsObjSel )
+ {
+ GetView().SetDrawFuncPtr( nullptr );
+ GetView().LeaveDrawCreate();
+ }
+
+ CallChgLnk();
+ }
+
+ (this->*m_fnSetCursor)( &m_aDest, true );
+
+ bDiff = aOldRect != GetCharRect();
+
+ if( bIsFrameSel )
+ {
+ // In frames take only the upper corner
+ // so that it can be re-selected.
+ aOldRect.SSize( 5, 5 );
+ }
+
+ // reset Dest. SPoint Flags
+ m_bDestOnStack = false;
+ }
+
+ // Position into the stack; bDiff indicates if there is a
+ // difference between the old and the new cursor position.
+ m_pCursorStack.reset( new CursorStack( bDiff, bIsFrameSel, aOldRect.Center(),
+ lOffset, std::move(m_pCursorStack) ) );
+ return !m_bDestOnStack && bDiff;
+}
+
+bool SwWrtShell::PopCursor(bool bUpdate, bool bSelect)
+{
+ if( nullptr == m_pCursorStack)
+ return false;
+
+ const bool bValidPos = m_pCursorStack->bValidCurPos;
+ if( bUpdate && bValidPos )
+ {
+ // If a predecessor is on the stack,
+ // use the flag for a valid position.
+ SwRect aTmpArea(VisArea());
+ aTmpArea.Pos().AdjustY( -(m_pCursorStack->lOffset) );
+ if( aTmpArea.Contains( m_pCursorStack->aDocPos ) )
+ {
+ if( bSelect )
+ SttSelect();
+ else
+ EndSelect();
+
+ (this->*m_fnSetCursor)(&m_pCursorStack->aDocPos, !m_pCursorStack->bIsFrameSel);
+ if( m_pCursorStack->bIsFrameSel && IsObjSelectable(m_pCursorStack->aDocPos))
+ {
+ HideCursor();
+ SelectObj( m_pCursorStack->aDocPos );
+ EnterSelFrameMode( &m_pCursorStack->aDocPos );
+ }
+ }
+ // If a discrepancy between the visible range and the
+ // remembered cursor position occurs, all of the remembered
+ // positions are thrown away.
+ else
+ {
+ ResetCursorStack_();
+ return false;
+ }
+ }
+ m_pCursorStack = std::move(m_pCursorStack->pNext);
+ if( nullptr == m_pCursorStack )
+ {
+ m_ePageMove = MV_NO;
+ m_bDestOnStack = false;
+ }
+ return bValidPos;
+}
+
+// Reset of all pushed cursor positions; these will
+// not be displayed ( --> No Start-/EndAction!!)
+
+void SwWrtShell::ResetCursorStack_()
+{
+ while(m_pCursorStack)
+ m_pCursorStack = std::move(m_pCursorStack->pNext);
+ m_ePageMove = MV_NO;
+ m_bDestOnStack = false;
+}
+/**
+ if no stack exists --> cancel selection
+ if stack && change of direction
+ --> pop cursor and return
+ else
+ --> push cursor
+ transpose cursor
+*/
+
+bool SwWrtShell::PageCursor(SwTwips lOffset, bool bSelect)
+{
+ // Do nothing if an offset of 0 was indicated
+ if(!lOffset) return false;
+ // Was once used to force a reformat of the layout.
+ // This has not work that way, because the cursor was not set
+ // because this does not happen within a
+ // Start-/EndActionParentheses.
+ // Because only SwViewShell::EndAction() is called at the end,
+ // no updating of the display of the cursor position takes place.
+ // The CursorShell-Actionparentheses cannot be used, because it
+ // always leads to displaying the cursor, thus also,
+ // if after the scroll scrolled in a region without a valid position.
+ // SwViewShell::StartAction();
+ PageMove eDir = lOffset > 0? MV_PAGE_DOWN: MV_PAGE_UP;
+ // Change of direction and stack present
+ if( eDir != m_ePageMove && m_ePageMove != MV_NO && PopCursor( true, bSelect ))
+ return true;
+
+ const bool bRet = PushCursor(lOffset, bSelect);
+ m_ePageMove = eDir;
+ return bRet;
+}
+
+bool SwWrtShell::GotoPage(sal_uInt16 nPage, bool bRecord)
+{
+ addCurrentPosition();
+ ShellMoveCursor aTmp( this, false);
+ if( SwCursorShell::GotoPage(nPage) && bRecord)
+ {
+ if(IsSelFrameMode())
+ {
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ }
+ return true;
+ }
+ return false;
+}
+
+bool SwWrtShell::GotoMark( const ::sw::mark::IMark* const pMark, bool bSelect )
+{
+ ShellMoveCursor aTmp( this, bSelect );
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwCursorShell::GotoMark( pMark, true/*bStart*/ );
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+ return bRet;
+}
+
+bool SwWrtShell::GotoFly( const OUString& rName, FlyCntType eType, bool bSelFrame )
+{
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwFEShell::GotoFly(rName, eType, bSelFrame);
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+ return bRet;
+}
+
+bool SwWrtShell::GotoINetAttr( const SwTextINetFormat& rAttr )
+{
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwCursorShell::GotoINetAttr(rAttr);
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+ return bRet;
+}
+
+void SwWrtShell::GotoOutline( SwOutlineNodes::size_type nIdx )
+{
+ addCurrentPosition();
+ SwCursorShell::GotoOutline (nIdx);
+}
+
+bool SwWrtShell::GotoOutline( const OUString& rName )
+{
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwCursorShell::GotoOutline (rName);
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+ return bRet;
+}
+
+bool SwWrtShell::GotoDrawingObject(std::u16string_view rName)
+{
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = false;
+ SdrView* pDrawView = GetDrawView();
+ if (pDrawView)
+ {
+ pDrawView->SdrEndTextEdit();
+ pDrawView->UnmarkAll();
+ SdrPage* pPage = getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
+ for (const rtl::Reference<SdrObject>& pObj : *pPage)
+ {
+ if (pObj->GetName() == rName)
+ {
+ SdrPageView* pPageView = pDrawView->GetSdrPageView();
+ if(pPageView)
+ {
+ pDrawView->MarkObj(pObj.get(), pPageView);
+ m_aNavigationMgr.addEntry(aPos);
+ EnterStdMode();
+ HideCursor();
+ EnterSelFrameMode();
+ bRet = true;
+ }
+ break;
+ }
+ }
+ }
+ return bRet;
+}
+
+bool SwWrtShell::GotoRegion( std::u16string_view rName )
+{
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwCursorShell::GotoRegion (rName);
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+ return bRet;
+ }
+
+bool SwWrtShell::GotoRefMark( const OUString& rRefMark, sal_uInt16 nSubType,
+ sal_uInt16 nSeqNo, sal_uInt16 nFlags )
+{
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwCursorShell::GotoRefMark(rRefMark, nSubType, nSeqNo, nFlags);
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+ return bRet;
+}
+
+bool SwWrtShell::GotoNextTOXBase( const OUString* pName )
+{
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwCursorShell::GotoNextTOXBase(pName);
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+ return bRet;
+}
+
+bool SwWrtShell::GotoTable( const OUString& rName )
+{
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwCursorShell::GotoTable(rName);
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+ return bRet;
+}
+
+void SwWrtShell::GotoFormatField( const SwFormatField& rField ) {
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwCursorShell::GotoFormatField(rField);
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+}
+
+void SwWrtShell::GotoFootnoteAnchor(const SwTextFootnote& rTextFootnote)
+{
+ SwPosition aPos = *GetCursor()->GetPoint();
+ bool bRet = SwCursorShell::GotoFootnoteAnchor(rTextFootnote);
+ if (bRet)
+ m_aNavigationMgr.addEntry(aPos);
+}
+
+const SwRangeRedline* SwWrtShell::GotoRedline( SwRedlineTable::size_type nArrPos, bool bSelect ) {
+ SwPosition aPos = *GetCursor()->GetPoint();
+ const SwRangeRedline *pRedline = SwCursorShell::GotoRedline(nArrPos, bSelect);
+ if (pRedline)
+ m_aNavigationMgr.addEntry(aPos);
+ return pRedline;
+}
+
+bool SwWrtShell::SelectTextAttr( sal_uInt16 nWhich, const SwTextAttr* pAttr )
+{
+ bool bRet;
+ {
+ SwMvContext aMvContext(this);
+ SttSelect();
+ bRet = SwCursorShell::SelectTextAttr( nWhich, false, pAttr );
+ }
+ EndSelect();
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/wrtsh/navmgr.cxx b/sw/source/uibase/wrtsh/navmgr.cxx
new file mode 100644
index 0000000000..eea6cda7dc
--- /dev/null
+++ b/sw/source/uibase/wrtsh/navmgr.cxx
@@ -0,0 +1,221 @@
+/* -*- 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/.
+ */
+
+#include <navmgr.hxx>
+#include <wrtsh.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/svapp.hxx>
+#include <cmdid.h>
+#include <view.hxx>
+#include <doc.hxx>
+#include <unocrsr.hxx>
+
+// This method positions the cursor to the position rPos.
+
+void SwNavigationMgr::GotoSwPosition(const SwPosition &rPos) {
+
+ // EnterStdMode() prevents the cursor to 'block' the current
+ // shell when it should move from the image back to the normal shell
+ m_rMyShell.EnterStdMode();
+ m_rMyShell.StartAllAction();
+ // cursor consists of two SwPositions: Point and Mark.
+ // Such a pair is called a PaM. SwPaM is derived from SwRing.
+ // The Ring contains the single regions of a multi-selection.
+ SwPaM* pPaM = m_rMyShell.GetCursor();
+
+ if(pPaM->HasMark())
+ pPaM->DeleteMark(); // If there was a selection, get rid of it
+ *pPaM->GetPoint() = rPos; // Position Cursor
+
+ m_rMyShell.EndAllAction();
+}
+
+// Ctor for the SwNavigationMgr class
+// Sets the shell to the current shell
+// and the index of the current position to 0
+
+SwNavigationMgr::SwNavigationMgr(SwWrtShell & rShell)
+ : m_nCurrent(0), m_rMyShell(rShell)
+{
+}
+
+SwNavigationMgr::~SwNavigationMgr()
+{
+ SolarMutexGuard g;
+ for (auto & it : m_entries)
+ {
+ EndListening(it->m_aNotifier);
+ }
+ m_entries.clear();
+}
+
+void SwNavigationMgr::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
+{
+ // our cursors may now spontaneously self-destruct: remove from
+ // m_entries if that happens
+ if (typeid(rHint) == typeid(sw::UnoCursorHint))
+ {
+ auto it = std::find_if(m_entries.begin(), m_entries.end(),
+ [&rBC](const sw::UnoCursorPointer& rItem) { return !rItem || &rBC == &rItem->m_aNotifier; });
+ if (it != m_entries.end())
+ {
+ EndListening(rBC);
+ m_entries.erase(it);
+ }
+ }
+}
+
+// This method is used by the navigation shell - defined in sw/source/uibase/inc/navsh.hxx
+// and implemented in sw/source/uibase/shells/navsh.cxx
+// It is called when we want to check if the back button should be enabled or not.
+// The back button should be enabled only if there are some entries in the navigation history
+
+bool SwNavigationMgr::backEnabled() {
+ return (m_nCurrent > 0);
+}
+
+// Similar to backEnabled() method.
+// The forward button should be enabled if we ever clicked back
+// Due to the implementation of the navigation class, this is when the
+// current position within the navigation history entries in not the last one
+// i.e. when the m_nCurrent index is not at the end of the m_entries vector
+
+bool SwNavigationMgr::forwardEnabled() {
+ return m_nCurrent+1 < m_entries.size();
+}
+
+// The goBack() method positions the cursor to the previous entry in the navigation history
+// If there was no history to go forward to, it adds the current position of the cursor
+// to the history so we could go forward to where we came from
+
+void SwNavigationMgr::goBack() {
+
+ // Although the button should be disabled whenever the backEnabled() returns false,
+ // the UI is sometimes not as responsive as we would like it to be :)
+ // this check prevents segmentation faults and in this way the class is not relying on the UI
+
+ if (!backEnabled()) return;
+
+ /* Trying to get the current cursor */
+ SwPaM* pPaM = m_rMyShell.GetCursor();
+ if (!pPaM) {
+ return;
+ }
+ // This flag will be used to manually refresh the buttons
+
+ bool bForwardWasDisabled = !forwardEnabled();
+
+ // If we're going backwards in our history, but the current location is not
+ // in the history then we need to add *here* to it so that we can "go
+ // forward" to here again.
+
+ if (bForwardWasDisabled) {
+
+ // the cursor consists of two SwPositions: Point and Mark.
+ // We are adding the current Point to the navigation history
+ // so we could later navigate forward to it
+
+ // The addEntry() method returns true iff we should decrement
+ // the index before navigating back
+
+ if (addEntry(*pPaM->GetPoint()) ) {
+ m_nCurrent--;
+ }
+ }
+ m_nCurrent--;
+ // Position cursor to appropriate navigation history entry
+ GotoSwPosition(*m_entries[m_nCurrent]->GetPoint());
+ // Refresh the buttons
+ if (bForwardWasDisabled)
+ m_rMyShell.GetView().GetViewFrame().GetBindings().Invalidate(FN_NAVIGATION_FORWARD);
+ if (!backEnabled())
+ m_rMyShell.GetView().GetViewFrame().GetBindings().Invalidate(FN_NAVIGATION_BACK);
+}
+
+// The goForward() method positions the cursor to the next entry in the navigation history
+
+void SwNavigationMgr::goForward() {
+
+ // Although the button should be disabled whenever the backForward() returns false,
+ // the UI is sometimes not as responsive as we would like it to be :)
+ // this check prevents segmentation faults and in this way the class is not relying on the UI
+
+ if (!forwardEnabled()) return;
+
+ // This flag will be used to manually refresh the buttons
+ bool bBackWasDisabled = !backEnabled();
+ // The current index is positioned at the current entry in the navigation history
+ // We have to increment it to go to the next entry
+ m_nCurrent++;
+ GotoSwPosition(*m_entries[m_nCurrent]->GetPoint());
+ // Refresh the buttons
+ if (bBackWasDisabled)
+ m_rMyShell.GetView().GetViewFrame().GetBindings().Invalidate(FN_NAVIGATION_BACK);
+ if (!forwardEnabled())
+ m_rMyShell.GetView().GetViewFrame().GetBindings().Invalidate(FN_NAVIGATION_FORWARD);
+}
+
+// This method adds the SwPosition rPos to the navigation history
+// rPos is usually the current position of the cursor in the document
+
+bool SwNavigationMgr::addEntry(const SwPosition& rPos) {
+
+ // Flags that will be used for refreshing the buttons
+ bool bBackWasDisabled = !backEnabled();
+ bool bForwardWasEnabled = forwardEnabled();
+
+ bool bRet = false; // return value of the function.
+ // Indicates whether the index should be decremented before
+ // jumping back or not
+ // The navigation history has recency with temporal ordering enhancement,
+ // as described on http://zing.ncsl.nist.gov/hfweb/proceedings/greenberg/
+ // If any forward history exists, twist the tail of the
+ // list from the current position to the end
+ if (bForwardWasEnabled) {
+
+ size_t number_ofm_entries = m_entries.size(); // To avoid calling m_entries.size() multiple times
+ int curr = m_nCurrent; // Index from which we'll twist the tail.
+ int n = (number_ofm_entries - curr) / 2; // Number of entries that will swap places
+ for (int i = 0; i < n; i++) {
+ std::swap(m_entries[curr + i], m_entries[number_ofm_entries -1 - i]);
+ }
+
+ if (*m_entries.back()->GetPoint() != rPos)
+ {
+ sw::UnoCursorPointer pCursor(m_rMyShell.GetDoc()->CreateUnoCursor(rPos));
+ StartListening(pCursor->m_aNotifier);
+ m_entries.push_back(pCursor);
+ }
+ bRet = true;
+ }
+ else {
+ if ( (!m_entries.empty() && *m_entries.back()->GetPoint() != rPos) || m_entries.empty() ) {
+ sw::UnoCursorPointer pCursor(m_rMyShell.GetDoc()->CreateUnoCursor(rPos));
+ StartListening(pCursor->m_aNotifier);
+ m_entries.push_back(pCursor);
+ bRet = true;
+ }
+ if (m_entries.size() > 1 && *m_entries.back()->GetPoint() == rPos)
+ bRet = true;
+ if (m_entries.size() == 1 && *m_entries.back()->GetPoint() == rPos)
+ bRet = false;
+ }
+ m_nCurrent = m_entries.size();
+
+ // Refresh buttons
+ if (bBackWasDisabled)
+ m_rMyShell.GetView().GetViewFrame().GetBindings().Invalidate(FN_NAVIGATION_BACK);
+ if (bForwardWasEnabled)
+ m_rMyShell.GetView().GetViewFrame().GetBindings().Invalidate(FN_NAVIGATION_FORWARD);
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/wrtsh/select.cxx b/sw/source/uibase/wrtsh/select.cxx
new file mode 100644
index 0000000000..3ae5842f61
--- /dev/null
+++ b/sw/source/uibase/wrtsh/select.cxx
@@ -0,0 +1,1057 @@
+/* -*- 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 <limits.h>
+#include <hintids.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/eitem.hxx>
+#include <svl/macitem.hxx>
+#include <unotools/charclass.hxx>
+#include <sfx2/event.hxx>
+#include <osl/diagnose.h>
+#include <cmdid.h>
+#include <view.hxx>
+#include <basesh.hxx>
+#include <wrtsh.hxx>
+#include <frmatr.hxx>
+#include <mdiexp.hxx>
+#include <fmtcol.hxx>
+#include <frmfmt.hxx>
+#include <swdtflvr.hxx>
+#include <doc.hxx>
+#include <wordcountdialog.hxx>
+#include <memory>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+
+#include <vcl/weld.hxx>
+#include <vcl/builder.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <unotools/configmgr.hxx>
+#include <bitmaps.hlst>
+
+#include <svx/svdview.hxx>
+
+namespace com::sun::star::util {
+ struct SearchOptions2;
+}
+
+using namespace ::com::sun::star::util;
+
+static tools::Long nStartDragX = 0, nStartDragY = 0;
+static bool bStartDrag = false;
+
+void SwWrtShell::Invalidate()
+{
+ // to avoid making the slot volatile, invalidate it every time if something could have been changed
+ // this is still much cheaper than asking for the state every 200 ms (and avoid background processing)
+ GetView().GetViewFrame().GetBindings().Invalidate( FN_STAT_SELMODE );
+ GetView().GetViewFrame().GetBindings().Update(FN_STAT_SELMODE); // make selection mode control icon update immediately
+ SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
+ if (pWrdCnt)
+ pWrdCnt->UpdateCounts();
+}
+
+bool SwWrtShell::SelNearestWrd()
+{
+ SwMvContext aMvContext(this);
+ if( !IsInWord() && !IsEndWrd() && !IsStartWord() )
+ PrvWrd();
+ if( IsEndWrd() )
+ Left(SwCursorSkipMode::Cells, false, 1, false );
+ return SelWrd();
+}
+
+bool SwWrtShell::SelWrd(const Point *pPt )
+{
+ bool bRet;
+ {
+ SwMvContext aMvContext(this);
+ SttSelect();
+ bRet = SwCursorShell::SelectWord( pPt );
+ }
+ EndSelect();
+ if( bRet )
+ {
+ m_bSelWrd = true;
+ if(pPt)
+ m_aStart = *pPt;
+ }
+ return bRet;
+}
+
+void SwWrtShell::SelSentence(const Point *pPt )
+{
+ {
+ SwMvContext aMvContext(this);
+ ClearMark();
+ SwCursorShell::GoStartSentence();
+ SttSelect();
+ SwCursorShell::GoEndSentence();
+ }
+ EndSelect();
+ if(pPt)
+ m_aStart = *pPt;
+ m_bSelLn = true;
+ m_bSelWrd = false; // disable SelWord, otherwise no SelLine goes on
+}
+
+void SwWrtShell::SelPara(const Point *pPt )
+{
+ {
+ SwMvContext aMvContext(this);
+ ClearMark();
+ SwCursorShell::MovePara( GoCurrPara, fnParaStart );
+ SttSelect();
+ SwCursorShell::MovePara( GoCurrPara, fnParaEnd );
+ }
+ EndSelect();
+ if(pPt)
+ m_aStart = *pPt;
+ m_bSelLn = false;
+ m_bSelWrd = false; // disable SelWord, otherwise no SelLine goes on
+}
+
+void SwWrtShell::SelAll()
+{
+ const bool bLockedView = IsViewLocked();
+ LockView( true );
+ {
+ if(m_bBlockMode)
+ LeaveBlockMode();
+ SwMvContext aMvContext(this);
+ bool bMoveTable = false;
+ std::optional<SwPosition> oStartPos;
+ std::optional<SwPosition> oEndPos;
+ SwShellCursor* pTmpCursor = nullptr;
+
+ // Query these early, before we move the cursor.
+ bool bHasWholeTabSelection = HasWholeTabSelection();
+ bool bIsCursorInTable = IsCursorInTable();
+
+ if (!bHasWholeTabSelection
+ && ( !bIsCursorInTable
+ || getShellCursor(false)->GetMarkNode().FindTableNode() == nullptr
+ || !ExtendedSelectedAll())) // ESA inside table -> else branch
+ {
+ if ( IsSelection() && IsCursorPtAtEnd() )
+ SwapPam();
+ pTmpCursor = getShellCursor( false );
+ if( pTmpCursor )
+ {
+ oStartPos.emplace( *pTmpCursor->GetPoint() );
+ oEndPos.emplace( *pTmpCursor->GetMark() );
+ }
+ Push();
+ bool bIsFullSel = !MoveSection( GoCurrSection, fnSectionStart);
+ SwapPam();
+ bIsFullSel &= !MoveSection( GoCurrSection, fnSectionEnd);
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ GoStart(true, &bMoveTable, false, !bIsFullSel);
+ SttSelect();
+ GoEnd(true, &bMoveTable);
+ }
+ else
+ {
+ if (MoveOutOfTable())
+ { // select outer text
+ EnterStdMode(); // delete m_pTableCursor
+// GoStart(true, &bMoveTable, false, true);
+ MoveSection(GoCurrSection, fnSectionStart); // don't move into prev table
+ SttSelect();
+ MoveSection(GoCurrSection, fnSectionEnd); // don't move to different cell
+ }
+ else
+ {
+ TrySelectOuterTable();
+ }
+ }
+
+ bool bNeedsExtendedSelectAll = StartsWith_() != StartsWith::None;
+
+ // the GoEnd() could have created a table selection, if so avoid ESA.
+ if (bNeedsExtendedSelectAll && bIsCursorInTable)
+ {
+ bNeedsExtendedSelectAll = !HasWholeTabSelection();
+ }
+
+ if (bNeedsExtendedSelectAll)
+ {
+ ExtendedSelectAll(/*bFootnotes =*/ false);
+ }
+
+ SwDoc *pDoc = GetDoc();
+ if ( pDoc )
+ {
+ pDoc->SetPrepareSelAll();
+ }
+
+ if( oStartPos )
+ {
+ pTmpCursor = getShellCursor( false );
+ if( pTmpCursor )
+ {
+ // Some special handling for sections (e.g. TOC) at the beginning of the document body
+ // to avoid the selection of the first section
+ // if the last selection was behind the first section or
+ // if the last selection was already the first section
+ // In this both cases we select to the end of document
+ if( ( *pTmpCursor->GetPoint() < *oEndPos ||
+ ( *oStartPos == *pTmpCursor->GetMark() &&
+ *oEndPos == *pTmpCursor->GetPoint() ) ) && !bNeedsExtendedSelectAll)
+ SwCursorShell::SttEndDoc(false);
+ }
+ }
+ }
+ EndSelect();
+ LockView( bLockedView );
+}
+
+// Description: Text search
+
+sal_Int32 SwWrtShell::SearchPattern( const i18nutil::SearchOptions2& rSearchOpt, bool bSearchInNotes,
+ SwDocPositions eStt, SwDocPositions eEnd,
+ FindRanges eFlags, bool bReplace )
+{
+ // no enhancement of existing selections
+ if(!(eFlags & FindRanges::InSel))
+ ClearMark();
+ bool bCancel = false;
+ sal_Int32 nRet = Find_Text(rSearchOpt, bSearchInNotes, eStt, eEnd, bCancel, eFlags, bReplace);
+ if(bCancel)
+ {
+ Undo();
+ nRet = SAL_MAX_INT32;
+ }
+ return nRet;
+}
+
+// Description: search for templates
+
+sal_Int32 SwWrtShell::SearchTempl( const OUString &rTempl,
+ SwDocPositions eStt, SwDocPositions eEnd,
+ FindRanges eFlags, const OUString* pReplTempl )
+{
+ // no enhancement of existing selections
+ if(!(eFlags & FindRanges::InSel))
+ ClearMark();
+ SwTextFormatColl *pColl = GetParaStyle(rTempl, SwWrtShell::GETSTYLE_CREATESOME);
+ SwTextFormatColl *pReplaceColl = nullptr;
+ if( pReplTempl )
+ pReplaceColl = GetParaStyle(*pReplTempl, SwWrtShell::GETSTYLE_CREATESOME );
+
+ bool bCancel = false;
+ sal_Int32 nRet = FindFormat(pColl ? *pColl : GetDfltTextFormatColl(),
+ eStt,eEnd, bCancel, eFlags, pReplaceColl);
+ if(bCancel)
+ {
+ Undo();
+ nRet = SAL_MAX_INT32;
+ }
+ return nRet;
+}
+
+// search for attributes
+
+sal_Int32 SwWrtShell::SearchAttr( const SfxItemSet& rFindSet, bool bNoColls,
+ SwDocPositions eStart, SwDocPositions eEnd,
+ FindRanges eFlags, const i18nutil::SearchOptions2* pSearchOpt,
+ const SfxItemSet* pReplaceSet )
+{
+ // no enhancement of existing selections
+ if (!(eFlags & FindRanges::InSel))
+ ClearMark();
+
+ // Searching
+ bool bCancel = false;
+ sal_Int32 nRet = FindAttrs(rFindSet, bNoColls, eStart, eEnd, bCancel, eFlags, pSearchOpt, pReplaceSet);
+
+ if(bCancel)
+ {
+ Undo();
+ nRet = SAL_MAX_INT32;
+ }
+ return nRet;
+}
+
+// Selection modes
+
+void SwWrtShell::PushMode()
+{
+ m_pModeStack = new ModeStack( m_pModeStack, m_bIns, m_bExtMode, m_bAddMode, m_bBlockMode );
+}
+
+void SwWrtShell::PopMode()
+{
+ if ( nullptr == m_pModeStack )
+ return;
+
+ if ( m_bExtMode && !m_pModeStack->bExt )
+ LeaveExtMode();
+ if ( m_bAddMode && !m_pModeStack->bAdd )
+ LeaveAddMode();
+ if ( m_bBlockMode && !m_pModeStack->bBlock )
+ LeaveBlockMode();
+ m_bIns = m_pModeStack->bIns;
+
+ m_pModeStack = std::move(m_pModeStack->pNext);
+}
+
+// Two methods for setting cursors: the first maps at the
+// eponymous methods in the CursorShell, the second removes
+// all selections at first.
+
+tools::Long SwWrtShell::SetCursor(const Point *pPt, bool bTextOnly)
+{
+ // Remove a possibly present selection at the position
+ // of the mouseclick
+
+ if(!IsInSelect() && TestCurrPam(*pPt)) {
+ ClearMark();
+ }
+
+ return SwCursorShell::SetCursor(*pPt, bTextOnly);
+}
+
+tools::Long SwWrtShell::SetCursorKillSel(const Point *pPt, bool bTextOnly )
+{
+ SwActContext aActContext(this);
+ ResetSelect(pPt,false);
+ return SwCursorShell::SetCursor(*pPt, bTextOnly);
+}
+
+void SwWrtShell::UnSelectFrame()
+{
+ // Remove Frame selection with guaranteed invalid position
+ Point aPt(LONG_MIN, LONG_MIN);
+ SelectObj(aPt);
+ SwTransferable::ClearSelection( *this );
+}
+
+// Remove of all selections
+
+tools::Long SwWrtShell::ResetSelect(const Point *,bool)
+{
+ if(IsSelFrameMode())
+ {
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ }
+ else
+ {
+ // SwActContext opens an Action -
+ // to avoid problems in the basic process with the
+ // shell switching, GetChgLnk().Call() may be called
+ // after EndAction().
+ {
+ SwActContext aActContext(this);
+ m_bSelWrd = m_bSelLn = false;
+ KillPams();
+ ClearMark();
+ m_fnKillSel = &SwWrtShell::Ignore;
+ m_fnSetCursor = &SwWrtShell::SetCursor;
+ }
+
+ // After canceling of all selections an update of Attr-Controls
+ // could be necessary.
+ GetChgLnk().Call(nullptr);
+
+ if ( GetEnhancedTableSelection() != SwTable::SEARCH_NONE )
+ UnsetEnhancedTableSelection();
+ }
+ Invalidate();
+ SwTransferable::ClearSelection( *this );
+ return 1;
+}
+
+bool SwWrtShell::IsSplitVerticalByDefault() const
+{
+ return GetDoc()->IsSplitVerticalByDefault();
+}
+
+void SwWrtShell::SetSplitVerticalByDefault(bool value)
+{
+ GetDoc()->SetSplitVerticalByDefault(value);
+}
+
+// Do nothing
+
+tools::Long SwWrtShell::Ignore(const Point *, bool ) {
+ return 1;
+}
+
+// Begin of a selection process.
+
+void SwWrtShell::SttSelect()
+{
+ if(m_bInSelect)
+ return;
+ if(!HasMark())
+ SetMark();
+ if( m_bBlockMode )
+ {
+ SwShellCursor* pTmp = getShellCursor( true );
+ if( !pTmp->HasMark() )
+ pTmp->SetMark();
+ }
+ m_fnKillSel = &SwWrtShell::Ignore;
+ m_fnSetCursor = &SwWrtShell::SetCursor;
+ m_bInSelect = true;
+ Invalidate();
+ SwTransferable::CreateSelection( *this );
+}
+
+namespace {
+
+void collectUIInformation(SwShellCursor* pCursor)
+{
+ EventDescription aDescription;
+ OUString aSelStart = OUString::number(pCursor->Start()->GetContentIndex());
+ OUString aSelEnd = OUString::number(pCursor->End()->GetContentIndex());
+
+ aDescription.aParameters = {{"START_POS", aSelStart}, {"END_POS", aSelEnd}};
+ aDescription.aAction = "SELECT";
+ aDescription.aID = "writer_edit";
+ aDescription.aKeyWord = "SwEditWinUIObject";
+ aDescription.aParent = "MainWindow";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+// End of a selection process.
+
+void SwWrtShell::EndSelect()
+{
+ if(m_bInSelect && !m_bExtMode)
+ {
+ m_bInSelect = false;
+ if (m_bAddMode)
+ {
+ AddLeaveSelect();
+ }
+ else
+ {
+ SttLeaveSelect();
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ }
+ }
+ SwWordCountWrapper *pWrdCnt = static_cast<SwWordCountWrapper*>(GetView().GetViewFrame().GetChildWindow(SwWordCountWrapper::GetChildWindowId()));
+ if (pWrdCnt)
+ pWrdCnt->UpdateCounts();
+
+ collectUIInformation(GetCursor_());
+}
+
+void SwWrtShell::ExtSelWrd(const Point *pPt, bool )
+{
+ SwMvContext aMvContext(this);
+ if( IsTableMode() )
+ return;
+
+ // Bug 66823: actual crsr has in additional mode no selection?
+ // Then destroy the actual and go to prev, this will be expand
+ if( !HasMark() && GoPrevCursor() )
+ {
+ bool bHasMark = HasMark(); // that's wrong!
+ GoNextCursor();
+ if( bHasMark )
+ {
+ DestroyCursor();
+ GoPrevCursor();
+ }
+ }
+
+ // check the direction of the selection with the new point
+ bool bMoveCursor = true, bToTop = false;
+ SwCursorShell::SelectWord( &m_aStart ); // select the startword
+ SwCursorShell::Push(); // save the cursor
+ SwCursorShell::SetCursor( *pPt ); // and check the direction
+
+ switch( SwCursorShell::CompareCursorStackMkCurrPt())
+ {
+ case -1: bToTop = false; break;
+ case 1: bToTop = true; break;
+ default: bMoveCursor = false; break;
+ }
+
+ SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent); // restore the saved cursor
+
+ if( !bMoveCursor )
+ return;
+
+ // select to Top but cursor select to Bottom? or
+ // select to Bottom but cursor select to Top? --> swap the cursor
+ if( bToTop )
+ SwapPam();
+
+ SwCursorShell::Push(); // save cur cursor
+ if( SwCursorShell::SelectWord( pPt )) // select the current word
+ {
+ if( bToTop )
+ SwapPam();
+ Combine();
+ }
+ else
+ {
+ SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
+ if( bToTop )
+ SwapPam();
+ }
+}
+
+void SwWrtShell::ExtSelLn(const Point *pPt, bool )
+{
+ SwMvContext aMvContext(this);
+ SwCursorShell::SetCursor(*pPt);
+ if( IsTableMode() )
+ return;
+
+ // Bug 66823: actual crsr has in additional mode no selection?
+ // Then destroy the actual and go to prev, this will be expand
+ if( !HasMark() && GoPrevCursor() )
+ {
+ bool bHasMark = HasMark(); // that's wrong!
+ GoNextCursor();
+ if( bHasMark )
+ {
+ DestroyCursor();
+ GoPrevCursor();
+ }
+ }
+
+ // if applicable fit the selection to the "Mark"
+ bool bToTop = !IsCursorPtAtEnd();
+ SwapPam();
+
+ // The "Mark" has to be at the end or the beginning of the line.
+ if( bToTop ? !IsEndSentence() : !IsStartSentence() )
+ {
+ if( bToTop )
+ {
+ if( !IsEndPara() )
+ SwCursorShell::Right(1,SwCursorSkipMode::Chars);
+ SwCursorShell::GoEndSentence();
+ }
+ else
+ SwCursorShell::GoStartSentence();
+ }
+ SwapPam();
+
+ if (bToTop)
+ SwCursorShell::GoStartSentence();
+ else
+ SwCursorShell::GoEndSentence();
+}
+
+// Back into the standard mode: no mode, no selections.
+
+void SwWrtShell::EnterStdMode()
+{
+ if(m_bAddMode)
+ LeaveAddMode();
+ if(m_bBlockMode)
+ LeaveBlockMode();
+ m_bBlockMode = false;
+ m_bExtMode = false;
+ m_bInSelect = false;
+ if(IsSelFrameMode())
+ {
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ }
+ else
+ {
+ // SwActContext opens and action which has to be
+ // closed prior to the call of
+ // GetChgLnk().Call()
+ SwActContext aActContext(this);
+ m_bSelWrd = m_bSelLn = false;
+ if( !IsRetainSelection() )
+ KillPams();
+ ClearMark();
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ }
+ Invalidate();
+ SwTransferable::ClearSelection( *this );
+}
+
+void SwWrtShell::AssureStdMode()
+{
+ // deselect any drawing or frame and leave editing mode
+ if (SdrView* pSdrView = GetDrawView())
+ {
+ if (pSdrView->IsTextEdit())
+ {
+ bool bLockView = IsViewLocked();
+ LockView(true);
+ EndTextEdit();
+ LockView(bLockView);
+ }
+ // go out of the frame
+ Point aPt(LONG_MIN, LONG_MIN);
+ SelectObj(aPt, SW_LEAVE_FRAME);
+ }
+ if (IsSelFrameMode() || IsObjSelected())
+ {
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ GetView().LeaveDrawCreate();
+ EnterStdMode();
+ DrawSelChanged();
+ GetView().StopShellTimer();
+ }
+ else
+ EnterStdMode();
+}
+
+// Extended Mode
+
+void SwWrtShell::EnterExtMode()
+{
+ if(m_bBlockMode)
+ {
+ LeaveBlockMode();
+ KillPams();
+ ClearMark();
+ }
+ m_bExtMode = true;
+ m_bAddMode = false;
+ m_bBlockMode = false;
+ SttSelect();
+}
+
+void SwWrtShell::LeaveExtMode()
+{
+ m_bExtMode = false;
+ EndSelect();
+}
+
+// End of a selection; if the selection is empty,
+// ClearMark().
+
+void SwWrtShell::SttLeaveSelect()
+{
+ if(SwCursorShell::HasSelection() && !IsSelTableCells() && m_bClearMark) {
+ return;
+ }
+ ClearMark();
+}
+
+// Leaving of the selection mode in additional mode
+
+void SwWrtShell::AddLeaveSelect()
+{
+ if(IsTableMode()) LeaveAddMode();
+ else if(SwCursorShell::HasSelection())
+ CreateCursor();
+}
+
+// Additional Mode
+
+void SwWrtShell::EnterAddMode()
+{
+ if(IsTableMode()) return;
+ if(m_bBlockMode)
+ LeaveBlockMode();
+ m_fnKillSel = &SwWrtShell::Ignore;
+ m_fnSetCursor = &SwWrtShell::SetCursor;
+ m_bAddMode = true;
+ m_bBlockMode = false;
+ m_bExtMode = false;
+ if(SwCursorShell::HasSelection())
+ CreateCursor();
+ Invalidate();
+}
+
+void SwWrtShell::LeaveAddMode()
+{
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ m_bAddMode = false;
+ Invalidate();
+}
+
+// Block Mode
+
+void SwWrtShell::EnterBlockMode()
+{
+ m_bBlockMode = false;
+ EnterStdMode();
+ m_bBlockMode = true;
+ CursorToBlockCursor();
+ Invalidate();
+}
+
+void SwWrtShell::LeaveBlockMode()
+{
+ m_bBlockMode = false;
+ BlockCursorToCursor();
+ EndSelect();
+ Invalidate();
+}
+
+// Insert mode
+
+void SwWrtShell::SetInsMode( bool bOn )
+{
+ const bool bDoAsk = officecfg::Office::Common::Misc::QuerySetInsMode::get();
+ if (!bOn && bDoAsk) {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetView().GetFrameWeld(), "cui/ui/querysetinsmodedialog.ui"));
+ std::unique_ptr<weld::Dialog> xQuery(xBuilder->weld_dialog("SetInsModeDialog"));
+ std::unique_ptr<weld::Image> xImage(xBuilder->weld_image("imSetInsMode"));
+ std::unique_ptr<weld::CheckButton> xCheckBox(xBuilder->weld_check_button("cbDontShowAgain"));
+
+ xImage->set_from_icon_name(RID_BMP_QUERYINSMODE);
+
+ const int nResult = xQuery->run();
+
+ std::shared_ptr<comphelper::ConfigurationChanges> xChanges(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::QuerySetInsMode::set(!xCheckBox->get_active(), xChanges);
+ xChanges->commit();
+
+ if ( nResult == static_cast<int>(RET_NO) )
+ return;
+ }
+ m_bIns = bOn;
+ SwCursorShell::SetOverwriteCursor( !m_bIns );
+ const SfxBoolItem aTmp( SID_ATTR_INSERT, m_bIns );
+ GetView().GetViewFrame().GetBindings().SetState( aTmp );
+ StartAction();
+ EndAction();
+ Invalidate();
+}
+//Overwrite mode is incompatible with red-lining
+void SwWrtShell::SetRedlineFlagsAndCheckInsMode( RedlineFlags eMode )
+{
+ SetRedlineFlags( eMode );
+ if (IsRedlineOn())
+ SetInsMode();
+}
+
+// Edit frame
+
+void SwWrtShell::BeginFrameDrag(const Point *pPt, bool bIsShift)
+{
+ m_fnDrag = &SwFEShell::Drag;
+ if(bStartDrag)
+ {
+ Point aTmp( nStartDragX, nStartDragY );
+ SwFEShell::BeginDrag( &aTmp, bIsShift );
+ }
+ else
+ SwFEShell::BeginDrag( pPt, bIsShift );
+}
+
+void SwWrtShell::EnterSelFrameMode(const Point *pPos)
+{
+ if(pPos)
+ {
+ nStartDragX = pPos->X();
+ nStartDragY = pPos->Y();
+ bStartDrag = true;
+ }
+ m_bLayoutMode = true;
+ HideCursor();
+
+ // equal call of BeginDrag in the SwFEShell
+ m_fnDrag = &SwWrtShell::BeginFrameDrag;
+ m_fnEndDrag = &SwWrtShell::UpdateLayoutFrame;
+ SwBaseShell::SetFrameMode( FLY_DRAG_START, this );
+ Invalidate();
+}
+
+void SwWrtShell::LeaveSelFrameMode()
+{
+ m_fnDrag = &SwWrtShell::BeginDrag;
+ m_fnEndDrag = &SwWrtShell::DefaultEndDrag;
+ m_bLayoutMode = false;
+ bStartDrag = false;
+ Edit();
+ SwBaseShell::SetFrameMode( FLY_DRAG_END, this );
+ Invalidate();
+}
+
+// Description: execute framebound macro
+
+IMPL_LINK( SwWrtShell, ExecFlyMac, const SwFlyFrameFormat*, pFlyFormat, void )
+{
+ const SwFrameFormat *pFormat = pFlyFormat ? static_cast<const SwFrameFormat*>(pFlyFormat) : GetFlyFrameFormat();
+ OSL_ENSURE(pFormat, "no frame format");
+ const SvxMacroItem &rFormatMac = pFormat->GetMacro();
+
+ if(rFormatMac.HasMacro(SvMacroItemId::SwObjectSelect))
+ {
+ const SvxMacro &rMac = rFormatMac.GetMacro(SvMacroItemId::SwObjectSelect);
+ if( IsFrameSelected() )
+ m_bLayoutMode = true;
+ CallChgLnk();
+ ExecMacro( rMac );
+ }
+}
+
+void SwWrtShell::UpdateLayoutFrame(const Point *, bool )
+{
+ // still a dummy
+ SwFEShell::EndDrag();
+ m_fnDrag = &SwWrtShell::BeginFrameDrag;
+}
+
+// Handler for toggling the modes. Returns back the old mode.
+
+void SwWrtShell::ToggleAddMode()
+{
+ m_bAddMode ? LeaveAddMode(): EnterAddMode();
+ Invalidate();
+}
+
+void SwWrtShell::ToggleBlockMode()
+{
+ m_bBlockMode ? LeaveBlockMode(): EnterBlockMode();
+ Invalidate();
+}
+
+void SwWrtShell::ToggleExtMode()
+{
+ m_bExtMode ? LeaveExtMode() : EnterExtMode();
+ Invalidate();
+}
+
+// Dragging in standard mode (Selecting of content)
+
+void SwWrtShell::BeginDrag(const Point * /*pPt*/, bool )
+{
+ if(m_bSelWrd)
+ {
+ m_bInSelect = true;
+ if( !IsCursorPtAtEnd() )
+ SwapPam();
+
+ m_fnDrag = &SwWrtShell::ExtSelWrd;
+ m_fnSetCursor = &SwWrtShell::Ignore;
+ }
+ else if(m_bSelLn)
+ {
+ m_bInSelect = true;
+ m_fnDrag = &SwWrtShell::ExtSelLn;
+ m_fnSetCursor = &SwWrtShell::Ignore;
+ }
+ else
+ {
+ m_fnDrag = &SwWrtShell::DefaultDrag;
+ SttSelect();
+ }
+}
+
+void SwWrtShell::DefaultDrag(const Point *, bool )
+{
+ if( IsSelTableCells() )
+ m_aSelTableLink.Call(*this);
+}
+
+void SwWrtShell::DefaultEndDrag(const Point * /*pPt*/, bool )
+{
+ m_fnDrag = &SwWrtShell::BeginDrag;
+ if( IsExtSel() )
+ LeaveExtSel();
+
+ if( IsSelTableCells() )
+ m_aSelTableLink.Call(*this);
+ EndSelect();
+}
+
+// #i32329# Enhanced table selection
+bool SwWrtShell::SelectTableRowCol( const Point& rPt, const Point* pEnd, bool bRowDrag )
+{
+ SwMvContext aMvContext(this);
+ SttSelect();
+ if(SelTableRowCol( rPt, pEnd, bRowDrag ))
+ {
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ return true;
+ }
+ return false;
+}
+
+// Description: Selection of a table line or column
+
+void SwWrtShell::SelectTableRow()
+{
+ if ( SelTableRow() )
+ {
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ }
+}
+
+void SwWrtShell::SelectTableCol()
+{
+ if ( SelTableCol() )
+ {
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ }
+}
+
+void SwWrtShell::SelectTableCell()
+{
+ if ( SelTableBox() )
+ {
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ }
+}
+
+// Description: Check if a word selection is present.
+// According to the rules for intelligent cut / paste
+// surrounding spaces are cut out.
+// Return: Delivers the type of the word selection.
+
+int SwWrtShell::IntelligentCut(SelectionType nSelection, bool bCut)
+{
+ // On multiple selection no intelligent drag and drop
+ // there are multiple cursors, since a second was placed
+ // already at the target position.
+ if( IsAddMode() || !(nSelection & SelectionType::Text) )
+ return NO_WORD;
+
+ OUString sText;
+ CharClass& rCC = GetAppCharClass();
+
+ // If the first character is no word character,
+ // no word selected.
+ sal_Unicode cPrev = GetChar(false);
+ sal_Unicode cNext = GetChar(true, -1);
+ if( !cPrev || !cNext ||
+ !rCC.isLetterNumeric( ( sText = OUString(cPrev) ), 0 ) ||
+ !rCC.isLetterNumeric( ( sText = OUString(cNext) ), 0 ) )
+ return NO_WORD;
+
+ cPrev = GetChar(false, -1);
+ cNext = GetChar();
+
+ int cWord = NO_WORD;
+ // is a word selected?
+ if (cPrev && cNext &&
+ CH_TXTATR_BREAKWORD != cPrev && CH_TXTATR_INWORD != cPrev &&
+ CH_TXTATR_BREAKWORD != cNext && CH_TXTATR_INWORD != cNext &&
+ !rCC.isLetterNumeric( ( sText = OUString(cPrev) ), 0 ) &&
+ !rCC.isLetterNumeric( ( sText = OUString(cNext) ), 0 ) )
+ cWord = WORD_NO_SPACE;
+
+ if(cWord == WORD_NO_SPACE && ' ' == cPrev )
+ {
+ cWord = WORD_SPACE_BEFORE;
+ // delete the space before
+ if(bCut)
+ {
+ Push();
+ if(IsCursorPtAtEnd())
+ SwapPam();
+ ClearMark();
+ SetMark();
+ SwCursorShell::Left(1,SwCursorSkipMode::Chars);
+ SwFEShell::Delete(true);
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ }
+ }
+ else if(cWord == WORD_NO_SPACE && cNext == ' ')
+ {
+ cWord = WORD_SPACE_AFTER;
+ // delete the space behind
+ if(bCut) {
+ Push();
+ if(!IsCursorPtAtEnd()) SwapPam();
+ ClearMark();
+ SetMark();
+ SwCursorShell::Right(1,SwCursorSkipMode::Chars);
+ SwFEShell::Delete(true);
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ }
+ }
+ return cWord;
+}
+
+ // jump to the next / previous hyperlink - inside text and also
+ // on graphics
+void SwWrtShell::SelectNextPrevHyperlink( bool bNext )
+{
+ StartAction();
+ bool bRet = SwCursorShell::SelectNxtPrvHyperlink( bNext );
+ if( !bRet ) // didn't find? wrap and check again
+ {
+ SwShellCursor* pCursor = GetCursor_();
+ SwCursorSaveState aSaveState(*pCursor);
+ EnterStdMode();
+ if( bNext )
+ SttEndDoc(true);
+ else
+ SttEndDoc(false);
+ bRet = SwCursorShell::SelectNxtPrvHyperlink(bNext);
+ if (!bRet) // didn't find again? restore cursor position and bail
+ {
+ pCursor->RestoreSavePos();
+ EndAction(true); // don't scroll to restored cursor position
+ return;
+ }
+ }
+ EndAction();
+
+ bool bCreateXSelection = false;
+ const bool bFrameSelected = IsFrameSelected() || IsObjSelected();
+ if( IsSelection() )
+ {
+ if ( bFrameSelected )
+ UnSelectFrame();
+
+ // Set the function pointer for the canceling of the selection
+ // set at cursor
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ bCreateXSelection = true;
+ }
+ else if( bFrameSelected )
+ {
+ EnterSelFrameMode();
+ bCreateXSelection = true;
+ }
+ else if( (CNT_GRF | CNT_OLE ) & GetCntType() )
+ {
+ SelectObj( GetCharRect().Pos() );
+ EnterSelFrameMode();
+ bCreateXSelection = true;
+ }
+
+ if( bCreateXSelection )
+ SwTransferable::CreateSelection( *this );
+}
+
+// For the preservation of the selection the cursor will be moved left
+// after SetMark(), so that the cursor is not moved by inserting text.
+// Because a present selection at the CORE page is cleared at the
+// current cursor position, the cursor will be pushed on the stack.
+// After moving, they will again resummarized.
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx
new file mode 100644
index 0000000000..4b2402fc93
--- /dev/null
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -0,0 +1,2731 @@
+/* -*- 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 <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/embed/EmbedMisc.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+
+#include <hintids.hxx>
+#include <sot/exchange.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/hdft.hxx>
+#include <svx/svdview.hxx>
+#include <svl/itemiter.hxx>
+#include <tools/bigint.hxx>
+#include <svtools/insdlg.hxx>
+#include <sfx2/ipclient.hxx>
+#include <editeng/formatbreakitem.hxx>
+#include <editeng/svxacorr.hxx>
+#include <editeng/ulspitem.hxx>
+#include <vcl/graph.hxx>
+#include <unotools/charclass.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/extrusionbar.hxx>
+#include <svx/fontworkbar.hxx>
+#include <dialoghelp.hxx>
+#include <frmfmt.hxx>
+#include <fmtftn.hxx>
+#include <fmthdft.hxx>
+#include <fmtpdsc.hxx>
+#include <txtfrm.hxx>
+#include <wdocsh.hxx>
+#include <swmodule.hxx>
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <cmdid.h>
+#include <pagedesc.hxx>
+#include <frmmgr.hxx>
+#include <swundo.hxx>
+#include <swcli.hxx>
+#include <poolfmt.hxx>
+#include <edtwin.hxx>
+#include <fmtcol.hxx>
+#include <swtable.hxx>
+#include <viscrs.hxx>
+#include <swdtflvr.hxx>
+#include <doc.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <SwCapObjType.hxx>
+#include <SwStyleNameMapper.hxx>
+#include <sfx2/request.hxx>
+#include <paratr.hxx>
+#include <ndtxt.hxx>
+#include <editeng/acorrcfg.hxx>
+#include <IMark.hxx>
+#include <sfx2/bindings.hxx>
+#include <flyfrm.hxx>
+
+// -> #111827#
+#include <SwRewriter.hxx>
+#include <strings.hrc>
+// <- #111827#
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/unit_conversion.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <PostItMgr.hxx>
+#include <FrameControlsManager.hxx>
+#include <fldmgr.hxx>
+#include <docufld.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <fmtfld.hxx>
+
+#include <sfx2/msgpool.hxx>
+#include <sfx2/msg.hxx>
+#include <svtools/embedhlp.hxx>
+#include <svtools/strings.hrc>
+#include <svtools/svtresid.hxx>
+#include <svx/postattr.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zformat.hxx>
+#include <memory>
+
+#include "../../core/crsr/callnk.hxx"
+#include <frmtool.hxx>
+#include <viewopt.hxx>
+
+#include <IDocumentUndoRedo.hxx>
+#include <UndoInsert.hxx>
+#include <UndoCore.hxx>
+#include <formatlinebreak.hxx>
+#include <formatcontentcontrol.hxx>
+#include <textcontentcontrol.hxx>
+
+using namespace sw::mark;
+using namespace com::sun::star;
+namespace {
+
+void collectUIInformation(const OUString& rAction, const OUString& aParameters)
+{
+ EventDescription aDescription;
+ aDescription.aAction = rAction;
+ aDescription.aParameters = {{"parameters", aParameters}};
+ aDescription.aID = "writer_edit";
+ aDescription.aKeyWord = "SwEditWinUIObject";
+ aDescription.aParent = "MainWindow";
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+sal_uInt32 MakeAllOutlineContentTemporarilyVisible::nLock = 0;
+
+static bool lcl_IsAllowed(const SwWrtShell* rSh)
+{
+ if (rSh->GetViewOptions()->IsShowOutlineContentVisibilityButton() && rSh->IsEndPara())
+ {
+ SwTextNode* pTextNode = rSh->GetCursor()->GetPointNode().GetTextNode();
+ if (pTextNode && pTextNode->IsOutline())
+ {
+ // disallow if this is an outline node having folded content
+ bool bVisible = true;
+ pTextNode->GetAttrOutlineContentVisible(bVisible);
+ if (!bVisible)
+ return false;
+ }
+ }
+ return true;
+}
+
+#define BITFLD_INI_LIST \
+ m_bClearMark = \
+ m_bIns = true;\
+ m_bAddMode = \
+ m_bBlockMode = \
+ m_bExtMode = \
+ m_bInSelect = \
+ m_bLayoutMode = \
+ m_bSelWrd = \
+ m_bSelLn = \
+ m_bRetainSelection = false; \
+ m_bIsInClickToEdit = false;
+
+static SvxAutoCorrect* lcl_IsAutoCorr()
+{
+ SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect();
+ if( pACorr && !pACorr->IsAutoCorrFlag( ACFlags::CapitalStartSentence | ACFlags::CapitalStartWord |
+ ACFlags::AddNonBrkSpace | ACFlags::ChgOrdinalNumber | ACFlags::TransliterateRTL |
+ ACFlags::ChgToEnEmDash | ACFlags::SetINetAttr | ACFlags::Autocorrect |
+ ACFlags::SetDOIAttr ))
+ pACorr = nullptr;
+ return pACorr;
+}
+
+void SwWrtShell::NoEdit(bool bHideCursor)
+{
+ if(bHideCursor)
+ HideCursor();
+}
+
+void SwWrtShell::Edit()
+{
+ if (CanInsert())
+ {
+ ShowCursor();
+ }
+}
+
+bool SwWrtShell::IsEndWrd()
+{
+ SwMvContext aMvContext(this);
+ if(IsEndPara() && !IsSttPara())
+ return true;
+
+ return IsEndWord();
+}
+
+// Insert string
+void SwWrtShell::InsertByWord( const OUString & rStr)
+{
+ if( rStr.isEmpty() )
+ return;
+
+ bool bDelim = GetAppCharClass().isLetterNumeric( rStr, 0 );
+ sal_Int32 nPos = 0, nStt = 0;
+ for( ; nPos < rStr.getLength(); nPos++ )
+ {
+ bool bTmpDelim = GetAppCharClass().isLetterNumeric( rStr, nPos );
+ if( bTmpDelim != bDelim )
+ {
+ Insert( rStr.copy( nStt, nPos - nStt ));
+ nStt = nPos;
+ }
+ }
+ if( nStt != nPos )
+ Insert( rStr.copy( nStt, nPos - nStt ));
+}
+
+void SwWrtShell::Insert( const OUString &rStr )
+{
+ ResetCursorStack();
+ if( !CanInsert() )
+ return;
+
+ bool bStarted = false;
+ bool bHasSel = HasSelection(),
+ bCallIns = m_bIns /*|| bHasSel*/;
+ bool bDeleted = false;
+
+ if( bHasSel || ( !m_bIns && IsInHiddenRange(/*bSelect=*/true) ) )
+ {
+ // Only here parenthesizing, because the normal
+ // insert is already in parentheses at Editshell.
+ StartAllAction();
+
+ SwRewriter aRewriter;
+
+ aRewriter.AddRule(UndoArg1, GetCursorDescr());
+ aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
+ {
+ OUString aTmpStr = SwResId(STR_START_QUOTE) +
+ rStr + SwResId(STR_END_QUOTE);
+
+ aRewriter.AddRule(UndoArg3, aTmpStr);
+ }
+
+ StartUndo(SwUndoId::REPLACE, &aRewriter);
+ bStarted = true;
+ Push();
+ // let's interpret a selection within the same node as "replace"
+ bDeleted = DelRight(GetCursor()->GetPoint()->GetNode() == GetCursor()->GetMark()->GetNode());
+ Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore selection (if tracking changes)
+ NormalizePam(false); // tdf#127635 put point at the end of deletion
+ ClearMark();
+ }
+
+ bCallIns ?
+ SwEditShell::Insert2( rStr, bDeleted ) : SwEditShell::Overwrite( rStr );
+
+ // Check whether node is content control
+ SwTextContentControl* pTextContentControl = CursorInsideContentControl();
+ if (pTextContentControl)
+ {
+ std::shared_ptr<SwContentControl> pContentControl =
+ pTextContentControl->GetContentControl().GetContentControl();
+ if (pContentControl)
+ {
+ // Set showingPlcHdr to false as node has been edited
+ pContentControl->SetShowingPlaceHolder(false);
+ }
+ }
+
+ if( bStarted )
+ {
+ EndUndo();
+ EndAllAction();
+ }
+}
+
+// Maximum height limit not possible, because the maximum height
+// of the current frame can not be obtained.
+
+void SwWrtShell::InsertGraphic( const OUString &rPath, const OUString &rFilter,
+ const Graphic &rGrf, SwFlyFrameAttrMgr *pFrameMgr,
+ RndStdIds nAnchorType )
+{
+ ResetCursorStack();
+ if ( !CanInsert() )
+ return;
+
+ StartAllAction();
+
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC));
+
+ StartUndo(SwUndoId::INSERT, &aRewriter);
+
+ if ( HasSelection() )
+ DelRight();
+ // Inserted graphics in its own paragraph,
+ // if at the end of a non-empty paragraph.
+ //For i120928,avoid to split node
+
+ EnterSelFrameMode();
+
+ bool bSetGrfSize = true;
+ bool bOwnMgr = false;
+
+ if ( !pFrameMgr )
+ {
+ bOwnMgr = true;
+ pFrameMgr = new SwFlyFrameAttrMgr( true, this, Frmmgr_Type::GRF, nullptr );
+
+ // CAUTION
+ // GetAttrSet makes an adjustment
+ // While pasting is a SwFrameSize present
+ // because of the DEF-Framesize
+ // These must be removed explicitly for the optimal size.
+ pFrameMgr->DelAttr(RES_FRM_SIZE);
+
+ if (nAnchorType != RndStdIds::FLY_AT_PARA)
+ // Something other than at-para was requested.
+ pFrameMgr->SetAnchor(nAnchorType);
+ }
+ else
+ {
+ Size aSz( pFrameMgr->GetSize() );
+ if ( !aSz.Width() || !aSz.Height() )
+ {
+ aSz.setWidth(o3tl::toTwips(1, o3tl::Length::cm));
+ aSz.setHeight(o3tl::toTwips(1, o3tl::Length::cm));
+ pFrameMgr->SetSize( aSz );
+ }
+ else if ( aSz.Width() != DFLT_WIDTH && aSz.Height() != DFLT_HEIGHT )
+ bSetGrfSize = false;
+
+ pFrameMgr->SetHeightSizeType(SwFrameSize::Fixed);
+ }
+
+ // during change tracking, insert the image anchored as character
+ // (to create an SwRangeRedline on its anchor point)
+ if ( IsRedlineOn() && nAnchorType != RndStdIds::FLY_AS_CHAR )
+ pFrameMgr->SetAnchor( RndStdIds::FLY_AS_CHAR );
+
+ // Insert the graphic
+ SwFEShell::Insert(rPath, rFilter, &rGrf, &pFrameMgr->GetAttrSet());
+ if ( bOwnMgr )
+ pFrameMgr->UpdateAttrMgr();
+
+ if( bSetGrfSize )
+ {
+ Size aSizePixel = rGrf.GetSizePixel();
+ Size aBound = GetGraphicDefaultSize();
+
+ sal_Int32 nPreferredDPI = mxDoc->getIDocumentSettingAccess().getImagePreferredDPI();
+ Size aGrfSize;
+
+ if (nPreferredDPI > 0)
+ {
+ auto nWidth = o3tl::toTwips(aSizePixel.Width() / double(nPreferredDPI), o3tl::Length::in);
+ auto nHeight = o3tl::toTwips(aSizePixel.Height() / double(nPreferredDPI), o3tl::Length::in);
+ aGrfSize = Size(nWidth, nHeight);
+ }
+ else
+ {
+ GetGrfSize(aGrfSize);
+ }
+
+ // Add the margin attributes to GrfSize,
+ // because these counts at the margin additionally
+ aGrfSize.AdjustWidth(pFrameMgr->CalcWidthBorder() );
+ aGrfSize.AdjustHeight(pFrameMgr->CalcHeightBorder() );
+
+ const BigInt aTempWidth( aGrfSize.Width() );
+ const BigInt aTempHeight( aGrfSize.Height());
+
+ // Fit width if necessary, scale down the height proportional thereafter.
+ if( aGrfSize.Width() > aBound.Width() )
+ {
+ aGrfSize.setWidth( aBound.Width() );
+ aGrfSize.setHeight( BigInt(aBound.Width()) * aTempHeight / aTempWidth );
+ }
+ // Fit height if necessary, scale down the width proportional thereafter.
+ if( aGrfSize.Height() > aBound.Height() )
+ {
+ aGrfSize.setHeight( aBound.Height() );
+ aGrfSize.setWidth( BigInt(aBound.Height()) * aTempWidth / aTempHeight );
+ }
+ pFrameMgr->SetSize( aGrfSize );
+ pFrameMgr->UpdateFlyFrame();
+ }
+ if ( bOwnMgr )
+ delete pFrameMgr;
+
+ EndUndo();
+ EndAllAction();
+}
+
+// Insert an OLE-Object into the CORE.
+// if no object is transferred, then one will be created.
+
+void SwWrtShell::InsertObject( const svt::EmbeddedObjectRef& xRef, SvGlobalName const *pName,
+ sal_uInt16 nSlotId )
+{
+ ResetCursorStack();
+ if( !CanInsert() )
+ return;
+
+ if( !xRef.is() )
+ {
+ // temporary storage
+ svt::EmbeddedObjectRef xObj;
+ uno::Reference < embed::XStorage > xStor = comphelper::OStorageHelper::GetTemporaryStorage();
+ bool bDoVerb = true;
+ if ( pName )
+ {
+ comphelper::EmbeddedObjectContainer aCnt( xStor );
+ OUString aName;
+ // TODO/LATER: get aspect?
+ xObj.Assign( aCnt.CreateEmbeddedObject( pName->GetByteSequence(), aName ), embed::Aspects::MSOLE_CONTENT );
+ }
+ else
+ {
+ SvObjectServerList aServerList;
+ switch (nSlotId)
+ {
+ case SID_INSERT_OBJECT:
+ {
+ if (officecfg::Office::Common::Security::Scripting::DisableActiveContent::get())
+ {
+ std::unique_ptr<weld::MessageDialog> xError(
+ Application::CreateMessageDialog(
+ nullptr, VclMessageType::Warning, VclButtonsType::Ok,
+ SvtResId(STR_WARNING_ACTIVE_CONTENT_DISABLED)));
+ xError->run();
+ break;
+ }
+ aServerList.FillInsertObjects();
+ aServerList.Remove( SwDocShell::Factory().GetClassId() );
+ [[fallthrough]];
+ }
+
+ // TODO/LATER: recording! Convert properties to items
+ case SID_INSERT_FLOATINGFRAME:
+ {
+ SfxSlotPool* pSlotPool = SW_MOD()->GetSlotPool();
+ const SfxSlot* pSlot = pSlotPool->GetSlot(nSlotId);
+ OUString aCmd = pSlot->GetCommand();
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractInsertObjectDialog> pDlg(pFact->CreateInsertObjectDialog(GetFrameWeld(mxDoc->GetDocShell()),
+ aCmd, xStor, &aServerList));
+ if (pDlg)
+ {
+ pDlg->Execute();
+ bDoVerb = pDlg->IsCreateNew();
+ OUString aIconMediaType;
+ uno::Reference< io::XInputStream > xIconMetaFile = pDlg->GetIconIfIconified( &aIconMediaType );
+ xObj.Assign( pDlg->GetObject(),
+ xIconMetaFile.is() ? embed::Aspects::MSOLE_ICON : embed::Aspects::MSOLE_CONTENT );
+ if ( xIconMetaFile.is() )
+ xObj.SetGraphicStream( xIconMetaFile, aIconMediaType );
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ if ( xObj.is() )
+ {
+ if( InsertOleObject( xObj ) && bDoVerb )
+ {
+ SfxInPlaceClient* pClient = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin() );
+ if ( !pClient )
+ {
+ pClient = new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
+ SetCheckForOLEInCaption( true );
+ }
+
+ if ( xObj.GetViewAspect() == embed::Aspects::MSOLE_ICON )
+ {
+ SwRect aArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() );
+ aArea.Pos() += GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, xObj.GetObject() ).Pos();
+ MapMode aMapMode( MapUnit::MapTwip );
+ Size aSize = xObj.GetSize( &aMapMode );
+ aArea.Width( aSize.Width() );
+ aArea.Height( aSize.Height() );
+ RequestObjectResize( aArea, xObj.GetObject() );
+ }
+ else
+ CalcAndSetScale( xObj );
+
+ //#50270# We don't need to handle error, this is handled by the
+ //DoVerb in the SfxViewShell
+ pClient->DoVerb(embed::EmbedVerbs::MS_OLEVERB_SHOW);
+
+ // TODO/LATER: set document name - should be done in Client
+ }
+ }
+ }
+ else
+ {
+ if( HasSelection() )
+ DelRight();
+ InsertOleObject( xRef );
+ }
+}
+
+// Insert object into the Core.
+// From ClipBoard or Insert
+
+bool SwWrtShell::InsertOleObject( const svt::EmbeddedObjectRef& xRef, SwFlyFrameFormat **pFlyFrameFormat )
+{
+ //tdf#125100 Ensure that ole object is initially shown as pictogram
+ comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = mxDoc->GetDocShell()->getEmbeddedObjectContainer();
+ bool bSaveUserAllowsLinkUpdate = rEmbeddedObjectContainer.getUserAllowsLinkUpdate();
+ rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true);
+
+ ResetCursorStack();
+ StartAllAction();
+
+ StartUndo(SwUndoId::INSERT);
+
+ //Some differences between StarMath and any other objects:
+ //1. Selections should be deleted. For StarMath the Text should be
+ // passed to the Object
+ //2. If the cursor is at the end of a non empty paragraph a paragraph
+ // break should be inserted. StarMath objects are character bound and
+ // no break should be inserted.
+ //3. If an selection is passed to a StarMath object, this object should
+ // not be activated. false should be returned then.
+ bool bStarMath = true;
+ bool bActivate = true;
+
+ // set parent to get correct VisArea(in case of object needing parent printer)
+ uno::Reference < container::XChild > xChild( xRef.GetObject(), uno::UNO_QUERY );
+ if ( xChild.is() )
+ xChild->setParent( mxDoc->GetDocShell()->GetModel() );
+
+ SvGlobalName aCLSID( xRef->getClassID() );
+ bStarMath = ( SotExchange::IsMath( aCLSID ) != 0 );
+ if( IsSelection() )
+ {
+ if( bStarMath )
+ {
+ OUString aMathData;
+ GetSelectedText( aMathData, ParaBreakType::ToOnlyCR );
+
+ if( !aMathData.isEmpty() && svt::EmbeddedObjectRef::TryRunningState( xRef.GetObject() ) )
+ {
+ uno::Reference < beans::XPropertySet > xSet( xRef->getComponent(), uno::UNO_QUERY );
+ if ( xSet.is() )
+ {
+ try
+ {
+ xSet->setPropertyValue("Formula", uno::Any( aMathData ) );
+ bActivate = false;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ DelRight();
+ }
+
+ if ( !bStarMath )
+ SwFEShell::SplitNode( false, false );
+
+ EnterSelFrameMode();
+
+ const SvGlobalName* pName = nullptr;
+ SvGlobalName aObjClsId;
+ if (xRef.is())
+ {
+ aObjClsId = SvGlobalName(xRef.GetObject()->getClassID());
+ pName = &aObjClsId;
+ }
+ SwFlyFrameAttrMgr aFrameMgr( true, this, Frmmgr_Type::OLE, pName );
+ aFrameMgr.SetHeightSizeType(SwFrameSize::Fixed);
+
+ SwRect aBound;
+ CalcBoundRect( aBound, aFrameMgr.GetAnchor() );
+
+ //The Size should be suggested by the OLE server
+ MapMode aMapMode( MapUnit::MapTwip );
+ Size aSz = xRef.GetSize( &aMapMode );
+
+ //Object size can be limited
+ if ( aSz.Width() > aBound.Width() )
+ {
+ //Always limit proportional.
+ aSz.setHeight( aSz.Height() * aBound.Width() / aSz.Width() );
+ aSz.setWidth( aBound.Width() );
+ }
+ aFrameMgr.SetSize( aSz );
+ SwFlyFrameFormat *pFormat = SwFEShell::InsertObject( xRef, &aFrameMgr.GetAttrSet() );
+
+ // --> #i972#
+ if ( bStarMath && mxDoc->getIDocumentSettingAccess().get( DocumentSettingId::MATH_BASELINE_ALIGNMENT ) )
+ AlignFormulaToBaseline( xRef.GetObject() );
+
+ if (pFlyFrameFormat)
+ *pFlyFrameFormat = pFormat;
+
+ if ( SotExchange::IsChart( aCLSID ) )
+ {
+ uno::Reference< embed::XEmbeddedObject > xEmbeddedObj = xRef.GetObject();
+ if ( xEmbeddedObj.is() )
+ {
+ bool bDisableDataTableDialog = false;
+ svt::EmbeddedObjectRef::TryRunningState( xEmbeddedObj );
+ uno::Reference< beans::XPropertySet > xProps( xEmbeddedObj->getComponent(), uno::UNO_QUERY );
+ if ( xProps.is() &&
+ ( xProps->getPropertyValue("DisableDataTableDialog") >>= bDisableDataTableDialog ) &&
+ bDisableDataTableDialog )
+ {
+ xProps->setPropertyValue("DisableDataTableDialog",
+ uno::Any( false ) );
+ xProps->setPropertyValue("DisableComplexChartTypes",
+ uno::Any( false ) );
+ uno::Reference< util::XModifiable > xModifiable( xProps, uno::UNO_QUERY );
+ if ( xModifiable.is() )
+ {
+ xModifiable->setModified( true );
+ }
+ }
+ }
+ }
+
+ EndAllAction();
+ GetView().AutoCaption(OLE_CAP, &aCLSID);
+
+ SwRewriter aRewriter;
+
+ if ( bStarMath )
+ aRewriter.AddRule(UndoArg1, SwResId(STR_MATH_FORMULA));
+ else if ( SotExchange::IsChart( aCLSID ) )
+ aRewriter.AddRule(UndoArg1, SwResId(STR_CHART));
+ else
+ aRewriter.AddRule(UndoArg1, SwResId(STR_OLE));
+
+ EndUndo(SwUndoId::INSERT, &aRewriter);
+
+ rEmbeddedObjectContainer.setUserAllowsLinkUpdate(bSaveUserAllowsLinkUpdate);
+
+ return bActivate;
+}
+
+// The current selected OLE object will be loaded with the
+// verb into the server.
+void SwWrtShell::LaunchOLEObj(sal_Int32 nVerb)
+{
+ if ( GetCntType() != CNT_OLE ||
+ GetView().GetViewFrame().GetFrame().IsInPlace() )
+ return;
+
+ svt::EmbeddedObjectRef& xRef = GetOLEObject();
+ OSL_ENSURE( xRef.is(), "OLE not found" );
+
+ // LOK: we don't want to handle any other embedded objects than
+ // charts, there are too many problems with eg. embedded spreadsheets
+ // (like it creates a separate view for the calc sheet)
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ const auto classId = xRef->getClassID();
+ if (!SotExchange::IsChart(classId) && !SotExchange::IsMath(classId))
+ return;
+ }
+
+ SfxInPlaceClient* pCli = GetView().FindIPClient( xRef.GetObject(), &GetView().GetEditWin() );
+ if ( !pCli )
+ pCli = new SwOleClient( &GetView(), &GetView().GetEditWin(), xRef );
+
+ uno::Reference<lang::XInitialization> xOLEInit(xRef.GetObject(), uno::UNO_QUERY);
+ if (xOLEInit.is())
+ {
+ uno::Sequence<beans::PropertyValue> aArguments
+ = { comphelper::makePropertyValue("ReadOnly", pCli->IsProtected()) };
+ xOLEInit->initialize({ uno::Any(aArguments) });
+ }
+
+ static_cast<SwOleClient*>(pCli)->SetInDoVerb( true );
+
+ CalcAndSetScale( xRef );
+ pCli->DoVerb( nVerb );
+
+ static_cast<SwOleClient*>(pCli)->SetInDoVerb( false );
+ CalcAndSetScale( xRef );
+}
+
+void SwWrtShell::MoveObjectIfActive( svt::EmbeddedObjectRef& xObj, const Point& rOffset )
+{
+ try
+ {
+ sal_Int32 nState = xObj->getCurrentState();
+ if ( nState == css::embed::EmbedStates::INPLACE_ACTIVE
+ || nState == css::embed::EmbedStates::UI_ACTIVE )
+ {
+ SfxInPlaceClient* pCli =
+ GetView().FindIPClient( xObj.GetObject(), &(GetView().GetEditWin()) );
+ if ( pCli )
+ {
+ tools::Rectangle aArea = pCli->GetObjArea();
+ aArea += rOffset;
+ pCli->SetObjArea( aArea );
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+void SwWrtShell::CalcAndSetScale( svt::EmbeddedObjectRef& xObj,
+ const SwRect *pFlyPrtRect,
+ const SwRect *pFlyFrameRect,
+ const bool bNoTextFramePrtAreaChanged )
+{
+ // Setting the scale of the client. This arises from the difference
+ // between the VisArea of the object and the ObjArea.
+ OSL_ENSURE( xObj.is(), "ObjectRef not valid" );
+
+ sal_Int64 nAspect = xObj.GetViewAspect();
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ return; // the replacement image is completely controlled by container in this case
+
+ sal_Int64 nMisc = 0;
+ bool bLinkingChart = false;
+
+ try
+ {
+ nMisc = xObj->getStatus( nAspect );
+
+ // This can surely only be a non-active object, if desired they
+ // get the new size set as VisArea (StarChart).
+ if( embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE & nMisc )
+ {
+ // TODO/MBA: testing
+ SwRect aRect( pFlyPrtRect ? *pFlyPrtRect
+ : GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ));
+ if( !aRect.IsEmpty() )
+ {
+ // TODO/LEAN: getMapUnit can switch object to running state
+ // xObj.TryRunningState();
+
+ MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
+
+ // TODO/LATER: needs complete VisArea?!
+ Size aSize( OutputDevice::LogicToLogic(aRect.SVRect(), MapMode(MapUnit::MapTwip), MapMode(aUnit)).GetSize() );
+ awt::Size aSz;
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+
+ // Action 'setVisualAreaSize' doesn't have to turn on the
+ // modified state of the document, either.
+ bool bModified = false;
+ uno::Reference<util::XModifiable> xModifiable(xObj->getComponent(), uno::UNO_QUERY);
+ if (xModifiable.is())
+ bModified = xModifiable->isModified();
+ xObj->setVisualAreaSize( nAspect, aSz );
+ xModifiable.set(xObj->getComponent(), uno::UNO_QUERY);
+ if (xModifiable.is() && xModifiable->isModified() && !bModified)
+ xModifiable->setModified(bModified);
+
+ // #i48419# - action 'UpdateReplacement' doesn't
+ // have to change the modified state of the document.
+ // This is only a workaround for the defect, that this action
+ // modifies a document after load, because unnecessarily the
+ // replacement graphic is updated, in spite of the fact that
+ // nothing has been changed.
+ // If the replacement graphic changes by this action, the document
+ // will be already modified via other mechanisms.
+ {
+ bool bResetEnableSetModified(false);
+ if ( GetDoc()->GetDocShell()->IsEnableSetModified() )
+ {
+ GetDoc()->GetDocShell()->EnableSetModified( false );
+ bResetEnableSetModified = true;
+ }
+
+ //#i79576# don't destroy chart replacement images on load
+ //#i79578# don't request a new replacement image for charts to often
+ //a chart sends a modified call to the framework if it was changed
+ //thus the replacement update is already handled elsewhere
+ if ( !SotExchange::IsChart( xObj->getClassID() ) )
+ xObj.UpdateReplacement();
+
+ if ( bResetEnableSetModified )
+ {
+ GetDoc()->GetDocShell()->EnableSetModified();
+ }
+ }
+ }
+
+ // TODO/LATER: this is only a workaround,
+ uno::Reference< chart2::XChartDocument > xChartDocument( xObj->getComponent(), uno::UNO_QUERY );
+ bLinkingChart = ( xChartDocument.is() && !xChartDocument->hasInternalDataProvider() );
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ // TODO/LATER: handle the error
+ return;
+ }
+
+ SfxInPlaceClient* pCli = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin() );
+ if ( !pCli )
+ {
+ if ( (embed::EmbedMisc::EMBED_ACTIVATEIMMEDIATELY & nMisc)
+ || bLinkingChart
+ // --> OD #i117189# - refine condition for non-resizable objects
+ // non-resizable objects need to be set the size back by this method
+ || ( bNoTextFramePrtAreaChanged && nMisc & embed::EmbedMisc::EMBED_NEVERRESIZE ) )
+ {
+ pCli = new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
+ }
+ else
+ return;
+ }
+
+ // TODO/LEAN: getMapUnit can switch object to running state
+ // xObj.TryRunningState();
+
+ awt::Size aSize;
+ try
+ {
+ aSize = xObj->getVisualAreaSize( nAspect );
+ }
+ catch (const embed::NoVisualAreaSizeException&)
+ {
+ OSL_FAIL("Can't get visual area size!" );
+ // the scaling will not be done
+ }
+ catch (const uno::Exception&)
+ {
+ // TODO/LATER: handle the error
+ OSL_FAIL("Can't get visual area size!" );
+ return;
+ }
+
+ Size _aVisArea( aSize.Width, aSize.Height );
+
+ Fraction aScaleWidth( 1, 1 );
+ Fraction aScaleHeight( 1, 1 );
+
+ bool bUseObjectSize = false;
+
+ // As long as there comes no reasonable size from the object,
+ // nothing can be scaled.
+ if( _aVisArea.Width() && _aVisArea.Height() )
+ {
+ const MapMode aTmp( MapUnit::MapTwip );
+ MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
+ _aVisArea = OutputDevice::LogicToLogic(_aVisArea, MapMode(aUnit), aTmp);
+ Size aObjArea;
+ if ( pFlyPrtRect )
+ aObjArea = pFlyPrtRect->SSize();
+ else
+ aObjArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ).SSize();
+
+ // differ the aObjArea and _aVisArea by 1 Pixel then set new VisArea
+ tools::Long nX, nY;
+ SwSelPaintRects::Get1PixelInLogic( *this, &nX, &nY );
+ if( !( _aVisArea.Width() - nX <= aObjArea.Width() &&
+ _aVisArea.Width() + nX >= aObjArea.Width() &&
+ _aVisArea.Height()- nY <= aObjArea.Height()&&
+ _aVisArea.Height()+ nY >= aObjArea.Height() ))
+ {
+ if ( nMisc & embed::EmbedMisc::EMBED_NEVERRESIZE )
+ {
+ // the object must not be scaled,
+ // the size stored in object must be used for restoring
+ bUseObjectSize = true;
+ }
+ else
+ {
+ aScaleWidth = Fraction( aObjArea.Width(), _aVisArea.Width() );
+ aScaleHeight = Fraction( aObjArea.Height(), _aVisArea.Height());
+ }
+ }
+ }
+
+ // Now is the favorable time to set the ObjArea.
+ // The Scaling must be considered.
+ SwRect aArea;
+ if ( pFlyPrtRect )
+ {
+ aArea = *pFlyPrtRect;
+ aArea += pFlyFrameRect->Pos();
+ }
+ else
+ {
+ aArea = GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() );
+ aArea.Pos() += GetAnyCurRect( CurRectType::FlyEmbedded, nullptr, xObj.GetObject() ).Pos();
+ }
+
+ if ( bUseObjectSize )
+ {
+ // --> this moves non-resizable object so that when adding borders the baseline remains the same
+ const SwFlyFrameFormat *pFlyFrameFormat = dynamic_cast< const SwFlyFrameFormat * >( GetFlyFrameFormat() );
+ OSL_ENSURE( pFlyFrameFormat, "Could not find fly frame." );
+ if ( pFlyFrameFormat )
+ {
+ const Point &rPoint = pFlyFrameFormat->GetLastFlyFramePrtRectPos();
+ SwRect aRect( pFlyPrtRect ? *pFlyPrtRect
+ : GetAnyCurRect( CurRectType::FlyEmbeddedPrt, nullptr, xObj.GetObject() ));
+ aArea += rPoint - aRect.Pos(); // adjust area by diff of printing area position in order to keep baseline alignment correct.
+ }
+ aArea.Width ( _aVisArea.Width() );
+ aArea.Height( _aVisArea.Height() );
+ RequestObjectResize( aArea, xObj.GetObject() );
+ }
+ else
+ {
+ double nWidth(pCli->GetScaleWidth());
+ double nHeight(pCli->GetScaleHeight());
+ if (nWidth && nHeight)
+ {
+ aArea.Width ( aArea.Width() / nWidth );
+ aArea.Height( aArea.Height() / nHeight );
+ }
+ }
+
+ pCli->SetObjAreaAndScale( aArea.SVRect(), aScaleWidth, aScaleHeight );
+}
+
+void SwWrtShell::ConnectObj( svt::EmbeddedObjectRef& xObj, const SwRect &rPrt,
+ const SwRect &rFrame )
+{
+ SfxInPlaceClient* pCli = GetView().FindIPClient( xObj.GetObject(), &GetView().GetEditWin());
+ if ( !pCli )
+ new SwOleClient( &GetView(), &GetView().GetEditWin(), xObj );
+ CalcAndSetScale( xObj, &rPrt, &rFrame );
+}
+
+// Insert hard page break;
+// Selections will be overwritten
+void SwWrtShell::InsertPageBreak(const OUString *pPageDesc, const ::std::optional<sal_uInt16>& oPgNum )
+{
+ if (!lcl_IsAllowed(this))
+ return;
+
+ ResetCursorStack();
+ if( CanInsert() )
+ {
+ SwActContext aActContext(this);
+ StartUndo(SwUndoId::UI_INSERT_PAGE_BREAK);
+
+ if ( !IsCursorInTable() )
+ {
+ if(HasSelection())
+ DelRight();
+ SwFEShell::SplitNode();
+ // delete the numbered attribute of the last line if the last line is empty
+ GetDoc()->ClearLineNumAttrs( *GetCursor()->GetPoint() );
+ }
+
+ const SwPageDesc *pDesc = pPageDesc
+ ? FindPageDescByName( *pPageDesc, true ) : nullptr;
+ if( pDesc )
+ {
+ SwFormatPageDesc aDesc( pDesc );
+ aDesc.SetNumOffset( oPgNum );
+ SetAttrItem( aDesc );
+ }
+ else
+ SetAttrItem( SvxFormatBreakItem(SvxBreak::PageBefore, RES_BREAK) );
+ EndUndo(SwUndoId::UI_INSERT_PAGE_BREAK);
+ }
+ collectUIInformation("BREAK_PAGE", "parameter");
+}
+
+// Insert hard page break;
+// Selections will be overwritten
+
+void SwWrtShell::InsertLineBreak(std::optional<SwLineBreakClear> oClear)
+{
+ if (!lcl_IsAllowed(this))
+ return;
+
+ ResetCursorStack();
+ if( CanInsert() )
+ {
+ if(HasSelection())
+ DelRight();
+
+ const sal_Unicode cIns = 0x0A;
+ SwLineBreakClear eClear = SwLineBreakClear::NONE;
+ if (oClear.has_value())
+ {
+ eClear = *oClear;
+ }
+ SvxAutoCorrect* pACorr = lcl_IsAutoCorr();
+ if (pACorr && eClear == SwLineBreakClear::NONE)
+ AutoCorrect( *pACorr, cIns );
+ else
+ {
+ if (eClear == SwLineBreakClear::NONE)
+ {
+ SwWrtShell::Insert(OUString(cIns));
+ }
+ else
+ {
+ SwFormatLineBreak aLineBreak(eClear);
+ SetAttrItem(aLineBreak);
+ }
+ }
+ }
+}
+
+// Insert hard column break;
+// Selections will be overwritten
+
+void SwWrtShell::InsertColumnBreak()
+{
+ if (!lcl_IsAllowed(this))
+ return;
+
+ SwActContext aActContext(this);
+ ResetCursorStack();
+ if( !CanInsert() )
+ return;
+
+ StartUndo(SwUndoId::UI_INSERT_COLUMN_BREAK);
+
+ if ( !IsCursorInTable() )
+ {
+ if(HasSelection())
+ DelRight();
+ SwFEShell::SplitNode( false, false );
+ }
+ SetAttrItem(SvxFormatBreakItem(SvxBreak::ColumnBefore, RES_BREAK));
+
+ EndUndo(SwUndoId::UI_INSERT_COLUMN_BREAK);
+}
+
+void SwWrtShell::InsertContentControl(SwContentControlType eType)
+{
+ if (!lcl_IsAllowed(this))
+ {
+ return;
+ }
+
+ ResetCursorStack();
+ if (!CanInsert())
+ {
+ return;
+ }
+
+ auto pContentControl = std::make_shared<SwContentControl>(nullptr);
+ OUString aPlaceholder;
+ switch (eType)
+ {
+ case SwContentControlType::RICH_TEXT:
+ case SwContentControlType::PLAIN_TEXT:
+ {
+ pContentControl->SetShowingPlaceHolder(true);
+ if (eType == SwContentControlType::PLAIN_TEXT)
+ {
+ pContentControl->SetPlainText(true);
+ }
+ if (!HasSelection())
+ {
+ aPlaceholder = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER);
+ }
+ break;
+ }
+ case SwContentControlType::CHECKBOX:
+ {
+ pContentControl->SetCheckbox(true);
+ // Ballot Box with X
+ pContentControl->SetCheckedState(u"\u2612"_ustr);
+ // Ballot Box
+ pContentControl->SetUncheckedState(u"\u2610"_ustr);
+ aPlaceholder = u"\u2610"_ustr;
+ break;
+ }
+ case SwContentControlType::COMBO_BOX:
+ case SwContentControlType::DROP_DOWN_LIST:
+ {
+ if (eType == SwContentControlType::COMBO_BOX)
+ {
+ pContentControl->SetComboBox(true);
+ }
+ else if (eType == SwContentControlType::DROP_DOWN_LIST)
+ {
+ pContentControl->SetDropDown(true);
+ }
+
+ pContentControl->SetShowingPlaceHolder(true);
+ if (!HasSelection())
+ {
+ aPlaceholder = SwResId(STR_DROPDOWN_CONTENT_CONTROL_PLACEHOLDER);
+ }
+ SwContentControlListItem aListItem;
+ aListItem.m_aValue = aPlaceholder;
+ pContentControl->SetListItems({ aListItem });
+ break;
+ }
+ case SwContentControlType::PICTURE:
+ {
+ // Set up the picture content control.
+ pContentControl->SetShowingPlaceHolder(true);
+ pContentControl->SetPicture(true);
+
+ // Create the placeholder bitmap.
+ BitmapEx aBitmap(Size(1, 1), vcl::PixelFormat::N24_BPP);
+ Color aColor = SvtOptionsDrawinglayer::getHilightColor();
+ aColor.IncreaseLuminance(255 * 0.75);
+ aBitmap.Erase(aColor);
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1, SwResId(STR_GRAPHIC_DEFNAME));
+ StartUndo(SwUndoId::INSERT, &aRewriter);
+ LockPaint(LockPaintReason::InsertGraphic);
+ StartAction();
+ InsertGraphic(OUString(), OUString(), aBitmap, nullptr, RndStdIds::FLY_AS_CHAR);
+
+ // Set properties on the bitmap.
+ SfxItemSetFixed<RES_FRM_SIZE, RES_FRM_SIZE> aSet(GetDoc()->GetAttrPool());
+ GetFlyFrameAttr(aSet);
+ SwFormatFrameSize aSize(SwFrameSize::Fixed, 3000, 3000);
+ aSet.Put(aSize);
+ SetFlyFrameAttr(aSet);
+ SwFrameFormat* pFrameFormat = GetFlyFrameFormat();
+ EndAction();
+ UnlockPaint();
+ EndUndo();
+
+ // Go after the anchor position.
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ {
+ SwCursor* pCursor = getShellCursor(true);
+ pCursor->DeleteMark();
+ const SwFormatAnchor& rFormatAnchor = pFrameFormat->GetAnchor();
+ pCursor->GetPoint()->Assign( *rFormatAnchor.GetAnchorContentNode(), rFormatAnchor.GetAnchorContentOffset() + 1);
+ }
+
+ // Select before the anchor position.
+ Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
+ break;
+ }
+ case SwContentControlType::DATE:
+ {
+ pContentControl->SetShowingPlaceHolder(true);
+ pContentControl->SetDate(true);
+ SvNumberFormatter* pFormatter = GetDoc()->GetNumberFormatter();
+ sal_uInt32 nStandardFormat = pFormatter->GetStandardFormat(SvNumFormatType::DATE);
+ const SvNumberformat* pFormat = pFormatter->GetEntry(nStandardFormat);
+ pContentControl->SetDateFormat(pFormat->GetFormatstring());
+ pContentControl->SetDateLanguage(LanguageTag(pFormat->GetLanguage()).getBcp47());
+ if (!HasSelection())
+ {
+ aPlaceholder = SwResId(STR_DATE_CONTENT_CONTROL_PLACEHOLDER);
+ }
+ break;
+ }
+ }
+ if (aPlaceholder.getLength())
+ {
+ Insert(aPlaceholder);
+ Left(SwCursorSkipMode::Chars, /*bSelect=*/true, aPlaceholder.getLength(),
+ /*bBasicCall=*/false);
+ }
+ SwFormatContentControl aContentControl(pContentControl, RES_TXTATR_CONTENTCONTROL);
+ SetAttrItem(aContentControl);
+}
+
+// Insert footnote
+// rStr - optional footnote mark
+
+void SwWrtShell::InsertFootnote(const OUString &rStr, bool bEndNote, bool bEdit )
+{
+ ResetCursorStack();
+ if( !CanInsert() )
+ return;
+
+ if(HasSelection())
+ {
+ //collapse cursor to the end
+ if(!IsCursorPtAtEnd())
+ SwapPam();
+ ClearMark();
+ }
+ SwPosition aPos = *GetCursor()->GetPoint();
+ SwFormatFootnote aFootNote( bEndNote );
+ if(!rStr.isEmpty())
+ aFootNote.SetNumStr( rStr );
+
+ SetAttrItem(aFootNote);
+
+ if( bEdit )
+ {
+ // For editing the footnote text.
+ Left(SwCursorSkipMode::Chars, false, 1, false );
+ GotoFootnoteText();
+ }
+ m_aNavigationMgr.addEntry(aPos);
+}
+
+// tdf#141634
+static bool lcl_FoldedOutlineNodeEndOfParaSplit(SwWrtShell *pThis)
+{
+ SwTextNode* pTextNode = pThis->GetCursor()->GetPointNode().GetTextNode();
+ if (pTextNode && pTextNode->IsOutline())
+ {
+ bool bVisible = true;
+ pTextNode->GetAttrOutlineContentVisible(bVisible);
+ if (!bVisible)
+ {
+ const SwNodes& rNodes = pThis->GetNodes();
+ const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
+ SwOutlineNodes::size_type nPos;
+ (void) rOutlineNodes.Seek_Entry(pTextNode, &nPos);
+
+ SwNode* pSttNd = rOutlineNodes[nPos];
+
+ // determine end node of folded outline content
+ SwNode* pEndNd = &rNodes.GetEndOfContent();
+ if (rOutlineNodes.size() > nPos + 1)
+ pEndNd = rOutlineNodes[nPos + 1];
+
+ if (pThis->GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
+ {
+ // get the next outline node after the folded outline content (iPos)
+ // it is the next outline node with the same level or less
+ int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
+ SwOutlineNodes::size_type iPos = nPos;
+ while (++iPos < rOutlineNodes.size() &&
+ rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() > nLevel);
+
+ // get the correct end node
+ // the outline node may be in frames, headers, footers special section of doc model
+ SwNode* pStartOfSectionNodeSttNd = pSttNd->StartOfSectionNode();
+ while (pStartOfSectionNodeSttNd->StartOfSectionNode()
+ != pStartOfSectionNodeSttNd->StartOfSectionNode()->StartOfSectionNode())
+ {
+ pStartOfSectionNodeSttNd = pStartOfSectionNodeSttNd->StartOfSectionNode();
+ }
+ pEndNd = pStartOfSectionNodeSttNd->EndOfSectionNode();
+
+ if (iPos < rOutlineNodes.size())
+ {
+ SwNode* pStartOfSectionNode = rOutlineNodes[iPos]->StartOfSectionNode();
+ while (pStartOfSectionNode->StartOfSectionNode()
+ != pStartOfSectionNode->StartOfSectionNode()->StartOfSectionNode())
+ {
+ pStartOfSectionNode = pStartOfSectionNode->StartOfSectionNode();
+ }
+ if (pStartOfSectionNodeSttNd == pStartOfSectionNode)
+ pEndNd = rOutlineNodes[iPos];
+ }
+ }
+
+ // table, text box, header, footer
+ if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
+ {
+ // insert before section end node
+ if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
+ {
+ SwNodeIndex aIdx(*pSttNd->EndOfSectionNode());
+ while (aIdx.GetNode().IsEndNode())
+ --aIdx;
+ ++aIdx;
+ pEndNd = &aIdx.GetNode();
+ }
+ }
+ // if pSttNd isn't in table but pEndNd is then insert after table
+ else if (pEndNd->GetTableBox())
+ {
+ pEndNd = pEndNd->FindTableNode();
+ SwNodeIndex aIdx(*pEndNd, -1);
+ // account for nested tables
+ while (aIdx.GetNode().GetTableBox())
+ {
+ pEndNd = aIdx.GetNode().FindTableNode();
+ aIdx.Assign(*pEndNd, -1);
+ }
+ aIdx.Assign(*pEndNd->EndOfSectionNode(), +1);
+ pEndNd = &aIdx.GetNode();
+ }
+ // end node determined
+
+ // now insert the new outline node
+ SwDoc* pDoc = pThis->GetDoc();
+
+ // insert at end of tablebox doesn't work correct without
+ MakeAllOutlineContentTemporarilyVisible a(pDoc);
+
+ SwTextNode* pNd = pDoc->GetNodes().MakeTextNode(*pEndNd, pTextNode->GetTextColl(), true);
+
+ (void) rOutlineNodes.Seek_Entry(pNd, &nPos);
+ pThis->GotoOutline(nPos);
+
+ if (pDoc->GetIDocumentUndoRedo().DoesUndo())
+ {
+ pDoc->GetIDocumentUndoRedo().ClearRedo();
+ pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoInsert>(*pNd));
+ pDoc->GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoFormatColl>
+ (SwPaM(*pNd), pNd->GetTextColl(), true, true));
+ }
+
+ pThis->SetModified();
+ return true;
+ }
+ }
+ return false;
+}
+
+// SplitNode; also, because
+// - of deleting selected content;
+// - of reset of the Cursorstack if necessary.
+
+void SwWrtShell::SplitNode( bool bAutoFormat )
+{
+ ResetCursorStack();
+ if( !CanInsert() )
+ return;
+
+ SwActContext aActContext(this);
+
+ m_rView.GetEditWin().FlushInBuffer();
+ StartUndo(SwUndoId::SPLITNODE);
+
+ bool bHasSel = HasSelection();
+ if (bHasSel)
+ DelRight();
+
+ bool bHandled = false;
+ if (GetViewOptions()->IsShowOutlineContentVisibilityButton() && IsEndPara())
+ bHandled = lcl_FoldedOutlineNodeEndOfParaSplit(this);
+
+ if (!bHandled)
+ SwFEShell::SplitNode( bAutoFormat );
+
+ EndUndo(SwUndoId::SPLITNODE);
+}
+
+// Turn on numbering
+// Parameter: Optional specification of a name for the named list;
+// this indicates a position if it is possible to convert them
+// into a number and less than nMaxRules.
+
+// To test the CharFormats at the numbering
+// external void SetNumChrFormat( SwWrtShell*, SwNumRules& );
+
+// -> #i40041#
+// Preconditions (as far as OD has figured out):
+// - <SwEditShell::HasNumber()> is false, if <bNum> is true
+// - <SwEditShell::HasBullet()> is false, if <bNum> is false
+// Behavior of method is determined by the current situation at the current
+// cursor position in the document.
+void SwWrtShell::NumOrBulletOn(bool bNum)
+{
+ StartUndo(SwUndoId::NUMORNONUM);
+
+ const SwNumRule* pNumRule = GetNumRuleAtCurrCursorPos();
+
+ // - activate outline rule respectively turning on outline rule for
+ // current text node. But, only for turning on a numbering (<bNum> == true).
+ // - overwrite found numbering rule at current cursor position, if
+ // no numbering rule can be retrieved from the paragraph style.
+ bool bContinueFoundNumRule( false );
+ bool bActivateOutlineRule( false );
+ int nActivateOutlineLvl( MAXLEVEL ); // only relevant, if <bActivateOutlineRule> == true
+ SwTextFormatColl * pColl = GetCurTextFormatColl();
+ if ( pColl )
+ {
+ // retrieve numbering rule at paragraph
+ // style, which is found at current cursor position in the document.
+ SwNumRule* pCollRule = mxDoc->FindNumRulePtr(pColl->GetNumRule().GetValue());
+ // #125993# - The outline numbering rule isn't allowed
+ // to be derived from a parent paragraph style to a derived one.
+ // Thus check, if the found outline numbering rule is directly
+ // set at the paragraph style <pColl>. If not, set <pCollRule> to NULL
+ if ( pCollRule && pCollRule == GetDoc()->GetOutlineNumRule() )
+ {
+ const SwNumRule* pDirectCollRule =
+ mxDoc->FindNumRulePtr(pColl->GetNumRule( false ).GetValue());
+ if ( !pDirectCollRule )
+ {
+ pCollRule = nullptr;
+ }
+ }
+
+ if ( !pCollRule )
+ {
+ pNumRule = pCollRule;
+ }
+ // no activation or continuation of outline numbering in Writer/Web document
+ else if ( bNum &&
+ !dynamic_cast<SwWebDocShell*>(GetDoc()->GetDocShell()) &&
+ pCollRule == GetDoc()->GetOutlineNumRule() )
+ {
+ if ( pNumRule == pCollRule )
+ {
+ // check, if text node at current cursor positioned is counted.
+ // If not, let it been counted. Then it has to be checked,
+ // of the outline numbering has to be activated or continued.
+ SwTextNode const*const pTextNode = sw::GetParaPropsNode(
+ *GetLayout(), GetCursor()->GetPoint()->GetNode());
+ if ( pTextNode && !pTextNode->IsCountedInList() )
+ {
+ // check, if numbering of the outline level of the paragraph
+ // style is active. If not, activate this outline level.
+ nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
+ OSL_ENSURE( pColl->IsAssignedToListLevelOfOutlineStyle(),
+ "<SwWrtShell::NumOrBulletOn(..)> - paragraph style with outline rule, but no outline level" );
+ if ( pColl->IsAssignedToListLevelOfOutlineStyle() &&
+ pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
+ == SVX_NUM_NUMBER_NONE )
+ {
+ // activate outline numbering
+ bActivateOutlineRule = true;
+ }
+ else
+ {
+ // turning on outline numbering at current cursor position
+ bContinueFoundNumRule = true;
+ }
+ }
+ else
+ {
+ // #i101234#
+ // activate outline numbering, because from the precondition
+ // it's known, that <SwEdit::HasNumber()> == false
+ bActivateOutlineRule = true;
+ nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
+ }
+ }
+ else if ( !pNumRule )
+ {
+ // #i101234#
+ // Check, if corresponding list level of the outline numbering
+ // has already a numbering format set.
+ nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
+ if ( pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
+ == SVX_NUM_NUMBER_NONE )
+ {
+ // activate outline numbering, because from the precondition
+ // it's known, that <SwEdit::HasNumber()> == false
+ bActivateOutlineRule = true;
+ }
+ else
+ {
+ // turning on outline numbering at current cursor position
+ bContinueFoundNumRule = true;
+ }
+ }
+ else
+ {
+ // check, if numbering of the outline level of the paragraph
+ // style is active. If not, activate this outline level.
+ nActivateOutlineLvl = pColl->GetAssignedOutlineStyleLevel();
+ OSL_ENSURE( pColl->IsAssignedToListLevelOfOutlineStyle(),
+ "<SwWrtShell::NumOrBulletOn(..)> - paragraph style with outline rule, but no outline level" );
+ if ( pColl->IsAssignedToListLevelOfOutlineStyle() &&
+ pCollRule->Get( o3tl::narrowing<sal_uInt16>(nActivateOutlineLvl) ).GetNumberingType()
+ == SVX_NUM_NUMBER_NONE )
+ {
+ // activate outline numbering
+ bActivateOutlineRule = true;
+ }
+ else
+ {
+ // turning on outline numbering at current cursor position
+ bContinueFoundNumRule = true;
+ }
+ }
+ pNumRule = pCollRule;
+ }
+ }
+
+ // Only automatic numbering/bullet rules should be changed.
+ // Note: The outline numbering rule is also an automatic one. It's only
+ // changed, if it has to be activated.
+ if ( pNumRule )
+ {
+ if ( !pNumRule->IsAutoRule() )
+ {
+ pNumRule = nullptr;
+ }
+ else if ( pNumRule == GetDoc()->GetOutlineNumRule() &&
+ !bActivateOutlineRule && !bContinueFoundNumRule )
+ {
+ pNumRule = nullptr;
+ }
+ }
+
+ // Search for a previous numbering/bullet rule to continue it.
+ OUString sContinuedListId;
+ if ( !pNumRule )
+ {
+ pNumRule = GetDoc()->SearchNumRule( *GetCursor()->GetPoint(),
+ false, bNum, false, 0,
+ sContinuedListId, GetLayout() );
+ bContinueFoundNumRule = pNumRule != nullptr;
+ }
+
+ if (pNumRule)
+ {
+ SwNumRule aNumRule(*pNumRule);
+
+ // do not change found numbering/bullet rule, if it should only be continued.
+ if ( !bContinueFoundNumRule )
+ {
+ SwTextNode const*const pTextNode = sw::GetParaPropsNode(
+ *GetLayout(), GetCursor()->GetPoint()->GetNode());
+
+ if (pTextNode)
+ {
+ // use above retrieve outline level, if outline numbering has to be activated.
+ int nLevel = bActivateOutlineRule
+ ? nActivateOutlineLvl
+ : pTextNode->GetActualListLevel();
+
+ if (nLevel < 0)
+ nLevel = 0;
+
+ if (nLevel >= MAXLEVEL)
+ nLevel = MAXLEVEL - 1;
+
+ SwNumFormat aFormat(aNumRule.Get(o3tl::narrowing<sal_uInt16>(nLevel)));
+
+ if (bNum)
+ aFormat.SetNumberingType(SVX_NUM_ARABIC);
+ else
+ {
+ // #i63395# Only apply user defined default bullet font
+ if ( numfunc::IsDefBulletFontUserDefined() )
+ {
+ const vcl::Font* pFnt = &numfunc::GetDefBulletFont();
+ aFormat.SetBulletFont( pFnt );
+ }
+ aFormat.SetBulletChar( numfunc::GetBulletChar(static_cast<sal_uInt8>(nLevel)));
+ aFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
+ // #i93908# clear suffix for bullet lists
+ aFormat.SetListFormat("", "", nLevel);
+ }
+ aNumRule.Set(o3tl::narrowing<sal_uInt16>(nLevel), aFormat);
+ }
+ }
+
+ // reset indent attribute on applying list style
+ SetCurNumRule( aNumRule, false, sContinuedListId, true );
+ }
+ else
+ {
+ // #i95907#
+ const SvxNumberFormat::SvxNumPositionAndSpaceMode ePosAndSpaceMode(
+ numfunc::GetDefaultPositionAndSpaceMode() );
+ SwNumRule aNumRule( GetUniqueNumRuleName(), ePosAndSpaceMode );
+ // Append the character template at the numbering.
+ SwCharFormat* pChrFormat;
+ SwDocShell* pDocSh = GetView().GetDocShell();
+ // #i63395#
+ // Only apply user defined default bullet font
+ const vcl::Font* pFnt = numfunc::IsDefBulletFontUserDefined()
+ ? &numfunc::GetDefBulletFont()
+ : nullptr;
+
+ if (bNum)
+ {
+ pChrFormat = GetCharFormatFromPool( RES_POOLCHR_NUM_LEVEL );
+ }
+ else
+ {
+ pChrFormat = GetCharFormatFromPool( RES_POOLCHR_BULLET_LEVEL );
+ }
+
+ const SwTextNode *const pTextNode = sw::GetParaPropsNode(*GetLayout(),
+ GetCursor()->GetPoint()->GetNode());
+ const SwTwips nWidthOfTabs = pTextNode
+ ? pTextNode->GetWidthOfLeadingTabs()
+ : 0;
+ GetDoc()->getIDocumentContentOperations().RemoveLeadingWhiteSpace(*GetCursor());
+
+ const bool bHtml = dynamic_cast<SwWebDocShell*>( pDocSh ) != nullptr;
+ const bool bRightToLeft = IsInRightToLeftText();
+ for( sal_uInt8 nLvl = 0; nLvl < MAXLEVEL; ++nLvl )
+ {
+ SwNumFormat aFormat( aNumRule.Get( nLvl ) );
+ aFormat.SetCharFormat( pChrFormat );
+
+ if (! bNum)
+ {
+ // #i63395#
+ // Only apply user defined default bullet font
+ if ( pFnt )
+ {
+ aFormat.SetBulletFont( pFnt );
+ }
+ aFormat.SetBulletChar( numfunc::GetBulletChar(nLvl) );
+ aFormat.SetNumberingType(SVX_NUM_CHAR_SPECIAL);
+ // #i93908# clear suffix for bullet lists
+ aFormat.SetListFormat("", "", nLvl);
+ }
+
+ // #i95907#
+ if ( ePosAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
+ {
+ if(bHtml && nLvl)
+ {
+ // 1/2" for HTML
+ aFormat.SetAbsLSpace(nLvl * 720);
+ }
+ else if ( nWidthOfTabs > 0 )
+ {
+ aFormat.SetAbsLSpace(nWidthOfTabs + nLvl * 720);
+ }
+ }
+
+ // #i38904# Default alignment for
+ // numbering/bullet should be rtl in rtl paragraph:
+ if ( bRightToLeft )
+ {
+ aFormat.SetNumAdjust( SvxAdjust::Right );
+ }
+
+ aNumRule.Set( nLvl, aFormat );
+ }
+
+ // #i95907#
+ if ( pTextNode &&
+ ePosAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+
+ const SwTwips nTextNodeIndent = pTextNode->GetAdditionalIndentForStartingNewList();
+ if ( ( nTextNodeIndent + nWidthOfTabs ) != 0 )
+ {
+ // #i111172#/fdo#85666
+ // If text node is already inside a list, assure that the indents
+ // are the same. Thus, adjust the indent change value by subtracting
+ // indents of to be applied list style.
+ SwTwips nIndentChange = nTextNodeIndent + nWidthOfTabs;
+ if ( pTextNode->GetNumRule() )
+ {
+ int nLevel = pTextNode->GetActualListLevel();
+
+ if (nLevel < 0)
+ nLevel = 0;
+
+ if (nLevel >= MAXLEVEL)
+ nLevel = MAXLEVEL - 1;
+
+ const SwNumFormat& aFormat( aNumRule.Get( nLevel ) );
+ if ( aFormat.GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT )
+ {
+ nIndentChange -= aFormat.GetIndentAt() + aFormat.GetFirstLineIndent();
+ }
+ }
+ aNumRule.ChangeIndent( nIndentChange );
+ }
+ }
+ // reset indent attribute on applying list style
+ // start new list
+ SetCurNumRule( aNumRule, true, OUString(), true );
+ }
+
+ EndUndo(SwUndoId::NUMORNONUM);
+}
+// <- #i40041#
+
+void SwWrtShell::NumOn()
+{
+ NumOrBulletOn(true);
+}
+
+void SwWrtShell::NumOrBulletOff()
+{
+ const SwNumRule * pCurNumRule = GetNumRuleAtCurrCursorPos();
+
+ if (!pCurNumRule)
+ return;
+
+ if (pCurNumRule->IsOutlineRule())
+ {
+ SwNumRule aNumRule(*pCurNumRule);
+
+ SwTextNode * pTextNode =
+ sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->GetNode());
+
+ if (pTextNode)
+ {
+ int nLevel = pTextNode->GetActualListLevel();
+
+ if (nLevel < 0)
+ nLevel = 0;
+
+ if (nLevel >= MAXLEVEL)
+ nLevel = MAXLEVEL - 1;
+
+ SwNumFormat aFormat(aNumRule.Get(o3tl::narrowing<sal_uInt16>(nLevel)));
+
+ aFormat.SetNumberingType(SVX_NUM_NUMBER_NONE);
+ aNumRule.Set(nLevel, aFormat);
+
+ // no start or continuation of a list - the outline style is only changed.
+ SetCurNumRule( aNumRule, false );
+ }
+ }
+ else
+ {
+ DelNumRules();
+ }
+
+ // #126346# - Cursor can not be anymore in front of
+ // a label, because numbering/bullet is switched off.
+ SetInFrontOfLabel( false );
+}
+// <- #i29560#
+
+// Request Default-Bulletlist
+
+void SwWrtShell::BulletOn()
+{
+ NumOrBulletOn(false);
+}
+
+SelectionType SwWrtShell::GetSelectionType() const
+{
+ // ContentType cannot be determined within a Start-/EndAction.
+ // Because there is no invalid value TEXT will be returned.
+ // The value does not matter, it may be updated in EndAction anyway.
+
+ if (ActionPend())
+ return IsSelFrameMode() ? SelectionType::Frame : SelectionType::Text;
+
+ SwView &_rView = const_cast<SwView&>(GetView());
+ if (_rView.GetPostItMgr() && _rView.GetPostItMgr()->HasActiveSidebarWin() )
+ return SelectionType::PostIt;
+
+ // Inserting a frame is not a DrawMode
+ SelectionType nCnt;
+ if ( !_rView.GetEditWin().IsFrameAction() &&
+ (IsObjSelected() || (_rView.IsDrawMode() && !IsFrameSelected()) ))
+ {
+ if (GetDrawView()->IsTextEdit())
+ nCnt = SelectionType::DrawObjectEditMode;
+ else
+ {
+ if (GetView().IsFormMode()) // Only Form selected
+ nCnt = SelectionType::DbForm;
+ else
+ nCnt = SelectionType::DrawObject; // Any draw object
+
+ if (_rView.IsBezierEditMode())
+ nCnt |= SelectionType::Ornament;
+ else if( GetDrawView()->GetContext() == SdrViewContext::Media )
+ nCnt |= SelectionType::Media;
+
+ if (svx::checkForSelectedCustomShapes( GetDrawView(), true /* bOnlyExtruded */ ))
+ {
+ nCnt |= SelectionType::ExtrudedCustomShape;
+ }
+
+ if (svx::checkForSelectedFontWork( GetDrawView() ))
+ {
+ nCnt |= SelectionType::FontWork;
+ }
+ }
+
+ return nCnt;
+ }
+
+ nCnt = static_cast<SelectionType>(GetCntType());
+
+ if ( IsFrameSelected() )
+ {
+ if (_rView.IsDrawMode())
+ _rView.LeaveDrawCreate(); // clean up (Bug #45639)
+ if ( !(nCnt & (SelectionType::Graphic | SelectionType::Ole)) )
+ return SelectionType::Frame;
+ }
+
+ if ( IsCursorInTable() )
+ nCnt |= SelectionType::Table;
+
+ if ( IsTableMode() )
+ {
+ nCnt |= SelectionType::Table | SelectionType::TableCell;
+ SwTable::SearchType eTableSel = GetEnhancedTableSelection();
+ if ( eTableSel == SwTable::SEARCH_ROW )
+ nCnt |= SelectionType::TableRow;
+ else if ( eTableSel == SwTable::SEARCH_COL )
+ nCnt |= SelectionType::TableCol;
+ }
+
+ // Do not pop up numbering toolbar, if the text node has a numbering of type SVX_NUM_NUMBER_NONE.
+ const SwNumRule* pNumRule = GetNumRuleAtCurrCursorPos();
+ if ( pNumRule )
+ {
+ const SwTextNode* pTextNd =
+ sw::GetParaPropsNode(*GetLayout(), GetCursor()->GetPoint()->GetNode());
+
+ if ( pTextNd && pTextNd->IsInList() )
+ {
+ int nLevel = pTextNd->GetActualListLevel();
+
+ if (nLevel < 0)
+ nLevel = 0;
+
+ if (nLevel >= MAXLEVEL)
+ nLevel = MAXLEVEL - 1;
+
+ const SwNumFormat& rFormat = pNumRule->Get(nLevel);
+ if ( SVX_NUM_NUMBER_NONE != rFormat.GetNumberingType() )
+ nCnt |= SelectionType::NumberList;
+ }
+ }
+
+ return nCnt;
+}
+
+// Find the text collection with the name rCollname
+// Returns: Pointer at the collection or 0, if no
+// text collection with this name exists, or
+// this is a default template.
+
+SwTextFormatColl *SwWrtShell::GetParaStyle(const OUString &rCollName, GetStyle eCreate )
+{
+ SwTextFormatColl* pColl = FindTextFormatCollByName( rCollName );
+ if( !pColl && GETSTYLE_NOCREATE != eCreate )
+ {
+ sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( rCollName, SwGetPoolIdFromName::TxtColl );
+ if( USHRT_MAX != nId || GETSTYLE_CREATEANY == eCreate )
+ pColl = GetTextCollFromPool( nId );
+ }
+ return pColl;
+}
+
+// Find the text collection with the name rCollname
+// Returns: Pointer at the collection or 0, if no
+// character template with this name exists, or
+// this is a default template or template is automatic.
+
+SwCharFormat *SwWrtShell::GetCharStyle(const OUString &rFormatName, GetStyle eCreate )
+{
+ SwCharFormat* pFormat = FindCharFormatByName( rFormatName );
+ if( !pFormat && GETSTYLE_NOCREATE != eCreate )
+ {
+ sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName( rFormatName, SwGetPoolIdFromName::ChrFmt );
+ if( USHRT_MAX != nId || GETSTYLE_CREATEANY == eCreate )
+ pFormat = static_cast<SwCharFormat*>(GetFormatFromPool( nId ));
+ }
+ return pFormat;
+}
+
+// Find the table format with the name rFormatname
+// Returns: Pointer at the collection or 0, if no
+// frame format with this name exists or
+// this is a default format or the format is automatic.
+
+SwFrameFormat *SwWrtShell::GetTableStyle(std::u16string_view rFormatName)
+{
+ for( size_t i = GetTableFrameFormatCount(); i; )
+ {
+ SwFrameFormat *pFormat = &GetTableFrameFormat( --i );
+ if( !pFormat->IsDefault() &&
+ pFormat->GetName() == rFormatName && IsUsed( *pFormat ) )
+ return pFormat;
+ }
+ return nullptr;
+}
+
+void SwWrtShell::addCurrentPosition() {
+ SwPaM* pPaM = GetCursor();
+ m_aNavigationMgr.addEntry(*pPaM->GetPoint());
+}
+
+// Applying templates
+
+void SwWrtShell::SetPageStyle(const OUString &rCollName)
+{
+ if( !SwCursorShell::HasSelection() && !IsSelFrameMode() && !IsObjSelected() )
+ {
+ SwPageDesc* pDesc = FindPageDescByName( rCollName, true );
+ if( pDesc )
+ ChgCurPageDesc( *pDesc );
+ }
+}
+
+// Access templates
+
+OUString const & SwWrtShell::GetCurPageStyle() const
+{
+ return GetPageDesc(GetCurPageDesc( false/*bCalcFrame*/ )).GetName();
+}
+
+// Change the current template referring to the existing change.
+
+void SwWrtShell::QuickUpdateStyle()
+{
+ SwTextFormatColl *pColl = GetCurTextFormatColl();
+
+ // Default cannot be changed
+ if(pColl && !pColl->IsDefault())
+ {
+ FillByEx(pColl);
+ // Also apply the template to remove hard attribute assignment.
+ SetTextFormatColl(pColl);
+ }
+}
+
+void SwWrtShell::AutoUpdatePara(SwTextFormatColl* pColl, const SfxItemSet& rStyleSet, SwPaM* pPaM )
+{
+ SwPaM* pCursor = pPaM ? pPaM : GetCursor( );
+ SfxItemSetFixed<
+ RES_CHRATR_BEGIN, RES_CHRATR_END - 1,
+ RES_PARATR_BEGIN, RES_PARATR_END - 1,
+ RES_FRMATR_BEGIN, RES_FRMATR_END - 1,
+ SID_ATTR_TABSTOP_DEFAULTS,SID_ATTR_TABSTOP_OFFSET,
+ SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER,
+ SID_ATTR_PARA_MODEL, SID_ATTR_PARA_KEEP,
+ SID_ATTR_PARA_PAGENUM, SID_ATTR_PARA_PAGENUM> aCoreSet( GetAttrPool() );
+ GetPaMAttr( pCursor, aCoreSet );
+ bool bReset = false;
+ SfxItemIter aParaIter( aCoreSet );
+ for (auto pParaItem = aParaIter.GetCurItem(); pParaItem; pParaItem = aParaIter.NextItem())
+ {
+ if(!IsInvalidItem(pParaItem))
+ {
+ sal_uInt16 nWhich = pParaItem->Which();
+ if(SfxItemState::SET == aParaIter.GetItemState() &&
+ SfxItemState::SET == rStyleSet.GetItemState(nWhich))
+ {
+ aParaIter.ClearItem();
+ bReset = true;
+ }
+ }
+ }
+ StartAction();
+ if(bReset)
+ {
+ ResetAttr({}, pCursor);
+ SetAttrSet(aCoreSet, SetAttrMode::DEFAULT, pCursor);
+ }
+ mxDoc->ChgFormat(*pColl, rStyleSet );
+ EndAction();
+}
+
+void SwWrtShell::AutoUpdateFrame( SwFrameFormat* pFormat, const SfxItemSet& rStyleSet )
+{
+ StartAction();
+
+ ResetFlyFrameAttr( &rStyleSet );
+ pFormat->SetFormatAttr( rStyleSet );
+
+ EndAction();
+}
+
+void SwWrtShell::AutoCorrect( SvxAutoCorrect& rACorr, sal_Unicode cChar )
+{
+ ResetCursorStack();
+ if(!CanInsert())
+ return;
+
+ bool bStarted = false;
+ SwRewriter aRewriter;
+
+ if(HasSelection())
+ {
+ // Only parentheses here, because the regular insert
+ // is already clipped to the editshell
+ StartAllAction();
+
+ OUString aTmpStr1 = SwResId(STR_START_QUOTE) +
+ GetSelText() +
+ SwResId(STR_END_QUOTE);
+ OUString aTmpStr3 = SwResId(STR_START_QUOTE) +
+ OUStringChar(cChar) +
+ SwResId(STR_END_QUOTE);
+ aRewriter.AddRule( UndoArg1, aTmpStr1 );
+ aRewriter.AddRule( UndoArg2, SwResId(STR_YIELDS) );
+ aRewriter.AddRule( UndoArg3, aTmpStr3 );
+
+ StartUndo( SwUndoId::REPLACE, &aRewriter );
+ bStarted = true;
+ DelRight(true);
+ }
+ SwEditShell::AutoCorrect( rACorr, IsInsMode(), cChar );
+
+ if(bStarted)
+ {
+ EndAllAction();
+ EndUndo( SwUndoId::REPLACE, &aRewriter );
+ }
+}
+
+// Some kind of controlled copy ctor
+
+SwWrtShell::SwWrtShell( SwWrtShell& rSh, vcl::Window *_pWin, SwView &rShell )
+ : SwFEShell(rSh, _pWin)
+ , m_rView(rShell)
+ , m_aNavigationMgr(*this)
+{
+ BITFLD_INI_LIST
+ CurrShell aCurr( this );
+
+ SetSfxViewShell( static_cast<SfxViewShell *>(&rShell) );
+ SetFlyMacroLnk( LINK(this, SwWrtShell, ExecFlyMac) );
+
+ // place the cursor on the first field...
+ IFieldmark *pBM = nullptr;
+ if (IsFormProtected() && (pBM = GetFieldmarkAfter(/*bLoop=*/true)) !=nullptr) {
+ GotoFieldmark(pBM);
+ }
+}
+
+SwWrtShell::SwWrtShell( SwDoc& rDoc, vcl::Window *_pWin, SwView &rShell,
+ const SwViewOption *pViewOpt )
+ : SwFEShell(rDoc, _pWin, pViewOpt)
+ , m_rView(rShell)
+ , m_aNavigationMgr(*this)
+{
+ BITFLD_INI_LIST
+ CurrShell aCurr( this );
+ SetSfxViewShell( static_cast<SfxViewShell *>(&rShell) );
+ SetFlyMacroLnk( LINK(this, SwWrtShell, ExecFlyMac) );
+
+ // place the cursor on the first field...
+ IFieldmark *pBM = nullptr;
+ if (IsFormProtected() && (pBM = GetFieldmarkAfter(/*bLoop=*/true)) !=nullptr) {
+ GotoFieldmark(pBM);
+ }
+}
+
+SwWrtShell::~SwWrtShell()
+{
+ CurrShell aCurr( this );
+ while(IsModePushed())
+ PopMode();
+ while(PopCursor(false))
+ ;
+ SwTransferable::ClearSelection( *this );
+}
+
+bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete)
+{
+ ::std::optional<SwCallLink> aLink(std::in_place, *this);
+ return Pop(eDelete, aLink);
+}
+
+bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete, ::std::optional<SwCallLink>& roLink)
+{
+ bool bRet = SwCursorShell::Pop(eDelete, roLink);
+ if( bRet && IsSelection() )
+ {
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ }
+ return bRet;
+}
+
+bool SwWrtShell::CanInsert()
+{
+ if(IsSelFrameMode())
+ {
+ return false;
+ }
+
+ if(IsObjSelected())
+ {
+ return false;
+ }
+
+ if(GetView().GetDrawFuncPtr())
+ {
+ return false;
+ }
+
+ if(GetView().GetPostItMgr()->GetActiveSidebarWin())
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void SwWrtShell::ChgDBData(const SwDBData& aDBData)
+{
+ SwEditShell::ChgDBData(aDBData);
+ //notify the db-beamer if available
+ GetView().NotifyDBChanged();
+}
+
+OUString SwWrtShell::GetSelDescr() const
+{
+ OUString aResult;
+
+ SelectionType nSelType = GetSelectionType();
+ switch (nSelType)
+ {
+ case SelectionType::Graphic:
+ aResult = SwResId(STR_GRAPHIC);
+
+ break;
+ case SelectionType::Frame:
+ {
+ const SwFrameFormat * pFrameFormat = GetSelectedFrameFormat();
+
+ if (pFrameFormat)
+ aResult = pFrameFormat->GetDescription();
+ }
+ break;
+ case SelectionType::DrawObject:
+ {
+ aResult = SwResId(STR_DRAWING_OBJECTS);
+ }
+ break;
+ default:
+ if (mxDoc)
+ aResult = GetCursorDescr();
+ }
+
+ return aResult;
+}
+
+void SwWrtShell::ApplyViewOptions( const SwViewOption &rOpt )
+{
+ SwFEShell::ApplyViewOptions( rOpt );
+ //#i115062# invalidate meta character slot
+ GetView().GetViewFrame().GetBindings().Invalidate( FN_VIEW_META_CHARS );
+}
+
+void SwWrtShell::SetReadonlyOption(bool bSet)
+{
+ GetView().GetEditWin().GetFrameControlsManager().SetReadonlyControls( bSet );
+ SwViewShell::SetReadonlyOption( bSet );
+}
+
+// Switch on/off header or footer of a page style - if an empty name is
+// given all styles are changed
+
+void SwWrtShell::ChangeHeaderOrFooter(
+ std::u16string_view rStyleName, bool bHeader, bool bOn, bool bShowWarning)
+{
+ SdrView *const pSdrView = GetDrawView();
+ if (pSdrView && pSdrView->IsTextEdit())
+ { // tdf#107474 deleting header may delete active drawing object
+ pSdrView->SdrEndTextEdit(true);
+ }
+ addCurrentPosition();
+ StartAllAction();
+ StartUndo( SwUndoId::HEADER_FOOTER ); // #i7983#
+ bool bExecute = true;
+ bool bCursorSet = false;
+ for( size_t nFrom = 0, nTo = GetPageDescCnt();
+ nFrom < nTo; ++nFrom )
+ {
+ SwPageDesc aDesc( GetPageDesc( nFrom ));
+ OUString sTmp(aDesc.GetName());
+ if( rStyleName.empty() || rStyleName == sTmp )
+ {
+ bool bChgd = false;
+
+ if( bShowWarning && !bOn && GetActiveView() && GetActiveView() == &GetView() &&
+ ( (bHeader && aDesc.GetMaster().GetHeader().IsActive()) ||
+ (!bHeader && aDesc.GetMaster().GetFooter().IsActive()) ) )
+ {
+ bShowWarning = false;
+ //Actions have to be closed while the dialog is showing
+ EndAllAction();
+
+ weld::Window* pParent = GetView().GetFrameWeld();
+ short nResult;
+ if (bHeader) {
+ nResult = DeleteHeaderDialog(pParent).run();
+ } else {
+ nResult = DeleteFooterDialog(pParent).run();
+ }
+
+ bExecute = nResult == RET_YES;
+ StartAllAction();
+ if (nResult == RET_YES)
+ ToggleHeaderFooterEdit();
+ }
+ if( bExecute )
+ {
+ bChgd = true;
+ SwFrameFormat &rMaster = aDesc.GetMaster();
+ if(bHeader)
+ rMaster.SetFormatAttr( SwFormatHeader( bOn ));
+ else
+ rMaster.SetFormatAttr( SwFormatFooter( bOn ));
+ if( bOn )
+ {
+ // keep in sync with FN_PGNUMBER_WIZARD
+ constexpr tools::Long constTwips_5mm = o3tl::toTwips(5, o3tl::Length::mm);
+ SvxULSpaceItem aUL(bHeader ? 0 : constTwips_5mm, bHeader ? constTwips_5mm : 0, RES_UL_SPACE );
+ SwFrameFormat* pFormat = bHeader ?
+ const_cast<SwFrameFormat*>(rMaster.GetHeader().GetHeaderFormat()) :
+ const_cast<SwFrameFormat*>(rMaster.GetFooter().GetFooterFormat());
+ pFormat->SetFormatAttr( aUL );
+ XFillStyleItem aFill(drawing::FillStyle_NONE);
+ pFormat->SetFormatAttr(aFill);
+ }
+ }
+ if( bChgd )
+ {
+ ChgPageDesc( nFrom, aDesc );
+
+ if( !bCursorSet && bOn )
+ {
+ if ( !IsHeaderFooterEdit() )
+ ToggleHeaderFooterEdit();
+ bCursorSet = SetCursorInHdFt(
+ rStyleName.empty() ? SIZE_MAX : nFrom,
+ bHeader );
+ }
+ }
+ }
+ }
+ EndUndo( SwUndoId::HEADER_FOOTER ); // #i7983#
+ EndAllAction();
+}
+
+void SwWrtShell::SetShowHeaderFooterSeparator( FrameControlType eControl, bool bShow )
+{
+ SwViewShell::SetShowHeaderFooterSeparator( eControl, bShow );
+ if ( !bShow )
+ GetView().GetEditWin().GetFrameControlsManager().HideControls( eControl );
+}
+
+void SwWrtShell::InsertPostIt(SwFieldMgr& rFieldMgr, const SfxRequest& rReq)
+{
+ SwPostItField* pPostIt = dynamic_cast<SwPostItField*>(rFieldMgr.GetCurField());
+ bool bNew = !(pPostIt && pPostIt->GetTyp()->Which() == SwFieldIds::Postit);
+ if (bNew || GetView().GetPostItMgr()->IsAnswer())
+ {
+ const SvxPostItAuthorItem* pAuthorItem = rReq.GetArg<SvxPostItAuthorItem>(SID_ATTR_POSTIT_AUTHOR);
+ OUString sAuthor;
+ if ( pAuthorItem )
+ sAuthor = pAuthorItem->GetValue();
+ else
+ {
+ std::size_t nAuthor = SW_MOD()->GetRedlineAuthor();
+ sAuthor = SW_MOD()->GetRedlineAuthor(nAuthor);
+ }
+
+ const SvxPostItTextItem* pTextItem = rReq.GetArg<SvxPostItTextItem>(SID_ATTR_POSTIT_TEXT);
+ OUString sText;
+ if ( pTextItem )
+ sText = pTextItem->GetValue();
+
+ // If we have a text already registered for answer, use that
+ if (GetView().GetPostItMgr()->IsAnswer() && !GetView().GetPostItMgr()->GetAnswerText().isEmpty())
+ {
+ sText = GetView().GetPostItMgr()->GetAnswerText();
+ GetView().GetPostItMgr()->RegisterAnswerText(OUString());
+ }
+
+ if ( HasSelection() && !IsTableMode() )
+ {
+ KillPams();
+ }
+
+ // #i120513# Inserting a comment into an autocompletion crashes
+ // --> suggestion has to be removed before
+ GetView().GetEditWin().StopQuickHelp();
+
+ SwInsertField_Data aData(SwFieldTypesEnum::Postit, 0, sAuthor, sText, 0);
+
+ if (IsSelFrameMode())
+ {
+ SwFlyFrame* pFly = GetSelectedFlyFrame();
+
+ // Remember the anchor of the selected object before deletion.
+ std::optional<SwPosition> oAnchor;
+ if (pFly)
+ {
+ SwFrameFormat* pFormat = pFly->GetFormat();
+ if (pFormat)
+ {
+ RndStdIds eAnchorId = pFormat->GetAnchor().GetAnchorId();
+ if ((eAnchorId == RndStdIds::FLY_AS_CHAR || eAnchorId == RndStdIds::FLY_AT_CHAR) && pFormat->GetAnchor().GetAnchorNode())
+ {
+ oAnchor.emplace(*pFormat->GetAnchor().GetContentAnchor());
+ }
+ }
+ }
+
+ // A frame is selected, end frame selection.
+ EnterStdMode();
+ GetView().AttrChangedNotify(nullptr);
+
+ // Set up text selection, so the anchor of the frame will be the anchor of the
+ // comment.
+ if (pFly)
+ {
+ if (oAnchor)
+ *GetCurrentShellCursor().GetPoint() = *oAnchor;
+ SwFrameFormat* pFormat = pFly->GetFormat();
+ if (pFormat && pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
+ {
+ Right(SwCursorSkipMode::Cells, /*bSelect=*/true, 1, /*bBasicCall=*/false, /*bVisual=*/true);
+ }
+ else if (pFormat && pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_CHAR)
+ {
+ aData.m_oAnnotationRange.emplace(*GetCurrentShellCursor().Start(),
+ *GetCurrentShellCursor().End());
+ }
+ }
+ }
+
+ rFieldMgr.InsertField( aData );
+
+ Push();
+ SwCursorShell::Left(1, SwCursorSkipMode::Chars);
+ pPostIt = static_cast<SwPostItField*>(rFieldMgr.GetCurField());
+ Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore cursor position
+ }
+
+ // Client has disabled annotations rendering, no need to
+ // focus the postit field
+ if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
+ return;
+
+ if (pPostIt)
+ {
+ SwFieldType* pType = GetDoc()->getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Postit, OUString(), false);
+ if(auto pFormat = pType->FindFormatForField(pPostIt))
+ pFormat->Broadcast( SwFormatFieldHint( nullptr, SwFormatFieldHintWhich::FOCUS, &GetView() ) );
+ }
+}
+
+bool SwWrtShell::IsOutlineContentVisible(const size_t nPos)
+{
+ const SwOutlineNodes& rOutlineNodes = GetDoc()->GetNodes().GetOutLineNds();
+ const SwNode* pOutlineNode = rOutlineNodes[nPos];
+
+ // no layout frame means outline folding is set to include sub levels and the outline node has
+ // a parent outline node with outline content visible attribute false (folded outline content)
+ if (!pOutlineNode->GetTextNode()->getLayoutFrame(GetLayout()))
+ return false;
+
+ // try the next node to determine if this outline node has visible content
+ SwNodeIndex aIdx(*pOutlineNode, +1);
+ if (aIdx.GetNode() == aIdx.GetNodes().GetEndOfContent()) // end of regular content
+ return false;
+
+ if (aIdx.GetNode().IsTextNode() || aIdx.GetNode().IsTableNode() ||
+ aIdx.GetNode().IsSectionNode())
+ {
+ // * sublevels treated as outline content
+ // If next node (aIdx) doesn't have a layout frame
+ // then this outline node does not have visible outline content.
+ // * sublevels NOT treated as outline content
+ // If the next node (aIdx) is the next outline node
+ // then return the outline content visible attribute value.
+ if (!GetViewOptions()->IsTreatSubOutlineLevelsAsContent() &&
+ nPos + 1 < rOutlineNodes.size() &&
+ rOutlineNodes[nPos + 1] == &aIdx.GetNode())
+ return GetAttrOutlineContentVisible(nPos);
+
+ if (aIdx.GetNode().IsTextNode())
+ return aIdx.GetNode().GetTextNode()->getLayoutFrame(GetLayout());
+ if (aIdx.GetNode().IsTableNode())
+ {
+ SwTable& rTable = aIdx.GetNode().GetTableNode()->GetTable();
+ return rTable.HasLayout();
+ }
+ if (aIdx.GetNode().IsSectionNode())
+ {
+ const auto pFormat = aIdx.GetNode().GetSectionNode()->GetSection().GetFormat();
+ return pFormat && pFormat->IsVisible();
+ }
+ }
+
+ return true;
+}
+
+void SwWrtShell::MakeOutlineLevelsVisible(const int nLevel)
+{
+ MakeAllOutlineContentTemporarilyVisible a(GetDoc());
+
+ m_rView.SetMaxOutlineLevelShown(nLevel);
+
+ bool bDocChanged = false;
+
+ const SwOutlineNodes& rOutlineNodes = GetNodes().GetOutLineNds();
+
+ // Make all missing frames.
+ for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos)
+ {
+ SwNode* pNode = rOutlineNodes[nPos];
+ if (!pNode->GetTextNode()->getLayoutFrame(GetLayout()))
+ {
+ SwNodeIndex aIdx(*pNode, +1);
+ // Make the outline paragraph frame
+ MakeFrames(GetDoc(), *pNode, aIdx.GetNode());
+ // Make the outline content visible but don't set the outline visible attribute and
+ // don't make outline content made visible not visible that have outline visible
+ // attribute false. Visibility will be taken care of when
+ // MakeAllOutlineContentTemporarilyVisible goes out of scope.
+ MakeOutlineContentVisible(nPos, true, false);
+ bDocChanged = true;
+ }
+ }
+ // Remove outline paragraph frame and outline content frames above given level.
+ for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNodes.size(); ++nPos)
+ {
+ SwNode* pNode = rOutlineNodes[nPos];
+ auto nOutlineLevel = pNode->GetTextNode()->GetAttrOutlineLevel();
+ if (nOutlineLevel > nLevel)
+ {
+ // Remove the outline content but don't set the outline visible attribute. Visibility
+ // will be taken care of when MakeAllOutlineContentTemporarilyVisible goes out of scope.
+ MakeOutlineContentVisible(nPos, false, false);
+ // Remove the outline paragraph frame.
+ pNode->GetTextNode()->DelFrames(GetLayout());
+ bDocChanged = true;
+ }
+ }
+
+ // Broadcast DocChanged if document layout has changed so the Navigator will be updated.
+ if (bDocChanged)
+ GetDoc()->GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
+}
+
+void SwWrtShell::MakeOutlineContentVisible(const size_t nPos, bool bMakeVisible, bool bSetAttrOutlineVisibility)
+{
+ const SwNodes& rNodes = GetNodes();
+ const SwOutlineNodes& rOutlineNodes = rNodes.GetOutLineNds();
+
+ SwNode* pSttNd = rOutlineNodes[nPos];
+
+ // determine end node
+ SwNode* pEndNd = &rNodes.GetEndOfContent();
+ if (rOutlineNodes.size() > nPos + 1)
+ pEndNd = rOutlineNodes[nPos + 1];
+
+ if (GetViewOptions()->IsTreatSubOutlineLevelsAsContent())
+ {
+ // get the last outline node to include (iPos)
+ int nLevel = pSttNd->GetTextNode()->GetAttrOutlineLevel();
+ int nMaxOutlineLevelShown = m_rView.GetMaxOutlineLevelShown();
+ SwOutlineNodes::size_type iPos = nPos;
+ while (++iPos < rOutlineNodes.size() &&
+ rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() > nLevel &&
+ rOutlineNodes[iPos]->GetTextNode()->GetAttrOutlineLevel() <= nMaxOutlineLevelShown);
+
+ // get the correct end node
+ // the outline node may be in frames, headers, footers special section of doc model
+ SwNode* pStartOfSectionNodeSttNd = pSttNd->StartOfSectionNode();
+ while (pStartOfSectionNodeSttNd->StartOfSectionNode()
+ != pStartOfSectionNodeSttNd->StartOfSectionNode()->StartOfSectionNode())
+ {
+ pStartOfSectionNodeSttNd = pStartOfSectionNodeSttNd->StartOfSectionNode();
+ }
+ pEndNd = pStartOfSectionNodeSttNd->EndOfSectionNode();
+
+ if (iPos < rOutlineNodes.size())
+ {
+ SwNode* pStartOfSectionNode = rOutlineNodes[iPos]->StartOfSectionNode();
+ while (pStartOfSectionNode->StartOfSectionNode()
+ != pStartOfSectionNode->StartOfSectionNode()->StartOfSectionNode())
+ {
+ pStartOfSectionNode = pStartOfSectionNode->StartOfSectionNode();
+ }
+ if (pStartOfSectionNodeSttNd == pStartOfSectionNode)
+ pEndNd = rOutlineNodes[iPos];
+ }
+ }
+
+ // table, text box, header, footer
+ if (pSttNd->GetTableBox() || pSttNd->GetIndex() < rNodes.GetEndOfExtras().GetIndex())
+ {
+ // limit to within section
+ if (pSttNd->EndOfSectionIndex() < pEndNd->GetIndex())
+ pEndNd = pSttNd->EndOfSectionNode();
+ }
+ // if pSttNd isn't in table but pEndNd is, skip over all outline nodes in table
+ else if (pEndNd->GetTableBox())
+ {
+ pEndNd = &rNodes.GetEndOfContent();
+ for (size_t nOutlinePos = nPos + 2; nOutlinePos < rOutlineNodes.size(); nOutlinePos++)
+ {
+ if (!(rOutlineNodes[nOutlinePos]->GetTableBox()))
+ {
+ pEndNd = rOutlineNodes[nOutlinePos];
+ break;
+ }
+ }
+ }
+ // end node determined
+
+ // Remove content frames from the next node after the starting outline node to
+ // the determined ending node. Always do this to prevent the chance of duplicate
+ // frames being made. They will be remade below if needed.
+ SwNodeIndex aIdx(*pSttNd, +1);
+ while (aIdx != *pEndNd)
+ {
+ SwNode* pNd = &aIdx.GetNode();
+ if (pNd->IsContentNode())
+ pNd->GetContentNode()->DelFrames(nullptr);
+ else if (pNd->IsTableNode())
+ pNd->GetTableNode()->DelFrames(nullptr);
+ ++aIdx;
+ }
+
+ if (bMakeVisible) // make outline nodes outline content visible
+ {
+ // reset the index marker and make frames
+ aIdx.Assign(*pSttNd, +1);
+ MakeFrames(GetDoc(), aIdx.GetNode(), *pEndNd);
+
+ if (bSetAttrOutlineVisibility)
+ {
+ pSttNd->GetTextNode()->SetAttrOutlineContentVisible(true);
+
+ // make outline content made visible that have outline visible attribute false not visible
+ while (aIdx != *pEndNd)
+ {
+ SwNode* pNd = &aIdx.GetNode();
+ if (pNd->IsTextNode() && pNd->GetTextNode()->IsOutline())
+ {
+ SwTextNode* pTextNd = pNd->GetTextNode();
+ bool bOutlineContentVisibleAttr = true;
+ pTextNd->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
+ if (!bOutlineContentVisibleAttr)
+ {
+ SwOutlineNodes::size_type iPos;
+ if (rOutlineNodes.Seek_Entry(pTextNd, &iPos))
+ {
+ if (pTextNd->getLayoutFrame(nullptr))
+ MakeOutlineContentVisible(iPos, false);
+ }
+ }
+ }
+ ++aIdx;
+ }
+ }
+ }
+ else if (bSetAttrOutlineVisibility)
+ pSttNd->GetTextNode()->SetAttrOutlineContentVisible(false);
+}
+
+// make content visible or not visible only if needed
+void SwWrtShell::InvalidateOutlineContentVisibility()
+{
+ GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
+
+ const SwOutlineNodes& rOutlineNds = GetNodes().GetOutLineNds();
+ for (SwOutlineNodes::size_type nPos = 0; nPos < rOutlineNds.size(); ++nPos)
+ {
+ bool bIsOutlineContentVisible = IsOutlineContentVisible(nPos);
+ bool bOutlineContentVisibleAttr = true;
+ rOutlineNds[nPos]->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
+ if (!bIsOutlineContentVisible && bOutlineContentVisibleAttr)
+ MakeOutlineContentVisible(nPos);
+ else if (bIsOutlineContentVisible && !bOutlineContentVisibleAttr)
+ MakeOutlineContentVisible(nPos, false);
+ }
+}
+
+void SwWrtShell::MakeAllFoldedOutlineContentVisible(bool bMakeVisible)
+{
+ if (bMakeVisible)
+ {
+ // make all content visible
+
+ // When shortcut is assigned to the show outline content visibility button and used to
+ // toggle the feature and the mouse pointer is on an outline frame the button will not
+ // be removed. An easy way to make sure the button does not remain shown is to use the
+ // HideControls function.
+ GetView().GetEditWin().GetFrameControlsManager().HideControls(FrameControlType::Outline);
+
+ // temporarily set outline content visible attribute true for folded outline nodes
+ std::vector<SwNode*> aFoldedOutlineNodeArray;
+ for (SwNode* pNd: GetNodes().GetOutLineNds())
+ {
+ bool bOutlineContentVisibleAttr = true;
+ pNd->GetTextNode()->GetAttrOutlineContentVisible(bOutlineContentVisibleAttr);
+ if (!bOutlineContentVisibleAttr)
+ {
+ aFoldedOutlineNodeArray.push_back(pNd);
+ pNd->GetTextNode()->SetAttrOutlineContentVisible(true);
+ }
+ }
+
+ StartAction();
+ InvalidateOutlineContentVisibility();
+ EndAction();
+
+ // restore outline content visible attribute for folded outline nodes
+ for (SwNode* pNd: aFoldedOutlineNodeArray)
+ pNd->GetTextNode()->SetAttrOutlineContentVisible(false);
+ }
+ else
+ {
+ AssureStdMode();
+
+ // Get the outline position of the cursor so the cursor can be place at a visible outline
+ // node if it is not visible after InvalidateOutlineContentVisiblity below.
+ SwOutlineNodes::size_type nPos = GetOutlinePos();
+
+ StartAction();
+ InvalidateOutlineContentVisibility();
+ EndAction();
+
+ // If needed, find a visible outline node to place the cursor.
+ if (nPos != SwOutlineNodes::npos && !IsOutlineContentVisible(nPos))
+ {
+ while (nPos != SwOutlineNodes::npos &&
+ !GetNodes().GetOutLineNds()[nPos]->GetTextNode()->getLayoutFrame(GetLayout()))
+ --nPos;
+ if (nPos != SwOutlineNodes::npos)
+ GotoOutline(nPos);
+ }
+ }
+ GetView().GetDocShell()->Broadcast(SfxHint(SfxHintId::DocChanged));
+}
+
+bool SwWrtShell::GetAttrOutlineContentVisible(const size_t nPos) const
+{
+ bool bVisibleAttr = true;
+ GetNodes().GetOutLineNds()[nPos]->GetTextNode()->GetAttrOutlineContentVisible(bVisibleAttr);
+ return bVisibleAttr;
+}
+
+bool SwWrtShell::HasFoldedOutlineContentSelected() const
+{
+ // No need to check for selection over folded outline content when there are no outline nodes.
+ if (GetDoc()->GetNodes().GetOutLineNds().empty())
+ return false;
+ for(const SwPaM& rPaM : GetCursor()->GetRingContainer())
+ {
+ SwPaM aPaM(*rPaM.GetMark(), *rPaM.GetPoint());
+ aPaM.Normalize();
+ SwNodeIndex aPointIdx(aPaM.GetPoint()->GetNode());
+ SwNodeIndex aMarkIdx(aPaM.GetMark()->GetNode());
+ // Prevent crash in the for loop below by adjusting the mark if it is set to the end of
+ // content node.
+ if (aMarkIdx.GetNode() == GetDoc()->GetNodes().GetEndOfContent())
+ --aMarkIdx;
+ if (aPointIdx == aMarkIdx)
+ continue;
+ // Return true if any nodes in PaM are folded outline content nodes.
+ SwOutlineNodes::size_type nPos;
+ for (SwNodeIndex aIdx = aPointIdx; aIdx <= aMarkIdx; ++aIdx)
+ {
+ // To allow delete when the start of the selection is at the start of a
+ // paragraph and the end of the selection is at the start of a paragraph and there
+ // are no folded outline content nodes in between.
+ if (aIdx == aMarkIdx && aPaM.GetPoint()->GetContentIndex() == 0 &&
+ aPaM.GetMark()->GetContentIndex() == 0)
+ return false;
+
+ if (GetDoc()->GetNodes().GetOutLineNds().Seek_Entry(&(aIdx.GetNode()), &nPos) &&
+ !GetAttrOutlineContentVisible(nPos))
+ return true;
+ }
+ }
+ return false;
+}
+
+void SwWrtShell::InfoReadOnlyDialog(bool bAsync) const
+{
+ if (bAsync)
+ {
+ auto xInfo = std::make_shared<weld::MessageDialogController>(
+ GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui", "InfoReadonlyDialog");
+ if (GetViewOptions()->IsShowOutlineContentVisibilityButton() &&
+ HasFoldedOutlineContentSelected())
+ {
+ xInfo->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
+ xInfo->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
+ }
+ weld::DialogController::runAsync(xInfo, [](int) {});
+ }
+ else
+ {
+ std::unique_ptr<weld::Builder>
+ xBuilder(Application::CreateBuilder(GetView().GetFrameWeld(),
+ "modules/swriter/ui/inforeadonlydialog.ui"));
+ std::unique_ptr<weld::MessageDialog>
+ xInfo(xBuilder->weld_message_dialog("InfoReadonlyDialog"));
+ if (GetViewOptions()->IsShowOutlineContentVisibilityButton() &&
+ HasFoldedOutlineContentSelected())
+ {
+ xInfo->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
+ xInfo->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
+ }
+ xInfo->run();
+ }
+}
+
+bool SwWrtShell::WarnHiddenSectionDialog() const
+{
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(
+ GetView().GetFrameWeld(), "modules/swriter/ui/warnhiddensectiondialog.ui"));
+ std::unique_ptr<weld::MessageDialog> xQuery(
+ xBuilder->weld_message_dialog("WarnHiddenSectionDialog"));
+ if (GetViewOptions()->IsShowOutlineContentVisibilityButton()
+ && HasFoldedOutlineContentSelected())
+ {
+ xQuery->set_primary_text(SwResId(STR_INFORODLG_FOLDED_PRIMARY));
+ xQuery->set_secondary_text(SwResId(STR_INFORODLG_FOLDED_SECONDARY));
+ }
+
+ return (RET_YES == xQuery->run());
+}
+
+bool SwWrtShell::WarnSwitchToDesignModeDialog() const
+{
+ std::unique_ptr<weld::MessageDialog> xQuery(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Question, VclButtonsType::YesNo, SwResId(STR_A11Y_DESIGN_MODE_PRIMARY)));
+ xQuery->set_default_response(RET_YES);
+ xQuery->set_title(SwResId(STR_A11Y_DESIGN_MODE_TITLE));
+ xQuery->set_secondary_text(SwResId(STR_A11Y_DESIGN_MODE_SECONDARY));
+
+ return (RET_YES == xQuery->run());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/wrtsh/wrtsh2.cxx b/sw/source/uibase/wrtsh/wrtsh2.cxx
new file mode 100644
index 0000000000..3a9e51136f
--- /dev/null
+++ b/sw/source/uibase/wrtsh/wrtsh2.cxx
@@ -0,0 +1,686 @@
+/* -*- 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/macitem.hxx>
+#include <sfx2/frame.hxx>
+#include <svl/eitem.hxx>
+#include <svl/listener.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sot/exchange.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+#include <fmtinfmt.hxx>
+#include <wrtsh.hxx>
+#include <docsh.hxx>
+#include <fldbas.hxx>
+#include <expfld.hxx>
+#include <docufld.hxx>
+#include <reffld.hxx>
+#include <swundo.hxx>
+#include <doc.hxx>
+#include <frmfmt.hxx>
+#include <fmtfld.hxx>
+#include <view.hxx>
+#include <swevent.hxx>
+#include <section.hxx>
+#include <navicont.hxx>
+#include <txtinet.hxx>
+#include <cmdid.h>
+#include <swabstdlg.hxx>
+#include <SwRewriter.hxx>
+#include <authfld.hxx>
+#include <ndtxt.hxx>
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+
+#include <memory>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <sfx2/event.hxx>
+#include <sal/log.hxx>
+
+bool SwWrtShell::InsertField2(SwField const& rField, SwPaM* pAnnotationRange)
+{
+ ResetCursorStack();
+ if(!CanInsert())
+ return false;
+ StartAllAction();
+
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1, rField.GetDescription());
+
+ StartUndo(SwUndoId::INSERT, &aRewriter);
+
+ bool bDeleted = false;
+ std::optional<SwPaM> pAnnotationTextRange;
+ if (pAnnotationRange)
+ {
+ pAnnotationTextRange.emplace(*pAnnotationRange->Start(), *pAnnotationRange->End());
+ }
+
+ if ( HasSelection() )
+ {
+ if ( rField.GetTyp()->Which() == SwFieldIds::Postit )
+ {
+ // for annotation fields:
+ // - keep the current selection in order to create a corresponding annotation mark
+ // - collapse cursor to its end
+ if ( IsTableMode() )
+ {
+ GetTableCrs()->Normalize( false );
+ const SwPosition rStartPos( *(GetTableCrs()->GetMark()->GetNode().GetContentNode()), 0 );
+ KillPams();
+ if ( !IsEndOfPara() )
+ {
+ EndPara();
+ }
+ const SwPosition rEndPos( *GetCurrentShellCursor().GetPoint() );
+ pAnnotationTextRange.emplace( rStartPos, rEndPos );
+ }
+ else
+ {
+ NormalizePam( false );
+ const SwPaM& rCurrPaM = GetCurrentShellCursor();
+ pAnnotationTextRange.emplace( *rCurrPaM.GetPoint(), *rCurrPaM.GetMark() );
+ ClearMark();
+ }
+ }
+ else
+ {
+ bDeleted = DelRight();
+ }
+ }
+
+ bool const isSuccess = SwEditShell::InsertField(rField, bDeleted);
+
+ if ( pAnnotationTextRange )
+ {
+ if ( GetDoc() != nullptr )
+ {
+ const SwPaM& rCurrPaM = GetCurrentShellCursor();
+ if (*rCurrPaM.Start() == *pAnnotationTextRange->Start()
+ && *rCurrPaM.End() == *pAnnotationTextRange->End())
+ {
+ // Annotation range was passed in externally, and inserting the postit field shifted
+ // its start/end positions right by one. Restore the original position for the range
+ // start. This allows commenting on the placeholder character of the field.
+ if (pAnnotationTextRange->Start()->GetContentIndex() > 0)
+ pAnnotationTextRange->Start()->AdjustContent(-1);
+ }
+ IDocumentMarkAccess* pMarksAccess = GetDoc()->getIDocumentMarkAccess();
+ pMarksAccess->makeAnnotationMark( *pAnnotationTextRange, OUString() );
+ }
+ pAnnotationTextRange.reset();
+ }
+
+ EndUndo();
+ EndAllAction();
+
+ return isSuccess;
+}
+
+// Start the field update
+
+void SwWrtShell::UpdateInputFields( SwInputFieldList* pLst )
+{
+ // Go through the list of fields and updating
+ std::unique_ptr<SwInputFieldList> pTmp;
+ if (!pLst)
+ {
+ pTmp.reset(new SwInputFieldList( this ));
+ pLst = pTmp.get();
+ }
+
+ const size_t nCnt = pLst->Count();
+ if(!nCnt)
+ return;
+
+ pLst->PushCursor();
+
+ bool bCancel = false;
+
+ size_t nIndex = 0;
+ FieldDialogPressedButton ePressedButton = FieldDialogPressedButton::NONE;
+
+ SwField* pField = GetCurField();
+ if (pField)
+ {
+ for (size_t i = 0; i < nCnt; i++)
+ {
+ if (pField == pLst->GetField(i))
+ {
+ nIndex = i;
+ break;
+ }
+ }
+ }
+
+ while (!bCancel)
+ {
+ bool bPrev = nIndex > 0;
+ bool bNext = nIndex < nCnt - 1;
+ pLst->GotoFieldPos(nIndex);
+ pField = pLst->GetField(nIndex);
+ if (pField->GetTyp()->Which() == SwFieldIds::Dropdown)
+ {
+ bCancel = StartDropDownFieldDlg(pField, bPrev, bNext, GetView().GetFrameWeld(), &ePressedButton);
+ }
+ else
+ bCancel = StartInputFieldDlg(pField, bPrev, bNext, GetView().GetFrameWeld(), &ePressedButton);
+
+ if (!bCancel)
+ {
+ // Otherwise update error at multi-selection:
+ pLst->GetField(nIndex)->GetTyp()->UpdateFields();
+
+ if (ePressedButton == FieldDialogPressedButton::Previous && nIndex > 0)
+ nIndex--;
+ else if (ePressedButton == FieldDialogPressedButton::Next && nIndex < nCnt - 1)
+ nIndex++;
+ else
+ bCancel = true;
+ }
+ }
+
+ pLst->PopCursor();
+}
+
+namespace {
+
+// Listener class: will close InputField dialog if input field(s)
+// is(are) deleted (for instance, by an extension) after the dialog shows up.
+// Otherwise, the for loop in SwWrtShell::UpdateInputFields will crash when doing:
+// 'pTmp->GetField( i )->GetTyp()->UpdateFields();'
+// on a deleted field.
+class FieldDeletionListener : public SvtListener
+{
+ public:
+ FieldDeletionListener(AbstractFieldInputDlg* pInputFieldDlg, SwField* pField)
+ : mpInputFieldDlg(pInputFieldDlg)
+ , mpFormatField(nullptr)
+ {
+ SwInputField *const pInputField(dynamic_cast<SwInputField*>(pField));
+ SwSetExpField *const pSetExpField(dynamic_cast<SwSetExpField*>(pField));
+
+ if (pInputField && pInputField->GetFormatField())
+ {
+ mpFormatField = pInputField->GetFormatField();
+ }
+ else if (pSetExpField && pSetExpField->GetFormatField())
+ {
+ mpFormatField = pSetExpField->GetFormatField();
+ }
+
+ // Register for possible field deletion while dialog is open
+ if (mpFormatField)
+ StartListening(mpFormatField->GetNotifier());
+ }
+
+ virtual ~FieldDeletionListener() override
+ {
+ // Dialog closed, remove modification listener
+ EndListeningAll();
+ }
+
+ virtual void Notify(const SfxHint& rHint) override
+ {
+ // Input field has been deleted: better to close the dialog
+ if(rHint.GetId() == SfxHintId::Dying)
+ {
+ mpFormatField = nullptr;
+ mpInputFieldDlg->EndDialog(RET_CANCEL);
+ }
+ }
+ private:
+ VclPtr<AbstractFieldInputDlg> mpInputFieldDlg;
+ SwFormatField* mpFormatField;
+};
+
+}
+
+// Start input dialog for a specific field
+bool SwWrtShell::StartInputFieldDlg(SwField* pField, bool bPrevButton, bool bNextButton,
+ weld::Widget* pParentWin, SwWrtShell::FieldDialogPressedButton* pPressedButton)
+{
+
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractFieldInputDlg> pDlg(pFact->CreateFieldInputDlg(pParentWin, *this, pField, bPrevButton, bNextButton));
+
+ bool bRet;
+
+ {
+ FieldDeletionListener aModify(pDlg.get(), pField);
+ bRet = RET_CANCEL == pDlg->Execute();
+ }
+
+ if (pPressedButton)
+ {
+ if (pDlg->PrevButtonPressed())
+ *pPressedButton = FieldDialogPressedButton::Previous;
+ else if (pDlg->NextButtonPressed())
+ *pPressedButton = FieldDialogPressedButton::Next;
+ }
+
+ pDlg.disposeAndClear();
+ GetWin()->PaintImmediately();
+ return bRet;
+}
+
+bool SwWrtShell::StartDropDownFieldDlg(SwField* pField, bool bPrevButton, bool bNextButton,
+ weld::Widget* pParentWin, SwWrtShell::FieldDialogPressedButton* pPressedButton)
+{
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractDropDownFieldDialog> pDlg(pFact->CreateDropDownFieldDialog(pParentWin, *this, pField, bPrevButton, bNextButton));
+ const short nRet = pDlg->Execute();
+
+ if (pPressedButton)
+ {
+ if (pDlg->PrevButtonPressed())
+ *pPressedButton = FieldDialogPressedButton::Previous;
+ else if (pDlg->NextButtonPressed())
+ *pPressedButton = FieldDialogPressedButton::Next;
+ }
+
+ pDlg.disposeAndClear();
+ bool bRet = RET_CANCEL == nRet;
+ GetWin()->PaintImmediately();
+ if(RET_YES == nRet)
+ {
+ GetView().GetViewFrame().GetDispatcher()->Execute(FN_EDIT_FIELD, SfxCallMode::SYNCHRON);
+ }
+ return bRet;
+}
+
+// Insert directory - remove selection
+
+void SwWrtShell::InsertTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
+{
+ if(!CanInsert())
+ return;
+
+ if(HasSelection())
+ DelRight();
+
+ SwEditShell::InsertTableOf(rTOX, pSet);
+}
+
+// Update directory - remove selection
+
+void SwWrtShell::UpdateTableOf(const SwTOXBase& rTOX, const SfxItemSet* pSet)
+{
+ if(CanInsert())
+ {
+ SwEditShell::UpdateTableOf(rTOX, pSet);
+ }
+}
+
+// handler for click on the field given as parameter.
+// the cursor is positioned on the field.
+
+void SwWrtShell::ClickToField(const SwField& rField, bool bExecHyperlinks)
+{
+ addCurrentPosition();
+
+ // Since the cross reference and bibliography mark move the cursor,
+ // only select the field if it's not a Ctrl+Click
+ if (!bExecHyperlinks
+ || (SwFieldIds::GetRef != rField.GetTyp()->Which()
+ && SwFieldIds::TableOfAuthorities != rField.GetTyp()->Which()))
+ {
+ StartAllAction();
+ Right( SwCursorSkipMode::Chars, true, 1, false ); // Select the field.
+ NormalizePam();
+ EndAllAction();
+ }
+
+ m_bIsInClickToEdit = true;
+ switch( rField.GetTyp()->Which() )
+ {
+ case SwFieldIds::JumpEdit:
+ {
+ sal_uInt16 nSlotId = 0;
+ switch( rField.GetFormat() )
+ {
+ case JE_FMT_TABLE:
+ nSlotId = FN_INSERT_TABLE;
+ break;
+
+ case JE_FMT_FRAME:
+ nSlotId = FN_INSERT_FRAME;
+ break;
+
+ case JE_FMT_GRAPHIC: nSlotId = SID_INSERT_GRAPHIC; break;
+ case JE_FMT_OLE: nSlotId = SID_INSERT_OBJECT; break;
+
+ }
+
+ if( nSlotId )
+ {
+ StartUndo( SwUndoId::START );
+ //#97295# immediately select the right shell
+ GetView().StopShellTimer();
+ GetView().GetViewFrame().GetDispatcher()->Execute( nSlotId,
+ SfxCallMode::SYNCHRON|SfxCallMode::RECORD );
+ EndUndo( SwUndoId::END );
+ }
+ }
+ break;
+
+ case SwFieldIds::Macro:
+ {
+ const SwMacroField *pField = static_cast<const SwMacroField*>(&rField);
+ const OUString sText( rField.GetPar2() );
+ OUString sRet( sText );
+ ExecMacro( pField->GetSvxMacro(), &sRet );
+
+ // return value changed?
+ if( sRet != sText )
+ {
+ StartAllAction();
+ const_cast<SwField&>(rField).SetPar2( sRet );
+ rField.GetTyp()->UpdateFields();
+ EndAllAction();
+ }
+ }
+ break;
+
+ case SwFieldIds::TableOfAuthorities:
+ {
+ if (!bExecHyperlinks)
+ break; // Since it's not a Ctrl+Click, do not jump anywhere
+
+ Point vStartPoint = GetCursor_()->GetPtPos();
+ const SwAuthorityField* pField = static_cast<const SwAuthorityField*>(&rField);
+
+ if (auto targetType = pField->GetTargetType();
+ targetType == SwAuthorityField::TargetType::UseDisplayURL
+ || targetType == SwAuthorityField::TargetType::UseTargetURL)
+ {
+ // Since the user selected target type with URL, try to use it if not empty
+ if (const OUString& rURL = pField->GetAbsoluteURL();
+ rURL.getLength() > 0)
+ ::LoadURL(*this, rURL, LoadUrlFlags::NewView, /*rTargetFrameName=*/OUString());
+ }
+ else if (targetType == SwAuthorityField::TargetType::BibliographyTableRow)
+ {
+ // Since the user selected to target Bibliography Table Row,
+ // try finding matching bibliography table line
+
+ const bool bWasViewLocked = IsViewLocked();
+ LockView(true);
+
+ // Note: This way of iterating doesn't seem to take into account TOXes
+ // that are in a frame, probably in some other cases too
+ GotoPage(1);
+ while (GotoNextTOXBase())
+ {
+ const SwTOXBase* pIteratedTOX = nullptr;
+ const SwTOXBase* pPreviousTOX = nullptr;
+ OUString vFieldText;
+ while ((pIteratedTOX = GetCurTOX()) != nullptr
+ && pIteratedTOX->GetType() == TOX_AUTHORITIES)
+ {
+ if (pIteratedTOX != pPreviousTOX)
+ vFieldText = pField->GetAuthority(GetLayout(), &pIteratedTOX->GetTOXForm());
+
+ if (const SwNode& rCurrentNode = GetCursor()->GetPoint()->GetNode();
+ rCurrentNode.GetNodeType() == SwNodeType::Text
+ && (GetCursor()->GetPoint()->GetNode().FindSectionNode()->GetSection().GetType()
+ == SectionType::ToxContent) // this checks it's not a heading
+ && static_cast<const SwTextNode*>(&rCurrentNode)->GetText() == vFieldText)
+ {
+ // Since a node has been found that is a text node, isn't a heading,
+ // and has text matching to text generated by the field, jump to it
+ LockView(bWasViewLocked);
+ ShowCursor();
+ return;
+ }
+ pPreviousTOX = pIteratedTOX;
+ FwdPara();
+ }
+ }
+ // Since a matching node has not been found, return to original position
+ SetCursor(&vStartPoint);
+ LockView(bWasViewLocked);
+ }
+ }
+ break;
+
+ case SwFieldIds::GetRef:
+ if (!bExecHyperlinks)
+ break;
+
+ StartAllAction();
+ SwCursorShell::GotoRefMark( static_cast<const SwGetRefField&>(rField).GetSetRefName(),
+ static_cast<const SwGetRefField&>(rField).GetSubType(),
+ static_cast<const SwGetRefField&>(rField).GetSeqNo(),
+ static_cast<const SwGetRefField&>(rField).GetFlags() );
+ EndAllAction();
+ break;
+
+ case SwFieldIds::Input:
+ {
+ const SwInputField* pInputField = dynamic_cast<const SwInputField*>(&rField);
+ if ( pInputField == nullptr )
+ {
+ StartInputFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
+ }
+ }
+ break;
+
+ case SwFieldIds::SetExp:
+ if( static_cast<const SwSetExpField&>(rField).GetInputFlag() )
+ StartInputFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
+ break;
+ case SwFieldIds::Dropdown :
+ StartDropDownFieldDlg(const_cast<SwField*>(&rField), false, false, GetView().GetFrameWeld());
+ break;
+ default:
+ SAL_WARN_IF(rField.IsClickable(), "sw", "unhandled clickable field!");
+ }
+
+ m_bIsInClickToEdit = false;
+}
+
+void SwWrtShell::ClickToINetAttr( const SwFormatINetFormat& rItem, LoadUrlFlags nFilter )
+{
+ addCurrentPosition();
+
+ if( rItem.GetValue().isEmpty() )
+ return ;
+
+ m_bIsInClickToEdit = true;
+
+ // At first run the possibly set ObjectSelect Macro
+ const SvxMacro* pMac = rItem.GetMacro( SvMacroItemId::OnClick );
+ if( pMac )
+ {
+ SwCallMouseEvent aCallEvent;
+ aCallEvent.Set( &rItem );
+ GetDoc()->CallEvent( SvMacroItemId::OnClick, aCallEvent );
+ }
+
+ // So that the implementation of templates is displayed immediately
+ ::LoadURL( *this, rItem.GetValue(), nFilter, rItem.GetTargetFrame() );
+ const SwTextINetFormat* pTextAttr = rItem.GetTextINetFormat();
+ if( pTextAttr )
+ {
+ const_cast<SwTextINetFormat*>(pTextAttr)->SetVisited( true );
+ const_cast<SwTextINetFormat*>(pTextAttr)->SetVisitedValid( true );
+ }
+
+ m_bIsInClickToEdit = false;
+}
+
+bool SwWrtShell::ClickToINetGrf( const Point& rDocPt, LoadUrlFlags nFilter )
+{
+ bool bRet = false;
+ OUString sURL;
+ OUString sTargetFrameName;
+ const SwFrameFormat* pFnd = IsURLGrfAtPos( rDocPt, &sURL, &sTargetFrameName );
+ if( pFnd && !sURL.isEmpty() )
+ {
+ bRet = true;
+ // At first run the possibly set ObjectSelect Macro
+ SwCallMouseEvent aCallEvent;
+ aCallEvent.Set(EVENT_OBJECT_URLITEM, pFnd);
+ GetDoc()->CallEvent(SvMacroItemId::OnClick, aCallEvent);
+
+ ::LoadURL(*this, sURL, nFilter, sTargetFrameName);
+ }
+ return bRet;
+}
+
+static void LoadURL(SwView& rView, const OUString& rURL, LoadUrlFlags nFilter,
+ const OUString& rTargetFrameName)
+{
+ SwDocShell* pDShell = rView.GetDocShell();
+ OSL_ENSURE( pDShell, "No DocShell?!");
+ SfxViewFrame& rViewFrame = rView.GetViewFrame();
+
+ if (!SfxObjectShell::AllowedLinkProtocolFromDocument(rURL, pDShell, rViewFrame.GetFrameWeld()))
+ return;
+
+ // We are doing tiledRendering, let the client handles the URL loading,
+ // unless we are jumping to a TOC mark.
+ if (comphelper::LibreOfficeKit::isActive() && !rURL.startsWith("#"))
+ {
+ rView.libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, rURL.toUtf8());
+ return;
+ }
+
+ OUString sTargetFrame(rTargetFrameName);
+ if (sTargetFrame.isEmpty() && pDShell)
+ {
+ using namespace ::com::sun::star;
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ pDShell->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps
+ = xDPS->getDocumentProperties();
+ sTargetFrame = xDocProps->getDefaultTarget();
+ }
+
+ OUString sReferer;
+ if( pDShell && pDShell->GetMedium() )
+ sReferer = pDShell->GetMedium()->GetName();
+ SfxFrameItem aView( SID_DOCFRAME, &rViewFrame );
+ SfxStringItem aName( SID_FILE_NAME, rURL );
+ SfxStringItem aTargetFrameName( SID_TARGETNAME, sTargetFrame );
+ SfxStringItem aReferer( SID_REFERER, sReferer );
+
+ SfxBoolItem aNewView( SID_OPEN_NEW_VIEW, false );
+ //#39076# Silent can be removed accordingly to SFX.
+ SfxBoolItem aBrowse( SID_BROWSE, true );
+
+ if ((nFilter & LoadUrlFlags::NewView) && !comphelper::LibreOfficeKit::isActive())
+ aTargetFrameName.SetValue( "_blank" );
+
+ rViewFrame.GetDispatcher()->ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON|SfxCallMode::RECORD,
+ {
+ &aName,
+ &aNewView, /*&aSilent,*/
+ &aReferer,
+ &aView, &aTargetFrameName,
+ &aBrowse
+ });
+}
+
+void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
+ const OUString& rTargetFrameName )
+{
+ OSL_ENSURE( !rURL.isEmpty(), "what should be loaded here?" );
+ if( rURL.isEmpty() )
+ return ;
+
+ // The shell could be 0 also!!!!!
+ if (auto pSh = dynamic_cast<SwWrtShell*>(&rVSh))
+ ::LoadURL(pSh->GetView(), rURL, nFilter, rTargetFrameName);
+}
+
+void SwWrtShell::NavigatorPaste( const NaviContentBookmark& rBkmk,
+ const sal_uInt16 nAction )
+{
+ if( EXCHG_IN_ACTION_COPY == nAction )
+ {
+ // Insert
+ OUString sURL = rBkmk.GetURL();
+ // Is this is a jump within the current Doc?
+ const SwDocShell* pDocShell = GetView().GetDocShell();
+ if(pDocShell->HasName())
+ {
+ const OUString rName = pDocShell->GetMedium()->GetURLObject().GetURLNoMark();
+
+ if (sURL.startsWith(rName))
+ {
+ if (sURL.getLength()>rName.getLength())
+ {
+ sURL = sURL.copy(rName.getLength());
+ }
+ else
+ {
+ sURL.clear();
+ }
+ }
+ }
+ SwFormatINetFormat aFormat( sURL, OUString() );
+ InsertURL( aFormat, rBkmk.GetDescription() );
+ }
+ else
+ {
+ SwSectionData aSection( SectionType::FileLink, GetUniqueSectionName() );
+ OUString aLinkFile = o3tl::getToken(rBkmk.GetURL(), 0, '#')
+ + OUStringChar(sfx2::cTokenSeparator)
+ + OUStringChar(sfx2::cTokenSeparator)
+ + o3tl::getToken(rBkmk.GetURL(), 1, '#');
+ aSection.SetLinkFileName( aLinkFile );
+ aSection.SetProtectFlag( true );
+ const SwSection* pIns = InsertSection( aSection );
+ if( EXCHG_IN_ACTION_MOVE == nAction && pIns )
+ {
+ aSection = SwSectionData(*pIns);
+ aSection.SetLinkFileName( OUString() );
+ aSection.SetType( SectionType::Content );
+ aSection.SetProtectFlag( false );
+
+ // the update of content from linked section at time delete
+ // the undostack. Then the change of the section don't create
+ // any undoobject. - BUG 69145
+ bool bDoesUndo = DoesUndo();
+ SwUndoId nLastUndoId(SwUndoId::EMPTY);
+ if (GetLastUndoInfo(nullptr, & nLastUndoId))
+ {
+ if (SwUndoId::INSSECTION != nLastUndoId)
+ {
+ DoUndo(false);
+ }
+ }
+ UpdateSection( GetSectionFormatPos( *pIns->GetFormat() ), aSection );
+ DoUndo( bDoesUndo );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/wrtsh/wrtsh3.cxx b/sw/source/uibase/wrtsh/wrtsh3.cxx
new file mode 100644
index 0000000000..0907794d7c
--- /dev/null
+++ b/sw/source/uibase/wrtsh/wrtsh3.cxx
@@ -0,0 +1,392 @@
+/* -*- 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 <svx/svxids.hrc>
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdview.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/srchdlg.hxx>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/diagnose.h>
+#include <sfx2/dispatch.hxx>
+#include <comphelper/lok.hxx>
+#include <tools/json_writer.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+#include <swmodule.hxx>
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <IMark.hxx>
+#include <doc.hxx>
+#include <formatcontentcontrol.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <SwRewriter.hxx>
+#include <strings.hrc>
+#include <textcontentcontrol.hxx>
+
+using namespace ::com::sun::star;
+
+bool SwWrtShell::MoveBookMark( BookMarkMove eFuncId, const ::sw::mark::IMark* const pMark)
+{
+ addCurrentPosition();
+ (this->*m_fnKillSel)( nullptr, false );
+
+ bool bRet = true;
+ switch(eFuncId)
+ {
+ case BOOKMARK_INDEX:bRet = SwCursorShell::GotoMark( pMark );break;
+ case BOOKMARK_NEXT: bRet = SwCursorShell::GoNextBookmark();break;
+ case BOOKMARK_PREV: bRet = SwCursorShell::GoPrevBookmark();break;
+ default:;//prevent warning
+ }
+
+ if( bRet && IsSelFrameMode() )
+ {
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ }
+ if( IsSelection() )
+ {
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ }
+ return bRet;
+}
+
+bool SwWrtShell::GotoField( const SwFormatField& rField )
+{
+ (this->*m_fnKillSel)( nullptr, false );
+
+ bool bRet = SwCursorShell::GotoFormatField( rField );
+ if( bRet && IsSelFrameMode() )
+ {
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ }
+
+ if( IsSelection() )
+ {
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ }
+
+ return bRet;
+}
+
+bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentControl,
+ bool bOnlyRefresh)
+{
+ std::shared_ptr<SwContentControl> pContentControl = rContentControl.GetContentControl();
+ if (IsFrameSelected() && pContentControl && pContentControl->GetPicture())
+ {
+ // A frame is already selected, and its anchor is inside a picture content control.
+ if (pContentControl->GetShowingPlaceHolder())
+ {
+ // Replace the placeholder image with a real one.
+ GetView().StopShellTimer();
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ tools::JsonWriter aJson;
+ aJson.put("action", "change-picture");
+ OString pJson(aJson.finishAndGetAsOString());
+ GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_CONTENT_CONTROL,
+ pJson);
+ }
+ else
+ {
+ GetView().GetViewFrame().GetDispatcher()->Execute(SID_CHANGE_PICTURE,
+ SfxCallMode::SYNCHRON);
+ }
+ pContentControl->SetShowingPlaceHolder(false);
+ }
+ return true;
+ }
+
+ (this->*m_fnKillSel)(nullptr, false);
+
+ bool bRet = SwCursorShell::GotoFormatContentControl(rContentControl);
+
+ if (bRet && pContentControl && pContentControl->GetCheckbox())
+ {
+ // Checkbox: GotoFormatContentControl() selected the old state.
+ LockView(/*bViewLocked=*/true);
+ OUString aOldState = GetCursorDescr();
+ OUString aNewState;
+ if (pContentControl->GetChecked())
+ aNewState = bOnlyRefresh ? pContentControl->GetCheckedState()
+ : pContentControl->GetUncheckedState();
+ else
+ aNewState = bOnlyRefresh ? pContentControl->GetUncheckedState()
+ : pContentControl->GetCheckedState();
+
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1, aOldState);
+ aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
+ aRewriter.AddRule(UndoArg3, aNewState);
+ GetIDocumentUndoRedo().StartUndo(SwUndoId::REPLACE, &aRewriter);
+
+ // Toggle the state.
+ pContentControl->SetReadWrite(true);
+ DelLeft();
+ if (!bOnlyRefresh)
+ pContentControl->SetChecked(!pContentControl->GetChecked());
+ Insert(aNewState);
+ pContentControl->SetReadWrite(false);
+
+ GetIDocumentUndoRedo().EndUndo(SwUndoId::REPLACE, &aRewriter);
+ LockView(/*bViewLocked=*/false);
+ ShowCursor();
+ }
+ else if (bRet && pContentControl && pContentControl->GetSelectedListItem())
+ {
+ // Dropdown: GotoFormatContentControl() selected the old content.
+ size_t nSelectedListItem = *pContentControl->GetSelectedListItem();
+ LockView(/*bViewLocked=*/true);
+ OUString aOldState = GetCursorDescr();
+ OUString aNewState = pContentControl->GetListItems()[nSelectedListItem].ToString();
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1, aOldState);
+ aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
+ aRewriter.AddRule(UndoArg3, SwResId(STR_START_QUOTE) + aNewState + SwResId(STR_END_QUOTE));
+ GetIDocumentUndoRedo().StartUndo(SwUndoId::REPLACE, &aRewriter);
+
+ // Update the content.
+ pContentControl->SetReadWrite(true);
+ DelLeft();
+ pContentControl->SetSelectedListItem(std::nullopt);
+ Insert(aNewState);
+ pContentControl->SetReadWrite(false);
+
+ GetIDocumentUndoRedo().EndUndo(SwUndoId::REPLACE, &aRewriter);
+ LockView(/*bViewLocked=*/false);
+ ShowCursor();
+ }
+ else if (bRet && pContentControl && pContentControl->GetSelectedDate())
+ {
+ // Date: GotoFormatContentControl() selected the old content.
+ LockView(/*bViewLocked=*/true);
+ OUString aOldState = GetCursorDescr();
+ OUString aNewState = pContentControl->GetDateString();
+ SwRewriter aRewriter;
+ aRewriter.AddRule(UndoArg1, aOldState);
+ aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
+ aRewriter.AddRule(UndoArg3, SwResId(STR_START_QUOTE) + aNewState + SwResId(STR_END_QUOTE));
+ GetIDocumentUndoRedo().StartUndo(SwUndoId::REPLACE, &aRewriter);
+
+ // Write the doc model.
+ pContentControl->SetCurrentDateValue(*pContentControl->GetSelectedDate());
+ pContentControl->SetSelectedDate(std::nullopt);
+
+ // Update the content.
+ DelLeft();
+ Insert(aNewState);
+
+ GetIDocumentUndoRedo().EndUndo(SwUndoId::REPLACE, &aRewriter);
+ LockView(/*bViewLocked=*/false);
+ ShowCursor();
+ }
+
+ if (bRet && IsSelFrameMode())
+ {
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ }
+
+ if (IsSelection())
+ {
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ }
+
+ return bRet;
+}
+
+bool SwWrtShell::GotoFieldmark(::sw::mark::IFieldmark const * const pMark)
+{
+ (this->*m_fnKillSel)( nullptr, false );
+ bool bRet = SwCursorShell::GotoFieldmark(pMark);
+ if( bRet && IsSelFrameMode() )
+ {
+ UnSelectFrame();
+ LeaveSelFrameMode();
+ }
+ if( IsSelection() )
+ {
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ }
+ return bRet;
+}
+
+// Invalidate FontWork-Slots
+
+void SwWrtShell::DrawSelChanged( )
+{
+ static sal_uInt16 const aInval[] =
+ {
+ SID_ATTR_FILL_STYLE, SID_ATTR_FILL_COLOR, SID_ATTR_LINE_STYLE,
+ SID_ATTR_LINE_WIDTH, SID_ATTR_LINE_COLOR,
+ /*AF: these may be needed for the sidebar.
+ SID_SVX_AREA_TRANSPARENCY, SID_SVX_AREA_TRANSP_GRADIENT,
+ SID_SVX_AREA_TRANS_TYPE,
+ */
+ 0
+ };
+
+ GetView().GetViewFrame().GetBindings().Invalidate(aInval);
+
+ bool bOldVal = g_bNoInterrupt;
+ g_bNoInterrupt = true; // Trick to run AttrChangedNotify by timer.
+ GetView().AttrChangedNotify(nullptr);
+ g_bNoInterrupt = bOldVal;
+}
+
+void SwWrtShell::GotoMark( const OUString& rName )
+{
+ IDocumentMarkAccess::const_iterator_t ppMark = getIDocumentMarkAccess()->findMark( rName );
+ if (ppMark == getIDocumentMarkAccess()->getAllMarksEnd())
+ return;
+ MoveBookMark( BOOKMARK_INDEX, *ppMark );
+}
+
+void SwWrtShell::GotoMark( const ::sw::mark::IMark* const pMark )
+{
+ MoveBookMark( BOOKMARK_INDEX, pMark );
+}
+
+bool SwWrtShell::GoNextBookmark()
+{
+ if ( !getIDocumentMarkAccess()->getBookmarksCount() )
+ {
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
+ return false;
+ }
+ LockView( true );
+ bool bRet = MoveBookMark( BOOKMARK_NEXT );
+ if ( !bRet )
+ {
+ MoveBookMark( BOOKMARK_INDEX, *getIDocumentMarkAccess()->getBookmarksBegin() );
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::EndWrapped );
+ }
+ else
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
+ LockView( false );
+ ShowCursor();
+ return true;
+}
+
+bool SwWrtShell::GoPrevBookmark()
+{
+ if ( !getIDocumentMarkAccess()->getBookmarksCount() )
+ {
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
+ return false;
+ }
+ LockView( true );
+ bool bRet = MoveBookMark( BOOKMARK_PREV );
+ if ( !bRet )
+ {
+ MoveBookMark( BOOKMARK_INDEX, *( getIDocumentMarkAccess()->getBookmarksEnd() - 1 ) );
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::StartWrapped );
+ }
+ else
+ SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::Empty );
+ LockView( false );
+ ShowCursor();
+ return true;
+}
+
+void SwWrtShell::ExecMacro( const SvxMacro& rMacro, OUString* pRet, SbxArray* pArgs )
+{
+ // execute macro, if it is allowed.
+ if ( IsMacroExecAllowed() )
+ {
+ GetDoc()->ExecMacro( rMacro, pRet, pArgs );
+ }
+}
+
+sal_uInt16 SwWrtShell::CallEvent( SvMacroItemId nEvent, const SwCallMouseEvent& rCallEvent,
+ bool bChkPtr)
+{
+ return GetDoc()->CallEvent( nEvent, rCallEvent, bChkPtr );
+}
+
+ // If a util::URL-Button is selected, return its util::URL
+ // otherwise an empty string.
+bool SwWrtShell::GetURLFromButton( OUString& rURL, OUString& rDescr ) const
+{
+ bool bRet = false;
+ const SdrView *pDView = GetDrawView();
+ if( pDView )
+ {
+ // A fly is precisely achievable if it is selected.
+ const SdrMarkList &rMarkList = pDView->GetMarkedObjectList();
+
+ if (rMarkList.GetMark(0))
+ {
+ SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( rMarkList.GetMark(0)->GetMarkedSdrObj() );
+ if (pUnoCtrl && SdrInventor::FmForm == pUnoCtrl->GetObjInventor())
+ {
+ const uno::Reference< awt::XControlModel >& xControlModel = pUnoCtrl->GetUnoControlModel();
+
+ OSL_ENSURE( xControlModel.is(), "UNO-Control without Model" );
+ if( !xControlModel.is() )
+ return bRet;
+
+ uno::Reference< beans::XPropertySet > xPropSet(xControlModel, uno::UNO_QUERY);
+
+ uno::Any aTmp;
+
+ uno::Reference< beans::XPropertySetInfo > xInfo = xPropSet->getPropertySetInfo();
+ if(xInfo->hasPropertyByName( "ButtonType" ))
+ {
+ aTmp = xPropSet->getPropertyValue( "ButtonType" );
+ form::FormButtonType eTmpButtonType;
+ aTmp >>= eTmpButtonType;
+ if( form::FormButtonType_URL == eTmpButtonType)
+ {
+ // Label
+ aTmp = xPropSet->getPropertyValue( "Label" );
+ OUString uTmp;
+ if( (aTmp >>= uTmp) && !uTmp.isEmpty())
+ {
+ rDescr = uTmp;
+ }
+
+ // util::URL
+ aTmp = xPropSet->getPropertyValue( "TargetURL" );
+ if( (aTmp >>= uTmp) && !uTmp.isEmpty())
+ {
+ rURL = uTmp;
+ }
+ bRet = true;
+ }
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/wrtsh/wrtsh4.cxx b/sw/source/uibase/wrtsh/wrtsh4.cxx
new file mode 100644
index 0000000000..0442e3152b
--- /dev/null
+++ b/sw/source/uibase/wrtsh/wrtsh4.cxx
@@ -0,0 +1,253 @@
+/* -*- 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 <wrtsh.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+// Private methods, which move the cursor over search.
+// The removal of the selection must be made on the level above.
+
+// The beginning of a word is the follow of a
+// non-delimiter to delimiter. Furthermore, the follow of
+// non-sentence separators on sentence separator.
+// The begin of paragraph is also the word beginning.
+
+void SwWrtShell::SttWrd()
+{
+ if ( IsSttPara() )
+ return;
+ // Create temporary cursor without selection.
+ Push();
+ ClearMark();
+ if( !GoStartWord() )
+ // not found --> go to the beginning of the paragraph.
+ SwCursorShell::MovePara( GoCurrPara, fnParaStart );
+ ClearMark();
+ // If Mark was previously set, summarize.
+ Combine();
+}
+
+// The end of a word is the follow of separator to nonseparator.
+// The end of a word is also the sequence of word separators to
+// punctuation marks.
+// The end of a paragraph is also the end of a word.
+
+void SwWrtShell::EndWrd()
+{
+ if ( IsEndWrd() )
+ return;
+ // Create temporary cursor without selection.
+ Push();
+ ClearMark();
+ if( !GoEndWord() )
+ // not found --> go to the end of the paragraph.
+ SwCursorShell::MovePara(GoCurrPara, fnParaEnd);
+ ClearMark();
+ // If Mark was previously set, summarize.
+ Combine();
+}
+
+bool SwWrtShell::NxtWrd_()
+{
+ bool bRet = false;
+ while( IsEndPara() ) // If already at the end, then the next???
+ {
+ if(!SwCursorShell::Right(1,SwCursorSkipMode::Chars)) // Document - end ??
+ {
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ return bRet;
+ }
+ bRet = IsStartWord();
+ }
+ Push();
+ ClearMark();
+ while( !bRet )
+ {
+ if( !GoNextWord() )
+ {
+ if( (!IsEndPara() && !SwCursorShell::MovePara( GoCurrPara, fnParaEnd ) )
+ || !SwCursorShell::Right(1,SwCursorSkipMode::Chars) )
+ break;
+ bRet = IsStartWord();
+ }
+ else
+ bRet = true;
+ }
+ ClearMark();
+ Combine();
+ return bRet;
+}
+
+bool SwWrtShell::PrvWrd_()
+{
+ bool bRet = false;
+ while( IsSttPara() )
+ { // if already at the beginning, then the next???
+ if(!SwCursorShell::Left(1,SwCursorSkipMode::Chars))
+ { // Document - beginning ??
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ return bRet;
+ }
+ bRet = IsStartWord() || IsEndPara();
+ }
+ Push();
+ ClearMark();
+ while( !bRet )
+ {
+ if( !GoPrevWord() )
+ {
+ if( (!IsSttPara() && !SwCursorShell::MovePara( GoCurrPara, fnParaStart ) )
+ || !SwCursorShell::Left(1,SwCursorSkipMode::Chars) )
+ break;
+ bRet = IsStartWord();
+ }
+ else
+ bRet = true;
+ }
+ ClearMark();
+ Combine();
+ return bRet;
+}
+
+// #i92468#
+// method code of <SwWrtShell::NxtWrd_()> before fix for issue i72162
+bool SwWrtShell::NxtWrdForDelete()
+{
+ if ( IsEndPara() )
+ {
+ if ( !SwCursorShell::Right(1,SwCursorSkipMode::Chars) )
+ {
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ return false;
+ }
+ return true;
+ }
+ Push();
+ ClearMark();
+ if ( !GoNextWord() )
+ {
+ SwCursorShell::MovePara( GoCurrPara, fnParaEnd );
+ }
+ ClearMark();
+ Combine();
+ return true;
+}
+
+// method code of <SwWrtShell::PrvWrd_()> before fix for issue i72162
+bool SwWrtShell::PrvWrdForDelete()
+{
+ if ( IsSttPara() )
+ {
+ if ( !SwCursorShell::Left(1,SwCursorSkipMode::Chars) )
+ {
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ return false;
+ }
+ return true;
+ }
+ Push();
+ ClearMark();
+ if( !GoPrevWord() )
+ {
+ SwCursorShell::MovePara( GoCurrPara, fnParaStart );
+ }
+ ClearMark();
+ Combine();
+ return true;
+}
+
+bool SwWrtShell::FwdSentence_()
+{
+ Push();
+ ClearMark();
+ if(!SwCursorShell::Right(1,SwCursorSkipMode::Chars))
+ {
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ return false;
+ }
+ if( !GoNextSentence() && !IsEndPara() )
+ SwCursorShell::MovePara(GoCurrPara, fnParaEnd);
+
+ ClearMark();
+ Combine();
+ return true;
+}
+
+bool SwWrtShell::BwdSentence_()
+{
+ Push();
+ ClearMark();
+ if(!SwCursorShell::Left(1,SwCursorSkipMode::Chars))
+ {
+ Pop(SwCursorShell::PopMode::DeleteCurrent);
+ return false;
+ }
+ if( !GoStartSentence() && !IsSttPara() )
+ // not found --> go to the beginning of the paragraph
+ SwCursorShell::MovePara( GoCurrPara, fnParaStart );
+ ClearMark();
+ Combine();
+ return true;
+}
+
+bool SwWrtShell::FwdPara_()
+{
+ Push();
+ ClearMark();
+ bool bRet = SwCursorShell::MovePara(GoNextPara, fnParaStart);
+
+ ClearMark();
+ Combine();
+ return bRet;
+}
+
+bool SwWrtShell::BwdPara_()
+{
+ Push();
+ ClearMark();
+
+ bool bRet = SwCursorShell::MovePara(GoPrevPara, fnParaStart);
+ if ( !bRet && !IsSttOfPara() )
+ {
+ SttPara();
+ }
+
+ ClearMark();
+ Combine();
+ return bRet;
+}
+
+std::optional<OString> SwWrtShell::getLOKPayload(int nType, int nViewId) const
+{
+ switch(nType)
+ {
+ case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+ case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
+ return GetVisibleCursor()->getLOKPayload(nType, nViewId);
+ case LOK_CALLBACK_TEXT_SELECTION:
+ case LOK_CALLBACK_TEXT_SELECTION_START:
+ case LOK_CALLBACK_TEXT_SELECTION_END:
+ case LOK_CALLBACK_TEXT_VIEW_SELECTION:
+ return GetCursor_()->getLOKPayload(nType, nViewId);
+ }
+ abort();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/wrtsh/wrtundo.cxx b/sw/source/uibase/wrtsh/wrtundo.cxx
new file mode 100644
index 0000000000..770c59367a
--- /dev/null
+++ b/sw/source/uibase/wrtsh/wrtundo.cxx
@@ -0,0 +1,151 @@
+/* -*- 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/slstitm.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <wrtsh.hxx>
+#include <swundo.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <swdtflvr.hxx>
+#include <svtools/svtresid.hxx>
+#include <svtools/strings.hrc>
+#include <osl/diagnose.h>
+
+// Undo ends all modes. If a selection is emerged by the Undo,
+// this must be considered for further action.
+
+void SwWrtShell::Do(DoType eDoType, sal_uInt16 nCnt, sal_uInt16 nOffset)
+{
+ // #105332# save current state of DoesUndo()
+ bool bSaveDoesUndo = DoesUndo();
+
+ StartAllAction();
+ switch (eDoType)
+ {
+ case UNDO:
+ DoUndo(false); // #i21739#
+ // Reset modes
+ EnterStdMode();
+ SwEditShell::Undo(nCnt, nOffset);
+ break;
+ case REDO:
+ DoUndo(false); // #i21739#
+ // Reset modes
+ EnterStdMode();
+ SwEditShell::Redo( nCnt );
+ break;
+ case REPEAT:
+ // #i21739# do not touch undo flag here !!!
+ SwEditShell::Repeat( nCnt );
+ break;
+ }
+ EndAllAction();
+ // #105332# restore undo state
+ DoUndo(bSaveDoesUndo);
+
+ bool bCreateXSelection = false;
+ const bool bFrameSelected = IsFrameSelected() || IsObjSelected();
+ if ( IsSelection() )
+ {
+ if ( bFrameSelected )
+ UnSelectFrame();
+
+ // Set the function pointer for canceling the selection at the
+ // cursor position.
+ m_fnKillSel = &SwWrtShell::ResetSelect;
+ m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
+ bCreateXSelection = true;
+ }
+ else if ( bFrameSelected )
+ {
+ EnterSelFrameMode();
+ bCreateXSelection = true;
+ }
+ else if( (CNT_GRF | CNT_OLE ) & GetCntType() )
+ {
+ SelectObj( GetCharRect().Pos() );
+ EnterSelFrameMode();
+ bCreateXSelection = true;
+ }
+
+ if( bCreateXSelection )
+ SwTransferable::CreateSelection( *this );
+
+ // Bug 32918: After deleting of the numbering the object panel remains.
+ // Why is not here always a CallChgLink called?
+ CallChgLnk();
+}
+
+OUString SwWrtShell::GetDoString( DoType eDoType ) const
+{
+ OUString aUndoStr;
+ TranslateId pResStr = STR_UNDO;
+ switch( eDoType )
+ {
+ case UNDO:
+ pResStr = STR_UNDO;
+ (void)GetLastUndoInfo(&aUndoStr, nullptr, &m_rView);
+ break;
+ case REDO:
+ pResStr = STR_REDO;
+ (void)GetFirstRedoInfo(&aUndoStr, nullptr, &m_rView);
+ break;
+ default:;//prevent warning
+ }
+
+ return SvtResId(pResStr) + aUndoStr;
+}
+
+void SwWrtShell::GetDoStrings( DoType eDoType, SfxStringListItem& rStrs ) const
+{
+ SwUndoComments_t comments;
+ switch( eDoType )
+ {
+ case UNDO:
+ comments = GetIDocumentUndoRedo().GetUndoComments();
+ break;
+ case REDO:
+ comments = GetIDocumentUndoRedo().GetRedoComments();
+ break;
+ default:;//prevent warning
+ }
+
+ OUStringBuffer buf;
+ for (const OUString & comment : comments)
+ {
+ OSL_ENSURE(!comment.isEmpty(), "no Undo/Redo Text set");
+ buf.append(comment + "\n");
+ }
+ rStrs.SetString(buf.makeStringAndClear());
+}
+
+OUString SwWrtShell::GetRepeatString() const
+{
+ OUString str;
+ GetRepeatInfo(& str);
+
+ if (str.isEmpty())
+ {
+ return str;
+ }
+
+ return SvtResId(STR_REPEAT) + str;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */