summaryrefslogtreecommitdiff
path: root/sw/source
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source')
-rw-r--r--sw/source/core/attr/swatrset.cxx3
-rw-r--r--sw/source/core/bastyp/swrect.cxx12
-rw-r--r--sw/source/core/crsr/annotationmark.cxx2
-rw-r--r--sw/source/core/crsr/bookmrk.cxx45
-rw-r--r--sw/source/core/crsr/crbm.cxx15
-rw-r--r--sw/source/core/crsr/crsrsh.cxx9
-rw-r--r--sw/source/core/crsr/crstrvl.cxx64
-rw-r--r--sw/source/core/crsr/swcrsr.cxx4
-rw-r--r--sw/source/core/crsr/viscrs.cxx2
-rw-r--r--sw/source/core/doc/DocumentContentOperationsManager.cxx131
-rw-r--r--sw/source/core/doc/DocumentFieldsManager.cxx13
-rw-r--r--sw/source/core/doc/DocumentRedlineManager.cxx10
-rw-r--r--sw/source/core/doc/DocumentStylePoolManager.cxx2
-rw-r--r--sw/source/core/doc/docbm.cxx38
-rw-r--r--sw/source/core/doc/docchart.cxx23
-rw-r--r--sw/source/core/doc/docedt.cxx11
-rw-r--r--sw/source/core/doc/docfld.cxx58
-rw-r--r--sw/source/core/doc/doclay.cxx11
-rw-r--r--sw/source/core/doc/docnew.cxx27
-rw-r--r--sw/source/core/doc/docredln.cxx2
-rw-r--r--sw/source/core/doc/tblafmt.cxx2
-rw-r--r--sw/source/core/doc/textboxhelper.cxx3
-rw-r--r--sw/source/core/docnode/ndsect.cxx2
-rw-r--r--sw/source/core/docnode/ndtbl.cxx6
-rw-r--r--sw/source/core/docnode/node.cxx6
-rw-r--r--sw/source/core/docnode/nodes.cxx182
-rw-r--r--sw/source/core/draw/dcontact.cxx69
-rw-r--r--sw/source/core/draw/dview.cxx5
-rw-r--r--sw/source/core/edit/acorrect.cxx5
-rw-r--r--sw/source/core/edit/autofmt.cxx39
-rw-r--r--sw/source/core/edit/edatmisc.cxx2
-rw-r--r--sw/source/core/edit/eddel.cxx9
-rw-r--r--sw/source/core/edit/edfld.cxx11
-rw-r--r--sw/source/core/edit/edglbldc.cxx2
-rw-r--r--sw/source/core/edit/editsh.cxx4
-rw-r--r--sw/source/core/edit/edlingu.cxx19
-rw-r--r--sw/source/core/edit/edws.cxx6
-rw-r--r--sw/source/core/fields/expfld.cxx7
-rw-r--r--sw/source/core/fields/reffld.cxx4
-rw-r--r--sw/source/core/frmedt/fecopy.cxx2
-rw-r--r--sw/source/core/inc/DocumentContentOperationsManager.hxx9
-rw-r--r--sw/source/core/inc/MarkManager.hxx2
-rw-r--r--sw/source/core/inc/UndoDelete.hxx3
-rw-r--r--sw/source/core/inc/UndoRedline.hxx8
-rw-r--r--sw/source/core/inc/bookmrk.hxx10
-rw-r--r--sw/source/core/inc/docfld.hxx12
-rw-r--r--sw/source/core/inc/flyfrm.hxx3
-rw-r--r--sw/source/core/inc/flyfrms.hxx3
-rw-r--r--sw/source/core/inc/frame.hxx11
-rw-r--r--sw/source/core/inc/layact.hxx10
-rw-r--r--sw/source/core/inc/layfrm.hxx1
-rw-r--r--sw/source/core/inc/mvsave.hxx5
-rw-r--r--sw/source/core/inc/pagefrm.hxx3
-rw-r--r--sw/source/core/inc/rootfrm.hxx2
-rw-r--r--sw/source/core/inc/tabfrm.hxx1
-rw-r--r--sw/source/core/inc/unofldmid.h1
-rw-r--r--sw/source/core/layout/anchoreddrawobject.cxx14
-rw-r--r--sw/source/core/layout/atrfrm.cxx2
-rw-r--r--sw/source/core/layout/findfrm.cxx21
-rw-r--r--sw/source/core/layout/flowfrm.cxx2
-rw-r--r--sw/source/core/layout/fly.cxx40
-rw-r--r--sw/source/core/layout/flycnt.cxx46
-rw-r--r--sw/source/core/layout/flylay.cxx13
-rw-r--r--sw/source/core/layout/frmtool.cxx21
-rw-r--r--sw/source/core/layout/ftnfrm.cxx17
-rw-r--r--sw/source/core/layout/layact.cxx135
-rw-r--r--sw/source/core/layout/newfrm.cxx5
-rw-r--r--sw/source/core/layout/objectformattertxtfrm.cxx213
-rw-r--r--sw/source/core/layout/objectformattertxtfrm.hxx11
-rw-r--r--sw/source/core/layout/pagechg.cxx116
-rw-r--r--sw/source/core/layout/sectfrm.cxx3
-rw-r--r--sw/source/core/layout/tabfrm.cxx105
-rw-r--r--sw/source/core/layout/wsfrm.cxx20
-rw-r--r--sw/source/core/ole/ndole.cxx213
-rwxr-xr-xsw/source/core/text/frmform.cxx18
-rw-r--r--sw/source/core/text/itratr.cxx2
-rw-r--r--sw/source/core/text/itrform2.cxx19
-rw-r--r--sw/source/core/text/itrform2.hxx2
-rw-r--r--sw/source/core/text/porfld.cxx17
-rw-r--r--sw/source/core/text/porfld.hxx2
-rw-r--r--sw/source/core/text/porlay.cxx26
-rw-r--r--sw/source/core/text/txtfrm.cxx10
-rw-r--r--sw/source/core/text/xmldump.cxx63
-rw-r--r--sw/source/core/txtnode/ndtxt.cxx97
-rw-r--r--sw/source/core/txtnode/thints.cxx8
-rw-r--r--sw/source/core/txtnode/txatbase.cxx2
-rw-r--r--sw/source/core/txtnode/txtedt.cxx4
-rw-r--r--sw/source/core/undo/unbkmk.cxx2
-rw-r--r--sw/source/core/undo/undel.cxx26
-rw-r--r--sw/source/core/undo/undobj.cxx25
-rw-r--r--sw/source/core/undo/unins.cxx7
-rw-r--r--sw/source/core/undo/unredln.cxx38
-rw-r--r--sw/source/core/undo/untbl.cxx14
-rw-r--r--sw/source/core/unocore/unobkm.cxx2
-rw-r--r--sw/source/core/unocore/unochart.cxx6
-rw-r--r--sw/source/core/unocore/unocrsrhelper.cxx6
-rw-r--r--sw/source/core/unocore/unodraw.cxx2
-rw-r--r--sw/source/core/unocore/unofield.cxx6
-rw-r--r--sw/source/core/unocore/unoframe.cxx9
-rw-r--r--sw/source/core/unocore/unomap.cxx1
-rw-r--r--sw/source/core/unocore/unosett.cxx20
-rw-r--r--sw/source/core/unocore/unotext.cxx21
-rw-r--r--sw/source/core/view/printdata.cxx3
-rw-r--r--sw/source/filter/basflt/fltshell.cxx2
-rw-r--r--sw/source/filter/html/htmlplug.cxx7
-rw-r--r--sw/source/filter/html/htmltab.cxx40
-rw-r--r--sw/source/filter/html/htmltabw.cxx4
-rw-r--r--sw/source/filter/html/svxcss1.cxx6
-rw-r--r--sw/source/filter/html/swhtml.cxx4
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx761
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx69
-rw-r--r--sw/source/filter/ww8/docxexport.cxx134
-rw-r--r--sw/source/filter/ww8/docxexport.hxx16
-rw-r--r--sw/source/filter/ww8/docxsdrexport.cxx47
-rw-r--r--sw/source/filter/ww8/rtfattributeoutput.cxx2
-rw-r--r--sw/source/filter/ww8/wrtw8num.cxx11
-rw-r--r--sw/source/filter/ww8/wrtw8sty.cxx28
-rw-r--r--sw/source/filter/ww8/wrtww8.cxx1
-rw-r--r--sw/source/filter/ww8/wrtww8.hxx8
-rw-r--r--sw/source/filter/ww8/ww8atr.cxx20
-rw-r--r--sw/source/filter/ww8/ww8par.cxx13
-rw-r--r--sw/source/filter/ww8/ww8par.hxx12
-rw-r--r--sw/source/filter/ww8/ww8par2.cxx9
-rw-r--r--sw/source/filter/ww8/ww8par6.cxx3
-rw-r--r--sw/source/filter/xml/XMLRedlineImportHelper.cxx81
-rw-r--r--sw/source/filter/xml/xmlexp.hxx5
-rw-r--r--sw/source/filter/xml/xmlfmte.cxx12
-rw-r--r--sw/source/filter/xml/xmliteme.cxx2
-rw-r--r--sw/source/filter/xml/xmlithlp.cxx9
-rw-r--r--sw/source/filter/xml/xmltble.cxx149
-rw-r--r--sw/source/filter/xml/xmltexte.hxx12
-rw-r--r--sw/source/filter/xml/xmltexti.cxx9
-rw-r--r--sw/source/ui/dbui/dbinsdlg.cxx4
-rw-r--r--sw/source/ui/fldui/flddb.cxx12
-rw-r--r--sw/source/ui/fldui/flddinf.cxx22
-rw-r--r--sw/source/ui/fldui/fldref.cxx50
-rw-r--r--sw/source/ui/fldui/fldtdlg.cxx25
-rw-r--r--sw/source/ui/misc/bookmark.cxx6
-rw-r--r--sw/source/uibase/config/StoredChapterNumbering.cxx2
-rw-r--r--sw/source/uibase/dochdl/swdtflvr.cxx8
-rw-r--r--sw/source/uibase/docvw/OverlayRanges.hxx2
-rw-r--r--sw/source/uibase/docvw/ShadowOverlayObject.hxx6
-rw-r--r--sw/source/uibase/docvw/edtwin.cxx29
-rw-r--r--sw/source/uibase/fldui/fldmgr.cxx53
-rw-r--r--sw/source/uibase/inc/wrtsh.hxx5
-rw-r--r--sw/source/uibase/lingu/hhcwrp.cxx4
-rw-r--r--sw/source/uibase/ribbar/inputwin.cxx4
-rw-r--r--sw/source/uibase/shells/drwbassh.cxx110
-rw-r--r--sw/source/uibase/shells/drwtxtex.cxx8
-rw-r--r--sw/source/uibase/shells/frmsh.cxx2
-rw-r--r--sw/source/uibase/shells/tabsh.cxx2
-rw-r--r--sw/source/uibase/shells/textfld.cxx4
-rw-r--r--sw/source/uibase/shells/textsh1.cxx2
-rw-r--r--sw/source/uibase/uitest/uiobject.cxx25
-rw-r--r--sw/source/uibase/utlui/content.cxx2
-rw-r--r--sw/source/uibase/utlui/navipi.cxx2
-rw-r--r--sw/source/uibase/wrtsh/delete.cxx30
-rw-r--r--sw/source/uibase/wrtsh/select.cxx4
-rw-r--r--sw/source/uibase/wrtsh/wrtsh1.cxx16
-rw-r--r--sw/source/uibase/wrtsh/wrtsh2.cxx50
160 files changed, 3126 insertions, 1245 deletions
diff --git a/sw/source/core/attr/swatrset.cxx b/sw/source/core/attr/swatrset.cxx
index 7cd6303ecef1..55835c5d1c30 100644
--- a/sw/source/core/attr/swatrset.cxx
+++ b/sw/source/core/attr/swatrset.cxx
@@ -398,7 +398,8 @@ void SwAttrSet::CopyToModify( SwModify& rMod ) const
}
if (pSrcDoc != pDstDoc &&
- SfxItemState::SET == GetItemState(RES_PARATR_LIST_AUTOFMT, false, &pItem))
+ SfxItemState::SET == GetItemState(RES_PARATR_LIST_AUTOFMT, false, &pItem)
+ && static_cast<SwFormatAutoFormat const*>(pItem)->GetStyleHandle())
{
SfxItemSet const& rAutoStyle(*static_cast<SwFormatAutoFormat const&>(*pItem).GetStyleHandle());
std::shared_ptr<SfxItemSet> const pNewSet(
diff --git a/sw/source/core/bastyp/swrect.cxx b/sw/source/core/bastyp/swrect.cxx
index 1d53e6e7a71e..884c155003e2 100644
--- a/sw/source/core/bastyp/swrect.cxx
+++ b/sw/source/core/bastyp/swrect.cxx
@@ -19,6 +19,8 @@
#include <swrect.hxx>
+#include <libxml/xmlwriter.h>
+
#ifdef DBG_UTIL
#include <tools/stream.hxx>
#endif
@@ -218,6 +220,16 @@ void SwRect::SetUpperRightCorner( const Point& rNew )
void SwRect::SetLowerLeftCorner( const Point& rNew )
{ m_Point = Point(rNew.X(), rNew.Y() - m_Size.getHeight()); }
+void SwRect::dumpAsXmlAttributes(xmlTextWriterPtr writer) const
+{
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("left"), "%li", Left());
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("top"), "%li", Top());
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("width"), "%li", Width());
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("height"), "%li", Height());
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("bottom"), "%li", Bottom());
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("right"), "%li", Right());
+}
+
#ifdef DBG_UTIL
SvStream& WriteSwRect(SvStream &rStream, const SwRect &rRect)
{
diff --git a/sw/source/core/crsr/annotationmark.cxx b/sw/source/core/crsr/annotationmark.cxx
index ea11fad3d2cc..1deeb7e1f067 100644
--- a/sw/source/core/crsr/annotationmark.cxx
+++ b/sw/source/core/crsr/annotationmark.cxx
@@ -54,7 +54,7 @@ namespace sw { namespace mark
SwTextNode *pTextNode = GetMarkEnd().nNode.GetNode().GetTextNode();
assert(pTextNode);
SwTextField *const pTextField = pTextNode->GetFieldTextAttrAt(
- GetMarkEnd().nContent.GetIndex()-1, true);
+ GetMarkEnd().nContent.GetIndex()-1, ::sw::GetTextAttrMode::Default);
assert(pTextField != nullptr);
auto pPostItField
= dynamic_cast<const SwPostItField*>(pTextField->GetFormatField().GetField());
diff --git a/sw/source/core/crsr/bookmrk.cxx b/sw/source/core/crsr/bookmrk.cxx
index a16713dc295d..fad65a238147 100644
--- a/sw/source/core/crsr/bookmrk.cxx
+++ b/sw/source/core/crsr/bookmrk.cxx
@@ -25,6 +25,7 @@
#include <doc.hxx>
#include <ndtxt.hxx>
#include <pam.hxx>
+#include <hints.hxx>
#include <swserv.hxx>
#include <sfx2/linkmgr.hxx>
#include <UndoBookmark.hxx>
@@ -238,6 +239,12 @@ namespace
io_pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::UI_REPLACE, nullptr);
};
+
+ auto InvalidatePosition(SwPosition const& rPos) -> void
+ {
+ SwUpdateAttr const hint(rPos.nContent.GetIndex(), rPos.nContent.GetIndex(), 0);
+ rPos.nNode.GetNode().GetTextNode()->NotifyClients(nullptr, &hint);
+ }
}
namespace sw { namespace mark
@@ -337,6 +344,11 @@ namespace sw { namespace mark
}
// TODO: everything else uses MarkBase::GenerateNewName ?
+
+ auto MarkBase::InvalidateFrames() -> void
+ {
+ }
+
NavigatorReminder::NavigatorReminder(const SwPaM& rPaM)
: MarkBase(rPaM, "__NavigatorReminder__")
{ }
@@ -393,6 +405,7 @@ namespace sw { namespace mark
std::make_unique<SwUndoInsBookmark>(*this));
}
io_pDoc->getIDocumentState().SetModified();
+ InvalidateFrames();
}
void Bookmark::DeregisterFromDoc(SwDoc* const io_pDoc)
@@ -405,6 +418,36 @@ namespace sw { namespace mark
std::make_unique<SwUndoDeleteBookmark>(*this));
}
io_pDoc->getIDocumentState().SetModified();
+ InvalidateFrames();
+ }
+
+ // invalidate text frames in case it's hidden or Formatting Marks enabled
+ auto Bookmark::InvalidateFrames() -> void
+ {
+ InvalidatePosition(GetMarkPos());
+ if (IsExpanded())
+ {
+ InvalidatePosition(GetOtherMarkPos());
+ }
+ }
+
+ void Bookmark::Hide(bool const isHide)
+ {
+ if (isHide != m_bHidden)
+ {
+ m_bHidden = isHide;
+ InvalidateFrames();
+ }
+ }
+
+ void Bookmark::SetHideCondition(OUString const& rHideCondition)
+ {
+ if (m_sHideCondition != rHideCondition)
+ {
+ m_sHideCondition = rHideCondition;
+ // don't eval condition here yet - probably only needed for
+ // UI editing condition and that doesn't exist yet
+ }
}
::sfx2::IXmlIdRegistry& Bookmark::GetRegistry()
@@ -513,6 +556,8 @@ namespace sw { namespace mark
if (eMode == sw::mark::InsertMode::New)
{
lcl_SetFieldMarks(this, io_pDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND, pSepPos);
+ // no need to invalidate text frames here, the insertion of the
+ // CH_TXT_ATR already invalidates
}
else
{
diff --git a/sw/source/core/crsr/crbm.cxx b/sw/source/core/crsr/crbm.cxx
index a9175808de85..b35b1329cbca 100644
--- a/sw/source/core/crsr/crbm.cxx
+++ b/sw/source/core/crsr/crbm.cxx
@@ -130,9 +130,14 @@ bool IsMarkHidden(SwRootFrame const& rLayout, ::sw::mark::IMark const& rMark)
{
return false;
}
- SwTextNode const& rNode(*rMark.GetMarkPos().nNode.GetNode().GetTextNode());
+ SwNode const& rNode(rMark.GetMarkPos().nNode.GetNode());
+ SwTextNode const*const pTextNode(rNode.GetTextNode());
+ if (pTextNode == nullptr)
+ { // UNO_BOOKMARK may point to table node
+ return rNode.GetRedlineMergeFlag() == SwNode::Merge::Hidden;
+ }
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(
- rNode.getLayoutFrame(&rLayout)));
+ pTextNode->getLayoutFrame(&rLayout)));
if (!pFrame)
{
return true;
@@ -147,14 +152,14 @@ bool IsMarkHidden(SwRootFrame const& rLayout, ::sw::mark::IMark const& rMark)
}
else
{
- if (rMark.GetMarkPos().nContent.GetIndex() == rNode.Len())
+ if (rMark.GetMarkPos().nContent.GetIndex() == pTextNode->Len())
{ // at end of node: never deleted (except if node deleted)
- return rNode.GetRedlineMergeFlag() == SwNode::Merge::Hidden;
+ return pTextNode->GetRedlineMergeFlag() == SwNode::Merge::Hidden;
}
else
{ // check character following mark pos
return pFrame->MapModelToViewPos(rMark.GetMarkPos())
- == pFrame->MapModelToView(&rNode, rMark.GetMarkPos().nContent.GetIndex() + 1);
+ == pFrame->MapModelToView(pTextNode, rMark.GetMarkPos().nContent.GetIndex() + 1);
}
}
}
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index 0d8d273f34be..bf3f1718e67c 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -2244,7 +2244,14 @@ void SwCursorShell::Push()
*/
bool SwCursorShell::Pop(PopMode const eDelete)
{
- SwCallLink aLk( *this ); // watch Cursor-Moves; call Link if needed
+ ::std::unique_ptr<SwCallLink> pLink(::std::make_unique<SwCallLink>(*this)); // watch Cursor-Moves; call Link if needed
+ return Pop(eDelete, ::std::move(pLink));
+}
+
+bool SwCursorShell::Pop(PopMode const eDelete,
+ [[maybe_unused]] ::std::unique_ptr<SwCallLink> const pLink)
+{
+ assert(pLink); // parameter exists only to be deleted before return
// are there any left?
if (nullptr == m_pStackCursor)
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index 7df0ce6ff323..0c53e6448b46 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -774,7 +774,7 @@ bool SwCursorShell::MoveFieldType(
SwTextNode* pTNd = rPos.nNode.GetNode().GetTextNode();
OSL_ENSURE( pTNd, "No ContentNode" );
- SwTextField * pTextField = pTNd->GetFieldTextAttrAt( rPos.nContent.GetIndex(), true );
+ SwTextField * pTextField = pTNd->GetFieldTextAttrAt(rPos.nContent.GetIndex(), ::sw::GetTextAttrMode::Default);
const bool bDelField = ( pTextField == nullptr );
sal_Int32 nContentOffset = -1;
@@ -878,14 +878,14 @@ bool SwCursorShell::GotoFormatField( const SwFormatField& rField )
SwTextField * SwCursorShell::GetTextFieldAtPos(
const SwPosition* pPos,
- const bool bIncludeInputFieldAtStart )
+ ::sw::GetTextAttrMode const eMode)
{
SwTextField* pTextField = nullptr;
SwTextNode * const pNode = pPos->nNode.GetNode().GetTextNode();
if ( pNode != nullptr )
{
- pTextField = pNode->GetFieldTextAttrAt( pPos->nContent.GetIndex(), bIncludeInputFieldAtStart );
+ pTextField = pNode->GetFieldTextAttrAt( pPos->nContent.GetIndex(), eMode);
}
return pTextField;
@@ -893,11 +893,11 @@ SwTextField * SwCursorShell::GetTextFieldAtPos(
SwTextField* SwCursorShell::GetTextFieldAtCursor(
const SwPaM* pCursor,
- const bool bIncludeInputFieldAtStart )
+ ::sw::GetTextAttrMode const eMode)
{
SwTextField* pFieldAtCursor = nullptr;
- SwTextField* pTextField = GetTextFieldAtPos( pCursor->Start(), bIncludeInputFieldAtStart );
+ SwTextField* pTextField = GetTextFieldAtPos(pCursor->Start(), eMode);
if ( pTextField != nullptr
&& pCursor->Start()->nNode == pCursor->End()->nNode )
{
@@ -918,7 +918,8 @@ SwField* SwCursorShell::GetFieldAtCursor(
const SwPaM *const pCursor,
const bool bIncludeInputFieldAtStart)
{
- SwTextField *const pField(GetTextFieldAtCursor(pCursor, bIncludeInputFieldAtStart));
+ SwTextField *const pField(GetTextFieldAtCursor(pCursor,
+ bIncludeInputFieldAtStart ? ::sw::GetTextAttrMode::Default : ::sw::GetTextAttrMode::Expand));
return pField
? const_cast<SwField*>(pField->GetFormatField().GetField())
: nullptr;
@@ -949,7 +950,7 @@ bool SwCursorShell::CursorInsideInputField() const
{
for(SwPaM& rCursor : GetCursor()->GetRingContainer())
{
- if (dynamic_cast<const SwTextInputField*>(GetTextFieldAtCursor(&rCursor, true)))
+ if (dynamic_cast<const SwTextInputField*>(GetTextFieldAtCursor(&rCursor, ::sw::GetTextAttrMode::Parent)))
return true;
}
return false;
@@ -957,7 +958,7 @@ bool SwCursorShell::CursorInsideInputField() const
bool SwCursorShell::PosInsideInputField( const SwPosition& rPos )
{
- return dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos( &rPos, false )) != nullptr;
+ return dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos(&rPos, ::sw::GetTextAttrMode::Parent)) != nullptr;
}
bool SwCursorShell::DocPtInsideInputField( const Point& rDocPt ) const
@@ -973,7 +974,7 @@ bool SwCursorShell::DocPtInsideInputField( const Point& rDocPt ) const
sal_Int32 SwCursorShell::StartOfInputFieldAtPos( const SwPosition& rPos )
{
- const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos( &rPos, true ));
+ const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos(&rPos, ::sw::GetTextAttrMode::Default));
assert(pTextInputField != nullptr
&& "<SwEditShell::StartOfInputFieldAtPos(..)> - no Input Field at given position");
return pTextInputField->GetStart();
@@ -981,7 +982,7 @@ sal_Int32 SwCursorShell::StartOfInputFieldAtPos( const SwPosition& rPos )
sal_Int32 SwCursorShell::EndOfInputFieldAtPos( const SwPosition& rPos )
{
- const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos( &rPos, true ));
+ const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextFieldAtPos(&rPos, ::sw::GetTextAttrMode::Default));
assert(pTextInputField != nullptr
&& "<SwEditShell::EndOfInputFieldAtPos(..)> - no Input Field at given position");
return *(pTextInputField->End());
@@ -1930,7 +1931,7 @@ bool SwContentAtPos::IsInRTLText()const
return bRet;
}
-bool SwCursorShell::SelectText( const sal_Int32 nStart,
+bool SwCursorShell::SelectTextModel( const sal_Int32 nStart,
const sal_Int32 nEnd )
{
SET_CURR_SHELL( this );
@@ -1954,6 +1955,43 @@ bool SwCursorShell::SelectText( const sal_Int32 nStart,
return bRet;
}
+TextFrameIndex SwCursorShell::GetCursorPointAsViewIndex() const
+{
+ SwPosition const*const pPos(GetCursor()->GetPoint());
+ SwTextNode const*const pTextNode(pPos->nNode.GetNode().GetTextNode());
+ assert(pTextNode);
+ SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(pTextNode->getLayoutFrame(GetLayout())));
+ assert(pFrame);
+ return pFrame->MapModelToViewPos(*pPos);
+}
+
+bool SwCursorShell::SelectTextView(TextFrameIndex const nStart,
+ TextFrameIndex const nEnd)
+{
+ CurrShell aCurr( this );
+ bool bRet = false;
+
+ SwCallLink aLk( *this );
+ SwCursorSaveState aSaveState( *m_pCurrentCursor );
+
+ SwPosition& rPos = *m_pCurrentCursor->GetPoint();
+ m_pCurrentCursor->DeleteMark();
+ // indexes must correspond to cursor point!
+ SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(m_pCurrentCursor->GetPoint()->nNode.GetNode().GetTextNode()->getLayoutFrame(GetLayout())));
+ assert(pFrame);
+ rPos = pFrame->MapViewToModelPos(nStart);
+ m_pCurrentCursor->SetMark();
+ rPos = pFrame->MapViewToModelPos(nEnd);
+
+ if (!m_pCurrentCursor->IsSelOvr())
+ {
+ UpdateCursor();
+ bRet = true;
+ }
+
+ return bRet;
+}
+
bool SwCursorShell::SelectTextAttr( sal_uInt16 nWhich,
bool bExpand,
const SwTextAttr* pTextAttr )
@@ -1970,14 +2008,14 @@ bool SwCursorShell::SelectTextAttr( sal_uInt16 nWhich,
pTextAttr = pTextNd
? pTextNd->GetTextAttrAt(rPos.nContent.GetIndex(),
nWhich,
- bExpand ? SwTextNode::EXPAND : SwTextNode::DEFAULT)
+ bExpand ? ::sw::GetTextAttrMode::Expand : ::sw::GetTextAttrMode::Default)
: nullptr;
}
if( pTextAttr )
{
const sal_Int32* pEnd = pTextAttr->End();
- bRet = SelectText( pTextAttr->GetStart(), ( pEnd ? *pEnd : pTextAttr->GetStart() + 1 ) );
+ bRet = SelectTextModel(pTextAttr->GetStart(), (pEnd ? *pEnd : pTextAttr->GetStart() + 1));
}
}
return bRet;
diff --git a/sw/source/core/crsr/swcrsr.cxx b/sw/source/core/crsr/swcrsr.cxx
index 19d47dcec68e..98a3b9682442 100644
--- a/sw/source/core/crsr/swcrsr.cxx
+++ b/sw/source/core/crsr/swcrsr.cxx
@@ -210,7 +210,7 @@ namespace
SwTextNode* pTextNd = pPos->nNode.GetNode().GetTextNode();
if (!pTextNd)
return nullptr;
- return pTextNd->GetTextAttrAt(pPos->nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTextNode::PARENT);
+ return pTextNd->GetTextAttrAt(pPos->nContent.GetIndex(), RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent);
}
}
@@ -1790,7 +1790,7 @@ bool SwCursor::LeftRight( bool bLeft, sal_uInt16 nCnt, sal_uInt16 nMode,
SwTextNode const*const pNode(GetPoint()->nNode.GetNode().GetTextNode());
assert(pNode);
SwTextAttr const*const pInputField(pNode->GetTextAttrAt(
- GetPoint()->nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTextNode::PARENT));
+ GetPoint()->nContent.GetIndex(), RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent));
if (pInputField)
{
continue; // skip over input fields
diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index 5aa804d364b0..4c4bbd682056 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -422,7 +422,7 @@ void SwSelPaintRects::HighlightInputField()
if (m_bShowTextInputFieldOverlay)
{
SwTextInputField* pCurTextInputFieldAtCursor =
- dynamic_cast<SwTextInputField*>(SwCursorShell::GetTextFieldAtPos( GetShell()->GetCursor()->Start(), false ));
+ dynamic_cast<SwTextInputField*>(SwCursorShell::GetTextFieldAtPos( GetShell()->GetCursor()->Start(), ::sw::GetTextAttrMode::Expand));
if ( pCurTextInputFieldAtCursor != nullptr )
{
SwTextNode* pTextNode = pCurTextInputFieldAtCursor->GetpTextNode();
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 0199260aa6cf..975a35965d17 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -387,7 +387,8 @@ namespace
*pDelPam->GetPoint(), nDelCount );
}
- if (pDelPam->GetNext() && *pDelPam->GetNext()->End() == *pDelPam->Start())
+ if (pDelPam->GetNext() != pDelPam.get()
+ && *pDelPam->GetNext()->End() == *pDelPam->Start())
{
*pDelPam->GetNext()->End() = *pDelPam->End();
pDelPam.reset(pDelPam->GetNext());
@@ -617,8 +618,9 @@ namespace sw
namespace
{
- bool lcl_DoWithBreaks(::sw::DocumentContentOperationsManager & rDocumentContentOperations, SwPaM & rPam,
- bool (::sw::DocumentContentOperationsManager::*pFunc)(SwPaM&, bool), const bool bForceJoinNext = false)
+ bool lcl_DoWithBreaks(::sw::DocumentContentOperationsManager & rDocumentContentOperations,
+ SwPaM & rPam, SwDeleteFlags const flags,
+ bool (::sw::DocumentContentOperationsManager::*pFunc)(SwPaM&, SwDeleteFlags, bool), const bool bForceJoinNext = false)
{
std::vector<std::pair<sal_uLong, sal_Int32>> Breaks;
@@ -626,7 +628,7 @@ namespace
if (Breaks.empty())
{
- return (rDocumentContentOperations.*pFunc)(rPam, bForceJoinNext);
+ return (rDocumentContentOperations.*pFunc)(rPam, flags, bForceJoinNext);
}
// Deletion must be split into several parts if the text node
@@ -650,7 +652,7 @@ namespace
rStart = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second + 1);
if (rStart < rEnd) // check if part is empty
{
- bRet &= (rDocumentContentOperations.*pFunc)(aPam, bForceJoinNext);
+ bRet &= (rDocumentContentOperations.*pFunc)(aPam, flags, bForceJoinNext);
nOffset = iter->first - rStart.nNode.GetIndex(); // deleted fly nodes...
}
rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second);
@@ -660,7 +662,7 @@ namespace
rStart = *rPam.Start(); // set to original start
if (rStart < rEnd) // check if part is empty
{
- bRet &= (rDocumentContentOperations.*pFunc)(aPam, bForceJoinNext);
+ bRet &= (rDocumentContentOperations.*pFunc)(aPam, flags, bForceJoinNext);
}
return bRet;
@@ -935,8 +937,10 @@ namespace
for(SaveRedline & rSvRedLine : rArr)
{
rSvRedLine.SetPos( nInsPos );
- pDoc->getIDocumentRedlineAccess().AppendRedline( rSvRedLine.pRedl, true );
- if (rSvRedLine.pRedl->GetType() == RedlineType::Delete)
+ IDocumentRedlineAccess::AppendResult const result(
+ pDoc->getIDocumentRedlineAccess().AppendRedline( rSvRedLine.pRedl, true ));
+ if ( IDocumentRedlineAccess::AppendResult::APPENDED == result &&
+ rSvRedLine.pRedl->GetType() == RedlineType::Delete )
{
UpdateFramesForAddDeleteRedline(*pDoc, *rSvRedLine.pRedl);
}
@@ -1994,7 +1998,7 @@ void DocumentContentOperationsManager::DeleteDummyChar(
assert(aPam.GetText().getLength() == 1 && aPam.GetText()[0] == cDummy);
(void) cDummy;
- DeleteRangeImpl(aPam);
+ DeleteRangeImpl(aPam, SwDeleteFlags::Default);
if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
&& !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
@@ -2005,7 +2009,7 @@ void DocumentContentOperationsManager::DeleteDummyChar(
void DocumentContentOperationsManager::DeleteRange( SwPaM & rPam )
{
- lcl_DoWithBreaks( *this, rPam, &DocumentContentOperationsManager::DeleteRangeImpl );
+ lcl_DoWithBreaks(*this, rPam, SwDeleteFlags::Default, &DocumentContentOperationsManager::DeleteRangeImpl);
if (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline()
&& !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
@@ -2108,7 +2112,7 @@ bool DocumentContentOperationsManager::DelFullPara( SwPaM& rPam )
::PaMCorrAbs( aDelPam, aTmpPos );
}
- std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete( aDelPam, true ));
+ std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete(aDelPam, SwDeleteFlags::Default, true));
*rPam.GetPoint() = *aDelPam.GetPoint();
pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
@@ -2131,6 +2135,37 @@ bool DocumentContentOperationsManager::DelFullPara( SwPaM& rPam )
return false;
}
}
+
+ // must delete all fieldmarks before CorrAbs(), or they'll remain
+ // moved to wrong node without their CH_TXT_ATR_FIELD*
+ // (note: deleteMarks() doesn't help here, in case of partially
+ // selected fieldmarks; let's delete these as re-inserting their chars
+ // elsewhere looks difficult)
+ ::std::set<::sw::mark::IFieldmark*> fieldmarks;
+ for (SwNodeIndex i = aRg.aStart; i <= aRg.aEnd; ++i)
+ {
+ if (SwTextNode *const pTextNode = i.GetNode().GetTextNode())
+ {
+ for (sal_Int32 j = 0; j < pTextNode->GetText().getLength(); ++j)
+ {
+ switch (pTextNode->GetText()[j])
+ {
+ case CH_TXT_ATR_FIELDSTART:
+ case CH_TXT_ATR_FIELDEND:
+ fieldmarks.insert(m_rDoc.getIDocumentMarkAccess()->getFieldmarkAt(SwPosition(*pTextNode, j)));
+ break;
+ case CH_TXT_ATR_FIELDSEP:
+ fieldmarks.insert(m_rDoc.getIDocumentMarkAccess()->getFieldmarkFor(SwPosition(*pTextNode, j)));
+ break;
+ }
+ }
+ }
+ }
+ for (auto const pFieldMark : fieldmarks)
+ {
+ m_rDoc.getIDocumentMarkAccess()->deleteMark(pFieldMark);
+ }
+
// move bookmarks, redlines etc.
if (aRg.aStart == aRg.aEnd) // only first CorrAbs variant handles this
{
@@ -2172,13 +2207,13 @@ bool DocumentContentOperationsManager::DelFullPara( SwPaM& rPam )
}
// #i100466# Add handling of new optional parameter <bForceJoinNext>
-bool DocumentContentOperationsManager::DeleteAndJoin( SwPaM & rPam,
+bool DocumentContentOperationsManager::DeleteAndJoin(SwPaM & rPam, SwDeleteFlags const flags,
const bool bForceJoinNext )
{
if ( lcl_StrLenOverflow( rPam ) )
return false;
- bool const ret = lcl_DoWithBreaks( *this, rPam, (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
+ bool const ret = lcl_DoWithBreaks( *this, rPam, flags, (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
? &DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl
: &DocumentContentOperationsManager::DeleteAndJoinImpl,
bForceJoinNext );
@@ -3311,8 +3346,8 @@ bool DocumentContentOperationsManager::ReplaceRange( SwPaM& rPam, const OUString
if (rStart < rEnd) // check if part is empty
{
bRet &= (m_rDoc.getIDocumentRedlineAccess().IsRedlineOn())
- ? DeleteAndJoinWithRedlineImpl(aPam)
- : DeleteAndJoinImpl(aPam, false);
+ ? DeleteAndJoinWithRedlineImpl(aPam, SwDeleteFlags::Default)
+ : DeleteAndJoinImpl(aPam, SwDeleteFlags::Default, false);
nOffset = iter->first - rStart.nNode.GetIndex(); // deleted fly nodes...
}
rEnd = SwPosition(*rNodes[iter->first - nOffset]->GetTextNode(), iter->second);
@@ -3447,21 +3482,28 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
aRedlRest.Restore();
if (bMakeNewFrames) // tdf#130685 only after aRedlRest
{ // recreate from previous node (could be merged now)
- if (SwTextNode *const pNode = aSavePos.GetNode().GetTextNode())
+ std::unordered_set<SwTextFrame*> frames;
+ SwTextNode * pNode = aSavePos.GetNode().GetTextNode();
+ SwTextNode *const pEndNode = rInsPos.GetNode().GetTextNode();
+ if (pEndNode)
{
- std::unordered_set<SwTextFrame*> frames;
- SwTextNode *const pEndNode = rInsPos.GetNode().GetTextNode();
- if (pEndNode)
+ SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pEndNode);
+ for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
{
- SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pEndNode);
- for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
+ if (pFrame->getRootFrame()->IsHideRedlines())
{
- if (pFrame->getRootFrame()->IsHideRedlines())
+ frames.insert(pFrame);
+ // tdf#135061 check if end node is merged to a preceding node
+ if (pNode == nullptr && pFrame->GetMergedPara()
+ && pFrame->GetMergedPara()->pFirstNode->GetIndex() < aSavePos.GetIndex())
{
- frames.insert(pFrame);
+ pNode = pFrame->GetMergedPara()->pFirstNode;
}
}
}
+ }
+ if (pNode != nullptr)
+ {
sw::RecreateStartTextFrames(*pNode);
if (!frames.empty())
{ // tdf#132187 check if the end node needs new frames
@@ -3873,7 +3915,7 @@ DocumentContentOperationsManager::~DocumentContentOperationsManager()
}
//Private methods
-bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM & rPam, const bool )
+bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl(SwPaM & rPam, SwDeleteFlags const flags, const bool)
{
assert(m_rDoc.getIDocumentRedlineAccess().IsRedlineOn());
@@ -3953,7 +3995,7 @@ bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM & rPa
{
assert(pRedline->HasValidRange());
undos.emplace_back(std::make_unique<SwUndoRedlineDelete>(
- *pRedline, SwUndoId::DELETE));
+ *pRedline, SwUndoId::DELETE, flags));
}
const SwRewriter aRewriter = undos.front()->GetRewriter();
// can only group a single undo action
@@ -4014,7 +4056,7 @@ bool DocumentContentOperationsManager::DeleteAndJoinWithRedlineImpl( SwPaM & rPa
return true;
}
-bool DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM & rPam,
+bool DocumentContentOperationsManager::DeleteAndJoinImpl(SwPaM & rPam, SwDeleteFlags const flags,
const bool bForceJoinNext )
{
bool bJoinText, bJoinPrev;
@@ -4026,7 +4068,7 @@ bool DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM & rPam,
}
{
- bool const bSuccess( DeleteRangeImpl( rPam ) );
+ bool const bSuccess( DeleteRangeImpl(rPam, flags) );
if (!bSuccess)
return false;
}
@@ -4045,14 +4087,14 @@ bool DocumentContentOperationsManager::DeleteAndJoinImpl( SwPaM & rPam,
return true;
}
-bool DocumentContentOperationsManager::DeleteRangeImpl(SwPaM & rPam, const bool)
+bool DocumentContentOperationsManager::DeleteRangeImpl(SwPaM & rPam, SwDeleteFlags const flags, const bool)
{
// Move all cursors out of the deleted range, but first copy the
// passed PaM, because it could be a cursor that would be moved!
SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
- bool const bSuccess( DeleteRangeImplImpl( aDelPam ) );
+ bool const bSuccess( DeleteRangeImplImpl(aDelPam, flags) );
if (bSuccess)
{ // now copy position from temp copy to given PaM
*rPam.GetPoint() = *aDelPam.GetPoint();
@@ -4061,7 +4103,7 @@ bool DocumentContentOperationsManager::DeleteRangeImpl(SwPaM & rPam, const bool)
return bSuccess;
}
-bool DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam)
+bool DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam, SwDeleteFlags const flags)
{
SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
@@ -4126,7 +4168,7 @@ bool DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam)
}
if (!bMerged)
{
- m_rDoc.GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDelete>( rPam ) );
+ m_rDoc.GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoDelete>(rPam, flags));
}
m_rDoc.getIDocumentState().SetModified();
@@ -4138,8 +4180,11 @@ bool DocumentContentOperationsManager::DeleteRangeImplImpl(SwPaM & rPam)
m_rDoc.getIDocumentRedlineAccess().DeleteRedline( rPam, true, RedlineType::Any );
// Delete and move all "Flys at the paragraph", which are within the Selection
- DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode,
- &rPam.GetMark()->nContent, &rPam.GetPoint()->nContent);
+ if (!(flags & SwDeleteFlags::ArtificialSelection))
+ {
+ DelFlyInRange(rPam.GetMark()->nNode, rPam.GetPoint()->nNode,
+ &rPam.GetMark()->nContent, &rPam.GetPoint()->nContent);
+ }
DelBookmarks(
pStt->nNode,
pEnd->nNode,
@@ -4272,7 +4317,7 @@ bool DocumentContentOperationsManager::ReplaceRangeImpl( SwPaM& rPam, const OUSt
// the other views out of the deletion range.
// Except for itself!
SwPaM aDelPam( *rPam.GetMark(), *rPam.GetPoint() );
- ::PaMCorrAbs( aDelPam, *aDelPam.GetPoint() );
+ ::PaMCorrAbs( aDelPam, *aDelPam.End() );
SwPosition *pStt = aDelPam.Start(),
*pEnd = aDelPam.End();
@@ -4376,12 +4421,26 @@ bool DocumentContentOperationsManager::ReplaceRangeImpl( SwPaM& rPam, const OUSt
InsertItemSet( aTmpRange, aSet );
}
+ // tdf#139982: Appending the redline may immediately delete flys
+ // anchored in the previous text if it's inside an insert redline.
+ // Also flys will be deleted if the redline is accepted. Move them
+ // to the position between the previous text and the new text,
+ // there the chance of surviving both accept and reject is best.
+ SaveFlyArr flys;
+ SaveFlyInRange(aDelPam, *aDelPam.End(), flys, false);
+
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
{
m_rDoc.GetIDocumentUndoRedo().AppendUndo(
std::make_unique<SwUndoRedlineDelete>( aDelPam, SwUndoId::REPLACE ));
}
+ // add redline similar to DeleteAndJoinWithRedlineImpl()
+ std::shared_ptr<SwUnoCursor> const pCursor(m_rDoc.CreateUnoCursor(*aDelPam.GetMark()));
+ pCursor->SetMark();
+ *pCursor->GetPoint() = *aDelPam.GetPoint();
m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Delete, aDelPam ), true);
+ RestFlyInRange(flys, *aDelPam.End(), &aDelPam.End()->nNode, true);
+ sw::UpdateFramesForAddDeleteRedline(m_rDoc, *pCursor);
*rPam.GetMark() = *aDelPam.GetMark();
if (m_rDoc.GetIDocumentUndoRedo().DoesUndo())
@@ -4404,8 +4463,8 @@ bool DocumentContentOperationsManager::ReplaceRangeImpl( SwPaM& rPam, const OUSt
m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( eOld );
*rPam.GetPoint() = pBkmk->GetMarkPos();
- if(pBkmk->IsExpanded())
- *rPam.GetMark() = pBkmk->GetOtherMarkPos();
+ *rPam.GetMark() = pBkmk->IsExpanded() ? pBkmk->GetOtherMarkPos() : pBkmk->GetMarkPos();
+
m_rDoc.getIDocumentMarkAccess()->deleteMark(pBkmk);
}
bJoinText = false;
diff --git a/sw/source/core/doc/DocumentFieldsManager.cxx b/sw/source/core/doc/DocumentFieldsManager.cxx
index 134d8cab9968..b696734c6899 100644
--- a/sw/source/core/doc/DocumentFieldsManager.cxx
+++ b/sw/source/core/doc/DocumentFieldsManager.cxx
@@ -1052,6 +1052,17 @@ void DocumentFieldsManager::UpdateExpFieldsImpl(
}
continue;
}
+ ::sw::mark::IBookmark *const pBookmark(
+ const_cast<::sw::mark::IBookmark *>(it->GetBookmark()));
+ if (pBookmark)
+ {
+ SwSbxValue const aValue(aCalc.Calculate(pBookmark->GetHideCondition()));
+ if (!aValue.IsVoidValue())
+ {
+ pBookmark->Hide(aValue.GetBool());
+ }
+ continue;
+ }
SwTextField* pTextField = const_cast<SwTextField*>(it->GetTextField());
if( !pTextField )
@@ -1743,7 +1754,7 @@ SwTextField * DocumentFieldsManager::GetTextFieldAtPos(const SwPosition & rPos)
SwTextNode * const pNode = rPos.nNode.GetNode().GetTextNode();
return (pNode != nullptr)
- ? pNode->GetFieldTextAttrAt( rPos.nContent.GetIndex(), true )
+ ? pNode->GetFieldTextAttrAt(rPos.nContent.GetIndex(), ::sw::GetTextAttrMode::Default)
: nullptr;
}
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index ff9b05743d10..718492ab3f79 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -283,6 +283,12 @@ void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
break;
}
+ // no nodes can be unmerged by this - skip MakeFrames() etc.
+ if (rPam.GetPoint()->nNode == rPam.GetMark()->nNode)
+ {
+ break; // continue with AppendAllObjs()
+ }
+
// first, call CheckParaRedlineMerge on the first paragraph,
// to init flag on new merge range (if any) + 1st node post the merge
auto eMode(sw::FrameMode::Existing);
@@ -301,6 +307,8 @@ void UpdateFramesForRemoveDeleteRedline(SwDoc & rDoc, SwPaM const& rPam)
pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
*pFrame, rFirstNode, eMode));
eMode = sw::FrameMode::New; // Existing is not idempotent!
+ // update pNode so MakeFrames starts on 2nd node
+ pNode = &rFirstNode;
}
}
if (pLast != pNode)
@@ -2317,7 +2325,7 @@ bool DocumentRedlineManager::SplitRedline( const SwPaM& rRange )
SwRedlineTable::size_type n = 0;
const SwPosition* pStt = rRange.Start();
const SwPosition* pEnd = rRange.End();
- GetRedline( *pStt, &n );
+ //FIXME overlapping problem GetRedline( *pStt, &n );
for ( ; n < mpRedlineTable->size(); ++n)
{
SwRangeRedline * pRedline = (*mpRedlineTable)[ n ];
diff --git a/sw/source/core/doc/DocumentStylePoolManager.cxx b/sw/source/core/doc/DocumentStylePoolManager.cxx
index 767af3a22010..b5bb128629e6 100644
--- a/sw/source/core/doc/DocumentStylePoolManager.cxx
+++ b/sw/source/core/doc/DocumentStylePoolManager.cxx
@@ -1588,7 +1588,7 @@ SwFormat* DocumentStylePoolManager::GetFormatFromPool( sal_uInt16 nId )
aSet.Put( SwFormatHoriOrient( 0, text::HoriOrientation::CENTER, text::RelOrientation::PRINT_AREA ) );
aSet.Put( SwFormatVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::PRINT_AREA ) );
Color aCol( COL_BLACK );
- SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 );
+ SvxBorderLine aLine( &aCol, SvxBorderLineWidth::Hairline );
SvxBoxItem aBox( RES_BOX );
aBox.SetLine( &aLine, SvxBoxItemLine::TOP );
aBox.SetLine( &aLine, SvxBoxItemLine::BOTTOM );
diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx
index a9eed445a21c..e9fde5afcd5e 100644
--- a/sw/source/core/doc/docbm.cxx
+++ b/sw/source/core/doc/docbm.cxx
@@ -561,6 +561,18 @@ namespace sw { namespace mark
pPos2->nContent.GetIndex());
}
#endif
+ if ( (!rPaM.GetPoint()->nNode.GetNode().IsTextNode()
+ && (eType != MarkType::UNO_BOOKMARK
+ // SwXTextRange can be on table node or plain start node (FLY_AT_FLY)
+ || !rPaM.GetPoint()->nNode.GetNode().IsStartNode()))
+ || (!rPaM.GetMark()->nNode.GetNode().IsTextNode()
+ && (eType != MarkType::UNO_BOOKMARK
+ || !rPaM.GetMark()->nNode.GetNode().IsStartNode())))
+ {
+ SAL_WARN("sw.core", "MarkManager::makeMark(..)"
+ " - refusing to create mark on non-textnode");
+ return nullptr;
+ }
// There should only be one CrossRefBookmark per Textnode per Type
if ((eType == MarkType::CROSSREF_NUMITEM_BOOKMARK || eType == MarkType::CROSSREF_HEADING_BOOKMARK)
&& (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.Start(), eType) != m_vBookmarks.end()))
@@ -809,6 +821,8 @@ namespace sw { namespace mark
if (!pMarkBase)
return;
+ pMarkBase->InvalidateFrames();
+
pMarkBase->SetMarkPos(*(rPaM.GetPoint()));
if(rPaM.HasMark())
pMarkBase->SetOtherMarkPos(*(rPaM.GetMark()));
@@ -818,6 +832,8 @@ namespace sw { namespace mark
if(pMarkBase->GetMarkPos() != pMarkBase->GetMarkStart())
pMarkBase->Swap();
+ pMarkBase->InvalidateFrames();
+
sortMarks();
}
@@ -1111,7 +1127,7 @@ namespace sw { namespace mark
pppMark != vMarksToDelete.rend();
++pppMark )
{
- vDelay.push_back(deleteMark(*pppMark));
+ vDelay.push_back(deleteMark(*pppMark, pSaveBkmk != nullptr));
}
} // scope to kill vDelay
@@ -1130,8 +1146,9 @@ namespace sw { namespace mark
{
std::unique_ptr<Fieldmark> m_pFieldmark;
SwDoc * m_pDoc;
- LazyFieldmarkDeleter(Fieldmark* pMark, SwDoc *const pDoc)
- : m_pFieldmark(pMark), m_pDoc(pDoc)
+ bool const m_isMoveNodes;
+ LazyFieldmarkDeleter(Fieldmark* pMark, SwDoc *const pDoc, bool const isMoveNodes)
+ : m_pFieldmark(pMark), m_pDoc(pDoc), m_isMoveNodes(isMoveNodes)
{
assert(m_pFieldmark);
}
@@ -1141,12 +1158,15 @@ namespace sw { namespace mark
// command *cannot* be deleted here as it would create a separate
// SwUndoDelete that's interleaved with the SwHistory of the outer
// one - only delete the CH_TXT_ATR_FIELD*!
- m_pFieldmark->ReleaseDoc(m_pDoc);
+ if (!m_isMoveNodes)
+ {
+ m_pFieldmark->ReleaseDoc(m_pDoc);
+ }
}
};
std::unique_ptr<IDocumentMarkAccess::ILazyDeleter>
- MarkManager::deleteMark(const const_iterator_t& ppMark)
+ MarkManager::deleteMark(const const_iterator_t& ppMark, bool const isMoveNodes)
{
std::unique_ptr<ILazyDeleter> ret;
if (ppMark.get() == m_vAllMarks.end())
@@ -1184,7 +1204,7 @@ namespace sw { namespace mark
ClearFieldActivation();
m_vFieldmarks.erase(ppFieldmark);
- ret.reset(new LazyFieldmarkDeleter(dynamic_cast<Fieldmark*>(pMark), m_pDoc));
+ ret.reset(new LazyFieldmarkDeleter(dynamic_cast<Fieldmark*>(pMark), m_pDoc, isMoveNodes));
}
else
{
@@ -1241,7 +1261,7 @@ namespace sw { namespace mark
for ( ; it != endIt; ++it)
if (*it == pMark)
{
- deleteMark(iterator(it));
+ deleteMark(iterator(it), false);
break;
}
}
@@ -1340,7 +1360,7 @@ namespace sw { namespace mark
if (!pFieldmark)
return;
- deleteMark(lcl_FindMark(m_vAllMarks, pFieldmark));
+ deleteMark(lcl_FindMark(m_vAllMarks, pFieldmark), false);
}
::sw::mark::IFieldmark* MarkManager::changeFormFieldmarkType(::sw::mark::IFieldmark* pFieldmark, const OUString& rNewType)
@@ -1703,7 +1723,7 @@ void SaveBookmark::SetInDoc(
{
::sw::mark::IBookmark* const pBookmark = dynamic_cast<::sw::mark::IBookmark*>(
pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName,
- m_eOrigBkmType, sw::mark::InsertMode::New));
+ m_eOrigBkmType, sw::mark::InsertMode::CopyText));
if(pBookmark)
{
pBookmark->SetKeyCode(m_aCode);
diff --git a/sw/source/core/doc/docchart.cxx b/sw/source/core/doc/docchart.cxx
index b602c92afd14..f31dd1f73088 100644
--- a/sw/source/core/doc/docchart.cxx
+++ b/sw/source/core/doc/docchart.cxx
@@ -110,9 +110,30 @@ void SwDoc::UpdateCharts_( const SwTable& rTable, SwViewShell const & rVSh ) con
aName == pONd->GetChartTableName() &&
pONd->getLayoutFrame( rVSh.GetLayout() ) )
{
+ // tdf#122995 for OLE/Charts in SW we do not (yet) have a refresh
+ // mechanism or embedding of the primitive representation, so this
+ // needs to be done locally here (simplest solution).
+ bool bImmediateMode(false);
+
+ if(pONd->IsChart())
+ {
+ // refresh to trigger repaint
+ const SwRect aChartRect(pONd->FindLayoutRect());
+ if(!aChartRect.IsEmpty())
+ const_cast<SwViewShell &>(rVSh).InvalidateWindows(aChartRect);
+
+ // forced refresh of the chart's primitive representation
+ pONd->GetOLEObj().resetBufferedData();
+
+ // InvalidateTable using the Immediate-Mode, else the chart will
+ // not yet know that it is invalidated at the next repaint and create
+ // the same graphical representation again
+ bImmediateMode = true;
+ }
+
SwChartDataProvider *pPCD = getIDocumentChartDataProviderAccess().GetChartDataProvider();
if (pPCD)
- pPCD->InvalidateTable( &rTable );
+ pPCD->InvalidateTable( &rTable, bImmediateMode );
// following this the framework will now take care of repainting
// the chart or it's replacement image...
}
diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx
index 1b93a7a56a78..d6072b4b3725 100644
--- a/sw/source/core/doc/docedt.cxx
+++ b/sw/source/core/doc/docedt.cxx
@@ -28,6 +28,7 @@
#include <mdiexp.hxx>
#include <mvsave.hxx>
#include <redline.hxx>
+#include <rolbck.hxx>
#include <rootfrm.hxx>
#include <splargs.hxx>
#include <swcrsr.hxx>
@@ -48,7 +49,7 @@ using namespace ::com::sun::star::i18n;
void RestFlyInRange( SaveFlyArr & rArr, const SwPosition& rStartPos,
- const SwNodeIndex* pInsertPos )
+ const SwNodeIndex* pInsertPos, bool const isForceToStartPos)
{
SwPosition aPos(rStartPos);
for(const SaveFly & rSave : rArr)
@@ -57,7 +58,7 @@ void RestFlyInRange( SaveFlyArr & rArr, const SwPosition& rStartPos,
SwFrameFormat* pFormat = rSave.pFrameFormat;
SwFormatAnchor aAnchor( pFormat->GetAnchor() );
- if (rSave.isAtInsertNode)
+ if (rSave.isAtInsertNode || isForceToStartPos)
{
if( pInsertPos != nullptr )
{
@@ -130,7 +131,7 @@ void SaveFlyInRange( const SwNodeRange& rRg, SaveFlyArr& rArr )
}
void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
- SaveFlyArr& rArr, bool bMoveAllFlys )
+ SaveFlyArr& rArr, bool bMoveAllFlys, SwHistory *const pHistory)
{
SwFrameFormats& rFormats = *rPam.GetPoint()->nNode.GetNode().GetDoc()->GetSpzFrameFormats();
SwFrameFormat* pFormat;
@@ -176,6 +177,10 @@ void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
|| (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()
&& (bInsPos = (rInsPos == *pAPos))))
{
+ if (pHistory)
+ {
+ pHistory->AddChangeFlyAnchor(*pFormat);
+ }
SaveFly aSave( pAPos->nNode.GetIndex() - rSttNdIdx.GetIndex(),
(RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())
? (pAPos->nNode == rSttNdIdx)
diff --git a/sw/source/core/doc/docfld.cxx b/sw/source/core/doc/docfld.cxx
index 8b5f7d467328..c027003c4e97 100644
--- a/sw/source/core/doc/docfld.cxx
+++ b/sw/source/core/doc/docfld.cxx
@@ -26,6 +26,7 @@
#include <unotools/transliterationwrapper.hxx>
#include <doc.hxx>
#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentMarkAccess.hxx>
#include <IDocumentState.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <cntfrm.hxx>
@@ -103,6 +104,24 @@ SetGetExpField::SetGetExpField( const SwSectionNode& rSectNd,
}
}
+SetGetExpField::SetGetExpField(::sw::mark::IBookmark const& rBookmark,
+ SwPosition const*const pPos)
+{
+ m_eSetGetExpFieldType = BOOKMARK;
+ m_CNTNT.pBookmark = &rBookmark;
+
+ if (pPos)
+ {
+ m_nNode = pPos->nNode.GetIndex();
+ m_nContent = pPos->nContent.GetIndex();
+ }
+ else
+ {
+ m_nNode = rBookmark.GetMarkStart().nNode.GetIndex();
+ m_nContent = rBookmark.GetMarkStart().nContent.GetIndex();;
+ }
+}
+
SetGetExpField::SetGetExpField( const SwTableBox& rTBox )
{
m_eSetGetExpFieldType = TABLEBOX;
@@ -272,6 +291,10 @@ const SwNode* SetGetExpField::GetNodeFromContent() const
pRet = m_CNTNT.pSection->GetFormat()->GetSectionNode();
break;
+ case BOOKMARK:
+ pRet = &m_CNTNT.pBookmark->GetMarkStart().nNode.GetNode();
+ break;
+
case CRSRPOS:
pRet = &m_CNTNT.pPos->nNode.GetNode();
break;
@@ -313,6 +336,9 @@ sal_Int32 SetGetExpField::GetCntPosFromContent() const
case TEXTTOXMARK:
nRet = m_CNTNT.pTextTOX->GetStart();
break;
+ case BOOKMARK:
+ nRet = m_CNTNT.pBookmark->GetMarkStart().nContent.GetIndex();
+ break;
case CRSRPOS:
nRet = m_CNTNT.pPos->nContent.GetIndex();
break;
@@ -863,7 +889,20 @@ void SwDocUpdateField::MakeFieldList_( SwDoc& rDoc, int eGetMode )
// add all to the list so that they are sorted
for (const auto &nId : aTmpArr)
{
- GetBodyNode( *rDoc.GetNodes()[ nId ]->GetSectionNode() );
+ SwSectionNode const& rSectionNode(*rDoc.GetNodes()[ nId ]->GetSectionNode());
+ GetBodyNodeGeneric(rSectionNode, rSectionNode);
+ }
+
+ // bookmarks with hide conditions, handle similar to sections
+ auto const& rIDMA(*rDoc.getIDocumentMarkAccess());
+ for (auto it = rIDMA.getBookmarksBegin(); it != rIDMA.getBookmarksEnd(); ++it)
+ {
+ auto const pBookmark(dynamic_cast<::sw::mark::IBookmark const*>(*it));
+ assert(pBookmark);
+ if (!pBookmark->GetHideCondition().isEmpty())
+ {
+ GetBodyNodeGeneric((*it)->GetMarkStart().nNode.GetNode(), *pBookmark);
+ }
}
}
@@ -1040,19 +1079,22 @@ void SwDocUpdateField::GetBodyNode( const SwTextField& rTField, SwFieldIds nFiel
m_pFieldSortList->insert( std::move(pNew) );
}
-void SwDocUpdateField::GetBodyNode( const SwSectionNode& rSectNd )
+template<typename T>
+void SwDocUpdateField::GetBodyNodeGeneric(SwNode const& rNode, T const& rCond)
{
- const SwDoc& rDoc = *rSectNd.GetDoc();
+ const SwDoc& rDoc = *rNode.GetDoc();
std::unique_ptr<SetGetExpField> pNew;
- if( rSectNd.GetIndex() < rDoc.GetNodes().GetEndOfExtras().GetIndex() )
+ if (rNode.GetIndex() < rDoc.GetNodes().GetEndOfExtras().GetIndex())
{
do { // middle check loop
// we need to get the anchor first
// create index to determine the TextNode
- SwPosition aPos( rSectNd );
- SwContentNode* pCNd = rDoc.GetNodes().GoNext( &aPos.nNode ); // to the next ContentNode
+ SwPosition aPos(rNode);
+ SwContentNode const*const pCNd = rNode.IsSectionNode()
+ ? rDoc.GetNodes().GoNext(&aPos.nNode) // to the next ContentNode
+ : rNode.GetContentNode();
if( !pCNd || !pCNd->IsTextNode() )
break;
@@ -1068,13 +1110,13 @@ void SwDocUpdateField::GetBodyNode( const SwSectionNode& rSectNd )
bool const bResult = GetBodyTextNode( rDoc, aPos, *pFrame );
OSL_ENSURE(bResult, "where is the Field");
- pNew.reset(new SetGetExpField( rSectNd, &aPos ));
+ pNew.reset(new SetGetExpField(rCond, &aPos));
} while( false );
}
if( !pNew )
- pNew.reset(new SetGetExpField( rSectNd ));
+ pNew.reset(new SetGetExpField(rCond));
m_pFieldSortList->insert( std::move(pNew) );
}
diff --git a/sw/source/core/doc/doclay.cxx b/sw/source/core/doc/doclay.cxx
index ec4861fe39b2..5b3dc0ef3687 100644
--- a/sw/source/core/doc/doclay.cxx
+++ b/sw/source/core/doc/doclay.cxx
@@ -157,13 +157,12 @@ SwFlyFrameFormat* SwDoc::MakeFlySection_( const SwPosition& rAnchPos,
pFrameFormat = getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_FRAME );
OUString sName;
- if( !mbInReading )
- switch( rNode.GetNodeType() )
- {
+ switch( rNode.GetNodeType() )
+ {
case SwNodeType::Grf: sName = GetUniqueGrfName(); break;
case SwNodeType::Ole: sName = GetUniqueOLEName(); break;
default: sName = GetUniqueFrameName(); break;
- }
+ }
SwFlyFrameFormat* pFormat = MakeFlyFrameFormat( sName, pFrameFormat );
// Create content and connect to the format.
@@ -1408,6 +1407,10 @@ const SwFlyFrameFormat* SwDoc::FindFlyByName( const OUString& rName, SwNodeType
void SwDoc::SetFlyName( SwFlyFrameFormat& rFormat, const OUString& rName )
{
+ if (rFormat.GetName() == rName)
+ {
+ return;
+ }
OUString sName( rName );
if( sName.isEmpty() || FindFlyByName( sName ) )
{
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index 984f2335bc45..6b041fa96c51 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -1054,19 +1054,19 @@ SwNodeIndex SwDoc::AppendDoc(const SwDoc& rSource, sal_uInt16 const nStartPageNu
{
SwNodeIndex aBreakIdx( GetNodes().GetEndOfContent(), -1 );
SwPosition aBreakPos( aBreakIdx );
- // InsertPageBreak just works on SwTextNode nodes, so make
- // sure the last node is one!
- bool bIsTextNode = aBreakIdx.GetNode().IsTextNode();
- if ( !bIsTextNode )
- getIDocumentContentOperations().AppendTextNode( aBreakPos );
- const OUString name = pTargetPageDesc->GetName();
- pTargetShell->InsertPageBreak( &name, nStartPageNumber );
- if ( !bIsTextNode )
- {
- pTargetShell->SttEndDoc( false );
- --aBreakIdx;
- GetNodes().Delete( aBreakIdx );
- }
+ // insert new node - will be removed at the end...
+ // (don't SplitNode() as it may move flys to the wrong node)
+ getIDocumentContentOperations().AppendTextNode(aBreakPos);
+ SwFormatPageDesc pageDesc(pTargetPageDesc);
+ pageDesc.SetNumOffset(nStartPageNumber);
+ // set break on the last paragraph
+ getIDocumentContentOperations().InsertPoolItem(SwPaM(aBreakPos),
+ pageDesc, SetAttrMode::DEFAULT, pTargetShell->GetLayout());
+ // tdf#148309 move to the last node - so that the "flush page break"
+ // code below will format the frame of the node with the page break,
+ // which is required for new page frames to be created! Else layout
+ // performance will be terrible.
+ pTargetShell->SttEndDoc(false);
// There is now a new empty text node on the new page. If it has
// any marks, those are from the previous page: move them back
@@ -1097,6 +1097,7 @@ SwNodeIndex SwDoc::AppendDoc(const SwDoc& rSource, sal_uInt16 const nStartPageNu
if ( !bDeletePrevious )
{
SAL_INFO( "sw.pageframe", "(Flush pagebreak AKA EndAllAction" );
+ assert(pTargetShell->GetCursor()->GetPoint()->nNode.GetNode().GetTextNode()->GetSwAttrSet().HasItem(RES_PAGEDESC));
pTargetShell->EndAllAction();
SAL_INFO( "sw.pageframe", "Flush changes AKA EndAllAction)" );
pTargetShell->StartAllAction();
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index ee8e8b23d8c0..66c6af16f4c9 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -1784,7 +1784,7 @@ OUString SwRangeRedline::GetDescr()
OUString sDescr = DenoteSpecialCharacters(pPaM->GetText());
if (const SwTextNode *pTextNode = pPaM->GetNode().GetTextNode())
{
- if (const SwTextAttr* pTextAttr = pTextNode->GetFieldTextAttrAt(pPaM->GetPoint()->nContent.GetIndex() - 1, true ))
+ if (const SwTextAttr* pTextAttr = pTextNode->GetFieldTextAttrAt(pPaM->GetPoint()->nContent.GetIndex() - 1, ::sw::GetTextAttrMode::Default))
{
sDescr = SwResId(STR_START_QUOTE)
+ pTextAttr->GetFormatField().GetField()->GetFieldName()
diff --git a/sw/source/core/doc/tblafmt.cxx b/sw/source/core/doc/tblafmt.cxx
index 35e626a0f5a1..3ff7ef02b6d0 100644
--- a/sw/source/core/doc/tblafmt.cxx
+++ b/sw/source/core/doc/tblafmt.cxx
@@ -1021,7 +1021,7 @@ SwTableAutoFormatTable::SwTableAutoFormatTable()
SvxBoxItem aBox( RES_BOX );
aBox.SetAllDistances(55);
- SvxBorderLine aLn( &aColor, DEF_LINE_WIDTH_5 );
+ SvxBorderLine aLn( &aColor, SvxBorderLineWidth::VeryThin );
aBox.SetLine( &aLn, SvxBoxItemLine::LEFT );
aBox.SetLine( &aLn, SvxBoxItemLine::BOTTOM );
diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index ea57aa58319d..40d1bb607c1e 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -90,7 +90,8 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape)
xPropertySet->setPropertyValue(UNO_NAME_SURROUND, uno::makeAny(text::WrapTextMode_THROUGH));
uno::Reference<container::XNamed> xNamed(xTextFrame, uno::UNO_QUERY);
- xNamed->setName(pShape->GetDoc()->GetUniqueFrameName());
+ assert(!xNamed->getName().isEmpty());
+ (void)xNamed;
// Link its text range to the original shape.
uno::Reference<text::XTextRange> xTextBox(xTextFrame, uno::UNO_QUERY_THROW);
diff --git a/sw/source/core/docnode/ndsect.cxx b/sw/source/core/docnode/ndsect.cxx
index 8c2efee0eb7e..6154cfc7d776 100644
--- a/sw/source/core/docnode/ndsect.cxx
+++ b/sw/source/core/docnode/ndsect.cxx
@@ -535,7 +535,7 @@ void SwDoc::DelSectionFormat( SwSectionFormat *pFormat, bool bDelNodes )
{
SwNodeIndex aUpdIdx( *pIdx );
SwPaM aPaM( *pSectNd->EndOfSectionNode(), *pSectNd );
- GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoDelete>( aPaM ));
+ GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoDelete>(aPaM, SwDeleteFlags::Default));
if( pFootnoteEndAtTextEnd )
GetFootnoteIdxs().UpdateFootnote( aUpdIdx );
getIDocumentState().SetModified();
diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx
index 15a49729ce51..e6731feba860 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -114,11 +114,11 @@ static void lcl_SetDfltBoxAttr( SwFrameFormat& rFormat, sal_uInt8 nId )
const bool bHTML = rFormat.getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE);
Color aCol( bHTML ? COL_GRAY : COL_BLACK );
- SvxBorderLine aLine( &aCol, DEF_LINE_WIDTH_0 );
+ // Default border in Writer: 0.5pt (matching Word)
+ SvxBorderLine aLine( &aCol, SvxBorderLineWidth::VeryThin );
if ( bHTML )
{
aLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
- aLine.SetWidth( DEF_LINE_WIDTH_0 );
}
SvxBoxItem aBox(RES_BOX);
aBox.SetAllDistances(55);
@@ -2040,7 +2040,7 @@ bool SwDoc::DeleteRowCol( const SwSelBoxes& rBoxes, bool bColumn )
bSavePageBreak = true;
}
}
- std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete( aPaM ));
+ std::unique_ptr<SwUndoDelete> pUndo(new SwUndoDelete(aPaM, SwDeleteFlags::Default));
if( bNewTextNd )
pUndo->SetTableDelLastNd();
pUndo->SetPgBrkFlags( bSavePageBreak, bSavePageDesc );
diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx
index 955e113f2768..0bf2729cd02c 100644
--- a/sw/source/core/docnode/node.cxx
+++ b/sw/source/core/docnode/node.cxx
@@ -1384,6 +1384,12 @@ void SwContentNode::DelFrames(SwRootFrame const*const pLayout)
pMerged->pParaPropsNode = pNode->GetTextNode();
break;
}
+ else if (pMerged->pFirstNode->GetIndex() == i)
+ { // this can only happen when called from CheckParaRedlineMerge()
+ // and the pMerged will be deleted anyway
+ pMerged->pParaPropsNode = pMerged->pFirstNode;
+ break;
+ }
}
assert(pMerged->listener.IsListeningTo(pMerged->pParaPropsNode));
}
diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx
index 2a2bef4f4488..28088536c7ba 100644
--- a/sw/source/core/docnode/nodes.cxx
+++ b/sw/source/core/docnode/nodes.cxx
@@ -43,6 +43,7 @@
#include <fmtftn.hxx>
#include <docsh.hxx>
+#include <rootfrm.hxx>
typedef std::vector<SwStartNode*> SwStartNodePointers;
@@ -2035,90 +2036,108 @@ SwContentNode* SwNodes::GoPrevSection( SwNodeIndex * pIdx,
return nullptr;
}
-//TODO: improve documentation
//TODO: The inventor of the "single responsibility principle" will be crying if you ever show this code to him!
-/** find the next/previous ContentNode or a table node with frames
+/** find the next/previous ContentNode or table node that should have layout
+ * frames that are siblings to the ones of the node at rFrameIdx.
*
- * If no pEnd is given, search is started with FrameIndex; otherwise
- * search is started with the one before rFrameIdx and after pEnd.
+ * Search is started backward with the one before rFrameIdx and
+ * forward after pEnd.
*
- * @param rFrameIdx node with frames to search in
- * @param pEnd ???
- * @return result node; 0 (!!!) if not found
+ * @param rFrameIdx in: node with frames to search in; out: found node
+ * @param pEnd last node after rFrameIdx that should be excluded from search
+ * @return result node; 0 if not found
*/
SwNode* SwNodes::FindPrvNxtFrameNode( SwNodeIndex& rFrameIdx,
- const SwNode* pEnd ) const
+ SwNode const*const pEnd,
+ SwRootFrame const*const pLayout) const
{
+ assert(pEnd != nullptr); // every caller currently
+
SwNode* pFrameNd = nullptr;
// no layout -> skip
if( GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell() )
{
- SwNode* pSttNd = &rFrameIdx.GetNode();
+ SwNode *const pSttNd = &rFrameIdx.GetNode();
- // move of a hidden section?
- SwSectionNode* pSectNd = pSttNd->IsSectionNode()
+ // inside a hidden section?
+ SwSectionNode *const pSectNd = pSttNd->IsSectionNode()
? pSttNd->StartOfSectionNode()->FindSectionNode()
: pSttNd->FindSectionNode();
if( !( pSectNd && pSectNd->GetSection().CalcHiddenFlag() ) )
{
// in a table in table situation we have to assure that we don't leave the
// outer table cell when the inner table is looking for a PrvNxt...
- SwTableNode* pTableNd = pSttNd->IsTableNode()
+ SwTableNode *const pTableNd = pSttNd->IsTableNode()
? pSttNd->StartOfSectionNode()->FindTableNode()
: pSttNd->FindTableNode();
SwNodeIndex aIdx( rFrameIdx );
- SwNode* pNd;
- if( pEnd )
- {
- --aIdx;
- pNd = &aIdx.GetNode();
- }
- else
- pNd = pSttNd;
-
- if( ( pFrameNd = pNd )->IsContentNode() )
- rFrameIdx = aIdx;
-
- // search forward or backward for a content node
- else if( nullptr != ( pFrameNd = GoPrevSection( &aIdx, true, false )) &&
- ::CheckNodesRange( aIdx, rFrameIdx, true ) &&
- // Never out of the table at the start
- pFrameNd->FindTableNode() == pTableNd &&
- // Bug 37652: Never out of the table at the end
- (!pFrameNd->FindTableNode() || pFrameNd->FindTableBoxStartNode()
- == pSttNd->FindTableBoxStartNode() ) &&
- (!pSectNd || pSttNd->IsSectionNode() ||
- pSectNd->GetIndex() < pFrameNd->GetIndex())
- )
+
+ // search backward for a content or table node
+
+ --aIdx;
+ pFrameNd = &aIdx.GetNode();
+
+ do
{
- rFrameIdx = aIdx;
+ if (pFrameNd->IsContentNode())
+ {
+ // TODO why does this not check for nested tables like forward direction
+ rFrameIdx = aIdx;
+ return pFrameNd;
+ }
+ else if (pFrameNd->IsEndNode() && pFrameNd->StartOfSectionNode()->IsTableNode())
+ {
+ if (pLayout == nullptr
+ || !pLayout->IsHideRedlines()
+ || pFrameNd->StartOfSectionNode()->GetRedlineMergeFlag() != SwNode::Merge::Hidden)
+ {
+ pFrameNd = pFrameNd->StartOfSectionNode();
+ rFrameIdx = *pFrameNd;
+ return pFrameNd;
+ }
+ else
+ {
+ aIdx = *pFrameNd->StartOfSectionNode();
+ --aIdx;
+ pFrameNd = &aIdx.GetNode();
+ }
+ }
+ else
+ {
+ pFrameNd = GoPrevSection( &aIdx, true, false );
+ if ( nullptr != pFrameNd && !(
+ ::CheckNodesRange( aIdx, rFrameIdx, true ) &&
+ // Never out of the table at the start
+ pFrameNd->FindTableNode() == pTableNd &&
+ // Bug 37652: Never out of the table at the end
+ (!pFrameNd->FindTableNode() || pFrameNd->FindTableBoxStartNode()
+ == pSttNd->FindTableBoxStartNode() ) &&
+ (!pSectNd || pSttNd->IsSectionNode() ||
+ pSectNd->GetIndex() < pFrameNd->GetIndex())
+ ))
+ {
+ pFrameNd = nullptr; // no preceding content node, stop search
+ }
+ }
}
- else
+ while (pFrameNd != nullptr);
+
+ // search forward for a content or table node
+
+ aIdx = pEnd->GetIndex() + 1;
+ pFrameNd = &aIdx.GetNode();
+
+ do
{
- if( pEnd )
- aIdx = pEnd->GetIndex() + 1;
- else
- aIdx = rFrameIdx;
-
- // NEVER leave the section when doing this!
- if( ( pEnd && ( pFrameNd = &aIdx.GetNode())->IsContentNode() ) ||
- ( nullptr != ( pFrameNd = GoNextSection( &aIdx, true, false )) &&
- ::CheckNodesRange( aIdx, rFrameIdx, true ) &&
- ( pFrameNd->FindTableNode() == pTableNd &&
- // NEVER go out of the table cell at the end
- (!pFrameNd->FindTableNode() || pFrameNd->FindTableBoxStartNode()
- == pSttNd->FindTableBoxStartNode() ) ) &&
- (!pSectNd || pSttNd->IsSectionNode() ||
- pSectNd->EndOfSectionIndex() > pFrameNd->GetIndex())
- ))
+ if (pFrameNd->IsContentNode())
{
// Undo when merging a table with one before, if there is also one after it.
// However, if the node is in a table, it needs to be returned if the
// SttNode is a section or a table!
- SwTableNode* pTableNode;
+ SwTableNode *const pTableNode = pFrameNd->FindTableNode();
if (pSttNd->IsTableNode() &&
- nullptr != (pTableNode = pFrameNd->FindTableNode()) &&
+ nullptr != pTableNode &&
// TABLE IN TABLE:
pTableNode != pSttNd->StartOfSectionNode()->FindTableNode())
{
@@ -2126,23 +2145,54 @@ SwNode* SwNodes::FindPrvNxtFrameNode( SwNodeIndex& rFrameIdx,
rFrameIdx = *pFrameNd;
}
else
+ {
rFrameIdx = aIdx;
+ }
+ return pFrameNd;
}
- else if( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsTableNode() )
+ else if (pFrameNd->IsTableNode())
{
- pFrameNd = pNd->StartOfSectionNode();
- rFrameIdx = *pFrameNd;
+ if (pLayout == nullptr
+ || !pLayout->IsHideRedlines()
+ || pFrameNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden)
+ {
+ rFrameIdx = *pFrameNd;
+ return pFrameNd;
+ }
+ else
+ {
+ aIdx = *pFrameNd->EndOfSectionNode();
+ ++aIdx;
+ pFrameNd = &aIdx.GetNode();
+ }
}
else
{
- if( pEnd )
- aIdx = pEnd->GetIndex() + 1;
- else
- aIdx = rFrameIdx.GetIndex() + 1;
+ pFrameNd = GoNextSection( &aIdx, true, false );
+ // NEVER leave the section when doing this!
+ if (pFrameNd
+ && !(::CheckNodesRange(aIdx, rFrameIdx, true)
+ && (pFrameNd->FindTableNode() == pTableNd &&
+ // NEVER go out of the table cell at the end
+ (!pFrameNd->FindTableNode() || pFrameNd->FindTableBoxStartNode()
+ == pSttNd->FindTableBoxStartNode()))
+ && (!pSectNd || pSttNd->IsSectionNode() ||
+ pSectNd->EndOfSectionIndex() > pFrameNd->GetIndex()))
+ )
+ {
+ pFrameNd = nullptr; // no following content node, stop search
+ }
+ }
+ }
+ while (pFrameNd != nullptr);
- if( (pFrameNd = &aIdx.GetNode())->IsTableNode() )
- rFrameIdx = aIdx;
- else
+ // probably this is dead code, because the GoNextSection()
+ // should have ended up in the first text node in the table and
+ // then checked it's in a table?
+ {
+ aIdx = pEnd->GetIndex() + 1;
+
+ pFrameNd = &aIdx.GetNode();
{
pFrameNd = nullptr;
@@ -2160,9 +2210,9 @@ SwNode* SwNodes::FindPrvNxtFrameNode( SwNodeIndex& rFrameIdx,
{
rFrameIdx = aIdx;
pFrameNd = &aIdx.GetNode();
+ assert(!"this isn't dead code?");
}
}
- }
}
}
}
diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
index 9d057bcabc7d..5f05c4d21cd7 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -476,8 +476,28 @@ SwFlyDrawContact::~SwFlyDrawContact()
}
}
-sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly)
+sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly,
+ SwFrame const& rAnchorFrame)
{
+ // maintain invariant that a shape's textbox immediately follows the shape
+ // also for the multiple SdrVirtObj created for shapes in header/footer
+ if (SwFrameFormat const*const pDrawFormat =
+ SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT))
+ {
+ // assume that the draw SdrVirtObj is always created before the flyframe one
+ if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
+ {
+ for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
+ {
+ if (&pAnchoredObj->GetFrameFormat() == pDrawFormat)
+ {
+ return pAnchoredObj->GetDrawObj()->GetOrdNum() + 1;
+ }
+ }
+ }
+ // if called from AppendObjs(), this is a problem; if called from lcl_SetFlyFrameAttr() it's not
+ SAL_INFO("sw", "GetOrdNumForNewRef: cannot find SdrObject for text box's shape");
+ }
// search for another Writer fly frame registered at same frame format
SwIterator<SwFlyFrame,SwFormat> aIter(*GetFormat());
const SwFlyFrame* pFlyFrame(nullptr);
@@ -499,7 +519,8 @@ sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly)
return GetMaster()->GetOrdNumDirect();
}
-SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly, SwFlyFrameFormat* pFormat)
+SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly,
+ SwFlyFrameFormat* pFormat, SwFrame const& rAnchorFrame)
{
// Find ContactObject from the Format. If there's already one, we just
// need to create a new Ref, else we create the Contact now.
@@ -526,7 +547,7 @@ SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly, SwFlyFrameFor
// #i27030# - insert new <SwVirtFlyDrawObj> instance
// into drawing page with correct order number
else
- rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj, pContact->GetOrdNumForNewRef(pFly));
+ rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj, pContact->GetOrdNumForNewRef(pFly, rAnchorFrame));
// #i38889# - assure, that new <SwVirtFlyDrawObj> instance
// is in a visible layer.
pContact->MoveObjToVisibleLayer(pDrawObj);
@@ -804,7 +825,7 @@ SwFrame* SwDrawContact::GetAnchorFrame(SdrObject const *const pDrawObj)
/** add a 'virtual' drawing object to drawing page.
*/
-SwDrawVirtObj* SwDrawContact::AddVirtObj()
+SwDrawVirtObj* SwDrawContact::AddVirtObj(SwFrame const& rAnchorFrame)
{
maDrawVirtObjs.push_back(
SwDrawVirtObjPtr(
@@ -812,7 +833,7 @@ SwDrawVirtObj* SwDrawContact::AddVirtObj()
GetMaster()->getSdrModelFromSdrObject(),
*GetMaster(),
*this)));
- maDrawVirtObjs.back()->AddToDrawingPage();
+ maDrawVirtObjs.back()->AddToDrawingPage(rAnchorFrame);
return maDrawVirtObjs.back().get();
}
@@ -1871,7 +1892,7 @@ void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
else
{
// append 'virtual' drawing object
- SwDrawVirtObj* pDrawVirtObj = AddVirtObj();
+ SwDrawVirtObj* pDrawVirtObj = AddVirtObj(*pFrame);
if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
{
ClrContourCache( pDrawVirtObj );
@@ -2220,30 +2241,56 @@ void SwDrawVirtObj::RemoveFromWriterLayout()
}
}
-void SwDrawVirtObj::AddToDrawingPage()
+void SwDrawVirtObj::AddToDrawingPage(SwFrame const& rAnchorFrame)
{
// determine 'master'
SdrObject* pOrgMasterSdrObj = mrDrawContact.GetMaster();
// insert 'virtual' drawing object into page, set layer and user call.
SdrPage* pDrawPg;
+ // default: insert before master object
+ auto NOTM_nOrdNum(GetReferencedObj().GetOrdNum());
+
+ // maintain invariant that a shape's textbox immediately follows the shape
+ // also for the multiple SdrDrawVirtObj created for shapes in header/footer
+ if (SwFrameFormat const*const pFlyFormat =
+ SwTextBoxHelper::getOtherTextBoxFormat(mrDrawContact.GetFormat(), RES_DRAWFRMFMT))
+ {
+ // this is for the case when the flyframe SdrVirtObj is created before the draw one
+ if (SwSortedObjs const*const pObjs = rAnchorFrame.GetDrawObjs())
+ {
+ for (SwAnchoredObject const*const pAnchoredObj : *pObjs)
+ {
+ if (&pAnchoredObj->GetFrameFormat() == pFlyFormat)
+ {
+ assert(dynamic_cast<SwFlyFrame const*>(pAnchoredObj));
+ NOTM_nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
+ // the master SdrObj should have the highest index
+ assert(NOTM_nOrdNum < GetReferencedObj().GetOrdNum());
+ break;
+ }
+ }
+ }
+ // this happens on initial insertion, the draw object is created first
+ SAL_INFO_IF(GetReferencedObj().GetOrdNum() == NOTM_nOrdNum, "sw", "AddToDrawingPage: cannot find SdrObject for text box's shape");
+ }
+
// #i27030# - apply order number of referenced object
if ( nullptr != ( pDrawPg = pOrgMasterSdrObj->getSdrPageFromSdrObject() ) )
{
// #i27030# - apply order number of referenced object
- pDrawPg->InsertObject( this, GetReferencedObj().GetOrdNum() );
+ pDrawPg->InsertObject(this, NOTM_nOrdNum);
}
else
{
pDrawPg = getSdrPageFromSdrObject();
if ( pDrawPg )
{
- pDrawPg->SetObjectOrdNum( GetOrdNumDirect(),
- GetReferencedObj().GetOrdNum() );
+ pDrawPg->SetObjectOrdNum(GetOrdNumDirect(), NOTM_nOrdNum);
}
else
{
- SetOrdNum( GetReferencedObj().GetOrdNum() );
+ SetOrdNum(NOTM_nOrdNum);
}
}
SetUserCall( &mrDrawContact );
diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx
index c1a7b6a8cbbc..b20ae1031382 100644
--- a/sw/source/core/draw/dview.cxx
+++ b/sw/source/core/draw/dview.cxx
@@ -231,6 +231,11 @@ void SwDrawView::AddCustomHdl()
// #i28701# - use last character rectangle saved at object
// in order to avoid a format of the anchor frame
SwAnchoredObject* pAnchoredObj = ::GetUserCall( pObj )->GetAnchoredObj( pObj );
+
+ // Invalidate/recalc LastCharRect which can contain invalid frame offset because
+ // of later frame changes
+ pAnchoredObj->CheckCharRectAndTopOfLine(false);
+
SwRect aAutoPos = pAnchoredObj->GetLastCharRect();
if ( aAutoPos.Height() )
{
diff --git a/sw/source/core/edit/acorrect.cxx b/sw/source/core/edit/acorrect.cxx
index 7304e6e7b702..286d4d078de5 100644
--- a/sw/source/core/edit/acorrect.cxx
+++ b/sw/source/core/edit/acorrect.cxx
@@ -346,8 +346,11 @@ OUString const* SwAutoCorrDoc::GetPrevPara(bool const bAtNormalPos)
}
sw::GotoPrevLayoutTextFrame(*pIdx, rEditSh.GetLayout());
}
- if (pFrame && 0 == pFrame->GetTextNodeForParaProps()->GetAttrOutlineLevel())
+ if (pFrame && !pFrame->GetText().isEmpty() &&
+ 0 == pFrame->GetTextNodeForParaProps()->GetAttrOutlineLevel())
+ {
pStr = & pFrame->GetText();
+ }
if( bUndoIdInitialized )
bUndoIdInitialized = true;
diff --git a/sw/source/core/edit/autofmt.cxx b/sw/source/core/edit/autofmt.cxx
index a3687b5e308c..80b91de1d649 100644
--- a/sw/source/core/edit/autofmt.cxx
+++ b/sw/source/core/edit/autofmt.cxx
@@ -571,29 +571,29 @@ bool SwAutoFormat::DoUnderline()
editeng::SvxBorderLine aLine;
switch( eState )
{
- case 1: // single, 0.05 pt
+ case 1: // single, hairline
aLine.SetBorderLineStyle(SvxBorderLineStyle::SOLID);
- aLine.SetWidth( DEF_LINE_WIDTH_0 );
+ aLine.SetWidth( SvxBorderLineWidth::Hairline );
break;
- case 2: // single, 1.0 pt
+ case 2: // single, thin
aLine.SetBorderLineStyle(SvxBorderLineStyle::SOLID);
- aLine.SetWidth( DEF_LINE_WIDTH_1 );
+ aLine.SetWidth( SvxBorderLineWidth::Thin );
break;
- case 3: // double, 1.0 pt
+ case 3: // double, thin
aLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
- aLine.SetWidth( DEF_LINE_WIDTH_1 );
+ aLine.SetWidth( SvxBorderLineWidth::Thin );
break;
- case 4: // double (thick/thin), 4.0 pt
+ case 4: // double, thick/thin
aLine.SetBorderLineStyle(SvxBorderLineStyle::THICKTHIN_SMALLGAP);
- aLine.SetWidth( DEF_LINE_WIDTH_3 );
+ aLine.SetWidth( SvxBorderLineWidth::Thick );
break;
- case 5: // double (thin/thick), 4.0 pt
+ case 5: // double, thin/thick
aLine.SetBorderLineStyle(SvxBorderLineStyle::THINTHICK_SMALLGAP);
- aLine.SetWidth( DEF_LINE_WIDTH_3 );
+ aLine.SetWidth( SvxBorderLineWidth::Thick );
break;
- case 6: // double, 2.5 pt
+ case 6: // double, medium
aLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
- aLine.SetWidth( DEF_LINE_WIDTH_2 );
+ aLine.SetWidth( SvxBorderLineWidth::Medium );
break;
}
SfxItemSet aSet(m_pDoc->GetAttrPool(),
@@ -1196,7 +1196,7 @@ void SwAutoFormat::DeleteSelImpl(SwPaM & rDelPam, SwPaM & rPamToCorrect)
SwPaM* pPrev = rPamToCorrect.GetPrev();
rPamToCorrect.GetRingContainer().merge( pShCursor->GetRingContainer() );
- m_pEditShell->DeleteSel( rDelPam );
+ m_pEditShell->DeleteSel(rDelPam, true);
// and remove Pam again:
SwPaM* p;
@@ -1212,7 +1212,7 @@ void SwAutoFormat::DeleteSelImpl(SwPaM & rDelPam, SwPaM & rPamToCorrect)
m_pCurTextFrame = GetFrame(*m_pCurTextNd); // keep it up to date
}
else
- m_pEditShell->DeleteSel( rDelPam );
+ m_pEditShell->DeleteSel(rDelPam, true);
}
bool SwAutoFormat::DeleteJoinCurNextPara(SwTextFrame const*const pNextFrame,
@@ -1904,11 +1904,14 @@ void SwAutoFormat::BuildHeadLine( sal_uInt16 nLvl )
JoinPrevPara();
DeleteLeadingTrailingBlanks( true, false );
- const SwTextFrame *const pNextFrame = GetNextNode(false);
- (void)DeleteJoinCurNextPara(pNextFrame, true);
-
+ const SwTextFrame* pNextFrame = GetNextNode(false);
+ if (pNextFrame->GetNext())
+ {
+ (void)DeleteJoinCurNextPara(pNextFrame, true);
+ pNextFrame = GetNextNode(false);
+ }
m_aDelPam.DeleteMark();
- m_aDelPam.GetPoint()->nNode = *GetNextNode(false)->GetTextNodeForParaProps();
+ m_aDelPam.GetPoint()->nNode = *pNextFrame->GetTextNodeForParaProps();
m_aDelPam.GetPoint()->nContent.Assign( m_aDelPam.GetContentNode(), 0 );
m_pDoc->SetTextFormatColl( m_aDelPam, &rNxtColl );
}
diff --git a/sw/source/core/edit/edatmisc.cxx b/sw/source/core/edit/edatmisc.cxx
index e8f82956106f..c70c90182a0b 100644
--- a/sw/source/core/edit/edatmisc.cxx
+++ b/sw/source/core/edit/edatmisc.cxx
@@ -184,8 +184,8 @@ void SwEditShell::SetAttrSet( const SfxItemSet& rSet, SetAttrMode nFlags, SwPaM*
GetDoc()->getIDocumentContentOperations().InsertItemSet(*pCursor, rSet, nFlags, GetLayout());
}
- EndAllAction();
GetDoc()->getIDocumentRedlineAccess().SetRedlineFlags( eOldMode );
+ EndAllAction();
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/edit/eddel.cxx b/sw/source/core/edit/eddel.cxx
index 74e845353566..37c19e60a91e 100644
--- a/sw/source/core/edit/eddel.cxx
+++ b/sw/source/core/edit/eddel.cxx
@@ -38,7 +38,7 @@
#include <strings.hrc>
#include <vector>
-void SwEditShell::DeleteSel( SwPaM& rPam, bool* pUndo )
+void SwEditShell::DeleteSel(SwPaM& rPam, bool const isArtificialSelection, bool *const pUndo)
{
bool bSelectAll = StartsWithTable() && ExtendedSelectedAll();
// only for selections
@@ -121,7 +121,8 @@ void SwEditShell::DeleteSel( SwPaM& rPam, bool* pUndo )
pPam = pNewPam.get();
}
// delete everything
- GetDoc()->getIDocumentContentOperations().DeleteAndJoin(*pPam);
+ GetDoc()->getIDocumentContentOperations().DeleteAndJoin(*pPam,
+ isArtificialSelection ? SwDeleteFlags::ArtificialSelection : SwDeleteFlags::Default);
SaveTableBoxContent( pPam->GetPoint() );
}
@@ -129,7 +130,7 @@ void SwEditShell::DeleteSel( SwPaM& rPam, bool* pUndo )
rPam.DeleteMark();
}
-bool SwEditShell::Delete()
+bool SwEditShell::Delete(bool const isArtificialSelection)
{
SET_CURR_SHELL( this );
bool bRet = false;
@@ -148,7 +149,7 @@ bool SwEditShell::Delete()
for(SwPaM& rPaM : GetCursor()->GetRingContainer())
{
- DeleteSel( rPaM, &bUndo );
+ DeleteSel(rPaM, isArtificialSelection, &bUndo);
}
// If undo container then close here
diff --git a/sw/source/core/edit/edfld.cxx b/sw/source/core/edit/edfld.cxx
index 7525a9af80af..75364a42bd1d 100644
--- a/sw/source/core/edit/edfld.cxx
+++ b/sw/source/core/edit/edfld.cxx
@@ -149,7 +149,7 @@ void SwEditShell::FieldToText( SwFieldType const * pType )
}
/// add a field at the cursor position
-void SwEditShell::Insert2(SwField const & rField, const bool bForceExpandHints)
+bool SwEditShell::InsertField(SwField const & rField, const bool bForceExpandHints)
{
SET_CURR_SHELL( this );
StartAllAction();
@@ -159,13 +159,15 @@ void SwEditShell::Insert2(SwField const & rField, const bool bForceExpandHints)
? SetAttrMode::FORCEHINTEXPAND
: SetAttrMode::DEFAULT;
+ bool bSuccess(false);
for(const SwPaM& rPaM : GetCursor()->GetRingContainer()) // for each PaM
{
- const bool bSuccess(GetDoc()->getIDocumentContentOperations().InsertPoolItem(rPaM, aField, nInsertFlags));
+ bSuccess |= GetDoc()->getIDocumentContentOperations().InsertPoolItem(rPaM, aField, nInsertFlags);
OSL_ENSURE( bSuccess, "Doc->Insert(Field) failed");
}
EndAllAction();
+ return bSuccess;
}
/// Are the PaMs positioned on fields?
@@ -223,7 +225,7 @@ void SwEditShell::UpdateOneField(SwField &rField)
if ( !pCursor->IsMultiSelection() && !pCursor->HasMark())
{
- pTextField = GetTextFieldAtPos( pCursor->Start(), true );
+ pTextField = GetTextFieldAtPos(pCursor->Start(), ::sw::GetTextAttrMode::Default);
if (!pTextField) // #i30221#
pTextField = lcl_FindInputField( GetDoc(), rField);
@@ -268,7 +270,8 @@ void SwEditShell::UpdateOneField(SwField &rField)
if( aPam.Start()->nContent != pCurStt->nContent )
bOkay = false;
- if( nullptr != (pTextField = GetTextFieldAtPos( pCurStt, true )) )
+ pTextField = GetTextFieldAtPos(pCurStt, ::sw::GetTextAttrMode::Default);
+ if( nullptr != pTextField )
{
pFormatField = const_cast<SwFormatField*>(&pTextField->GetFormatField());
SwField *pCurField = pFormatField->GetField();
diff --git a/sw/source/core/edit/edglbldc.cxx b/sw/source/core/edit/edglbldc.cxx
index 3d916edc5fe0..c5ea9081d043 100644
--- a/sw/source/core/edit/edglbldc.cxx
+++ b/sw/source/core/edit/edglbldc.cxx
@@ -272,7 +272,7 @@ void SwEditShell::DeleteGlobalDocContent( const SwGlblDocContents& rArr ,
rPos.nNode = pMyDoc->GetNodes().GetEndOfContent();
--rPos.nNode;
if( !pMyDoc->getIDocumentContentOperations().DelFullPara( *pCursor ) )
- Delete();
+ Delete(false);
}
break;
diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx
index 8f84ce42ed75..699997003daf 100644
--- a/sw/source/core/edit/editsh.cxx
+++ b/sw/source/core/edit/editsh.cxx
@@ -663,7 +663,7 @@ bool SwEditShell::InsertURL( const SwFormatINetFormat& rFormat, const OUString&
bDelText = bInsText = false;
if( bDelText )
- Delete();
+ Delete(true);
}
else if( pCursor->IsMultiSelection() && rFormat.GetValue() == rStr )
bInsText = false;
@@ -732,7 +732,7 @@ void SwEditShell::DelINetAttrWithText()
{
bool bRet = SelectTextAttr( RES_TXTATR_INETFMT, false );
if( bRet )
- DeleteSel( *GetCursor() );
+ DeleteSel(*GetCursor(), true);
}
/// Set the DontExpand flag at the text character attributes
diff --git a/sw/source/core/edit/edlingu.cxx b/sw/source/core/edit/edlingu.cxx
index 69446dd9b060..8c50eadd8740 100644
--- a/sw/source/core/edit/edlingu.cxx
+++ b/sw/source/core/edit/edlingu.cxx
@@ -823,11 +823,16 @@ void SwEditShell::HandleCorrectionError(const OUString& aText, SwPosition aPos,
SwRect& rSelectRect)
{
// save the start and end positions of the line and the starting point
+ SwNode const& rNode(GetCursor()->GetPoint()->nNode.GetNode());
Push();
LeftMargin();
- const sal_Int32 nLineStart = GetCursor()->GetPoint()->nContent.GetIndex();
+ const sal_Int32 nLineStart = &rNode == &GetCursor()->GetPoint()->nNode.GetNode()
+ ? GetCursor()->GetPoint()->nContent.GetIndex()
+ : 0;
RightMargin();
- const sal_Int32 nLineEnd = GetCursor()->GetPoint()->nContent.GetIndex();
+ const sal_Int32 nLineEnd = &rNode == &GetCursor()->GetPoint()->nNode.GetNode()
+ ? GetCursor()->GetPoint()->nContent.GetIndex()
+ : rNode.GetTextNode()->Len();
Pop(PopMode::DeleteCurrent);
// make sure the selection build later from the data below does
@@ -909,8 +914,14 @@ uno::Reference< XSpellAlternatives >
if (pWrong->InWrongWord(nBegin, nLen) && !pNode->IsSymbolAt(nBegin))
{
const OUString aText(pNode->GetText().copy(nBegin, nLen));
- OUString aWord = aText.replaceAll(OUStringChar(CH_TXTATR_BREAKWORD), "")
- .replaceAll(OUStringChar(CH_TXTATR_INWORD), "");
+ // TODO: this doesn't handle fieldmarks properly
+ ModelToViewHelper const aConversionMap(*pNode, GetLayout(),
+ ExpandMode::ExpandFields | ExpandMode::ExpandFootnote | ExpandMode::ReplaceMode
+ | (GetLayout()->IsHideRedlines() ? ExpandMode::HideDeletions : ExpandMode(0))
+ | (GetViewOptions()->IsShowHiddenChar() ? ExpandMode(0) : ExpandMode::HideInvisible));
+ auto const nBeginView(aConversionMap.ConvertToViewPosition(nBegin));
+ OUString const aWord(aConversionMap.getViewText().copy(nBeginView,
+ aConversionMap.ConvertToViewPosition(nBegin+nLen) - nBeginView));
uno::Reference< XSpellChecker1 > xSpell( ::GetSpellChecker() );
if( xSpell.is() )
diff --git a/sw/source/core/edit/edws.cxx b/sw/source/core/edit/edws.cxx
index dd5381cbb9eb..4991b9376a89 100644
--- a/sw/source/core/edit/edws.cxx
+++ b/sw/source/core/edit/edws.cxx
@@ -265,6 +265,12 @@ void SwEditShell::AutoCorrect( SvxAutoCorrect& rACorr, bool bInsert,
// FIXME: this _must_ be called with reference to the actual node text!
SwTextFrame const*const pFrame(static_cast<SwTextFrame const*>(pTNd->getLayoutFrame(GetLayout())));
TextFrameIndex const nPos(pFrame->MapModelToViewPos(*pCursor->GetPoint()));
+ // tdf#147414 sw_redlinehide: if cursor moved backward, it may be at the
+ // start of a delete redline - but MapViewToModelPos() always returns end
+ // of redline and it will be called when AutoCorrect actually inserts
+ // something - so first normalize cursor point to end of redline so that
+ // point will then be moved forward when something is inserted.
+ *pCursor->GetPoint() = pFrame->MapViewToModelPos(nPos);
OUString const& rMergedText(pFrame->GetText());
rACorr.DoAutoCorrect( aSwAutoCorrDoc,
rMergedText, sal_Int32(nPos),
diff --git a/sw/source/core/fields/expfld.cxx b/sw/source/core/fields/expfld.cxx
index 673e257e0554..c702e17d1cd5 100644
--- a/sw/source/core/fields/expfld.cxx
+++ b/sw/source/core/fields/expfld.cxx
@@ -1313,6 +1313,7 @@ std::unique_ptr<SwField> SwInputField::Copy() const
pField->SetHelp( maHelp );
pField->SetToolTip( maToolTip );
+ pField->maGrabBag = maGrabBag;
pField->SetAutomaticLanguage(IsAutomaticLanguage());
return std::unique_ptr<SwField>(pField.release());
@@ -1359,6 +1360,9 @@ bool SwInputField::QueryValue( uno::Any& rAny, sal_uInt16 nWhichId ) const
case FIELD_PROP_PAR4:
rAny <<= maToolTip;
break;
+ case FIELD_PROP_GRABBAG:
+ rAny <<= maGrabBag;
+ break;
default:
assert(false);
}
@@ -1381,6 +1385,9 @@ bool SwInputField::PutValue( const uno::Any& rAny, sal_uInt16 nWhichId )
case FIELD_PROP_PAR4:
rAny >>= maToolTip;
break;
+ case FIELD_PROP_GRABBAG:
+ rAny >>= maGrabBag;
+ break;
default:
assert(false);
}
diff --git a/sw/source/core/fields/reffld.cxx b/sw/source/core/fields/reffld.cxx
index c4825a9343df..9aaf9b2b9f34 100644
--- a/sw/source/core/fields/reffld.cxx
+++ b/sw/source/core/fields/reffld.cxx
@@ -771,7 +771,7 @@ static std::pair<OUString, bool> MakeRefNumStr(
SwTextNode const& rTextNodeOfReferencedItem(pLayout
? *sw::GetParaPropsNode(*pLayout, i_rTextNodeOfReferencedItem)
: i_rTextNodeOfReferencedItem);
- if ( rTextNodeOfReferencedItem.HasNumber() &&
+ if ( rTextNodeOfReferencedItem.HasNumber(pLayout) &&
rTextNodeOfReferencedItem.IsCountedInList() )
{
OSL_ENSURE( rTextNodeOfReferencedItem.GetNum(pLayout),
@@ -795,7 +795,7 @@ static std::pair<OUString, bool> MakeRefNumStr(
== rTextNodeOfReferencedItem.FindFooterStartNode() )
{
const SwNodeNum* pNodeNumForTextNodeOfField( nullptr );
- if ( rTextNodeOfField.HasNumber() &&
+ if ( rTextNodeOfField.HasNumber(pLayout) &&
rTextNodeOfField.GetNumRule() == rTextNodeOfReferencedItem.GetNumRule() )
{
pNodeNumForTextNodeOfField = rTextNodeOfField.GetNum(pLayout);
diff --git a/sw/source/core/frmedt/fecopy.cxx b/sw/source/core/frmedt/fecopy.cxx
index c2470b997a93..8589b8eed579 100644
--- a/sw/source/core/frmedt/fecopy.cxx
+++ b/sw/source/core/frmedt/fecopy.cxx
@@ -1021,7 +1021,7 @@ bool SwFEShell::Paste( SwDoc* pClpDoc, bool bNestedTable )
{
if( bDelTable && IsTableMode() )
{
- SwEditShell::Delete();
+ SwEditShell::Delete(false);
bDelTable = false;
}
diff --git a/sw/source/core/inc/DocumentContentOperationsManager.hxx b/sw/source/core/inc/DocumentContentOperationsManager.hxx
index 2d600b6ff8ba..994812dc14b4 100644
--- a/sw/source/core/inc/DocumentContentOperationsManager.hxx
+++ b/sw/source/core/inc/DocumentContentOperationsManager.hxx
@@ -48,6 +48,7 @@ public:
// Add optional parameter <bForceJoinNext>, default value <false>
// Needed for hiding of deletion redlines
bool DeleteAndJoin( SwPaM&,
+ SwDeleteFlags flags = SwDeleteFlags::Default,
const bool bForceJoinNext = false ) override;
bool MoveRange(SwPaM&, SwPosition&, SwMoveFlags) override;
@@ -159,10 +160,10 @@ public:
private:
SwDoc& m_rDoc;
- bool DeleteAndJoinImpl(SwPaM&, const bool);
- bool DeleteAndJoinWithRedlineImpl(SwPaM&, const bool unused = false);
- bool DeleteRangeImpl(SwPaM&, const bool unused = false);
- bool DeleteRangeImplImpl(SwPaM &);
+ bool DeleteAndJoinImpl(SwPaM&, SwDeleteFlags, const bool);
+ bool DeleteAndJoinWithRedlineImpl(SwPaM&, SwDeleteFlags, const bool unused = false);
+ bool DeleteRangeImpl(SwPaM&, SwDeleteFlags, const bool unused = false);
+ bool DeleteRangeImplImpl(SwPaM &, SwDeleteFlags);
bool ReplaceRangeImpl(SwPaM&, OUString const&, const bool);
SwFlyFrameFormat* InsNoTextNode( const SwPosition&rPos, SwNoTextNode*,
const SfxItemSet* pFlyAttrSet,
diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx
index edf8121836b6..7cb52c1a7c1e 100644
--- a/sw/source/core/inc/MarkManager.hxx
+++ b/sw/source/core/inc/MarkManager.hxx
@@ -67,7 +67,7 @@ namespace sw {
// deleters
virtual std::unique_ptr<ILazyDeleter>
- deleteMark(const const_iterator_t& ppMark) override;
+ deleteMark(const const_iterator_t& ppMark, bool isMoveNodes) override;
virtual void deleteMark(const ::sw::mark::IMark* const pMark) override;
virtual void clearAllMarks() override;
diff --git a/sw/source/core/inc/UndoDelete.hxx b/sw/source/core/inc/UndoDelete.hxx
index a4eb066581c9..b4ae4544d669 100644
--- a/sw/source/core/inc/UndoDelete.hxx
+++ b/sw/source/core/inc/UndoDelete.hxx
@@ -27,6 +27,7 @@
class SwRedlineSaveDatas;
class SwTextNode;
+enum class SwDeleteFlags;
namespace sfx2 {
class MetadatableUndo;
@@ -59,6 +60,7 @@ class SwUndoDelete
bool m_bResetPgDesc : 1; // TRUE: reset PgDsc on following node
bool m_bResetPgBrk : 1; // TRUE: reset PgBreak on following node
bool const m_bFromTableCopy : 1; // TRUE: called by SwUndoTableCpyTable
+ SwDeleteFlags m_DeleteFlags;
bool SaveContent( const SwPosition* pStt, const SwPosition* pEnd,
SwTextNode* pSttTextNd, SwTextNode* pEndTextNd );
@@ -66,6 +68,7 @@ class SwUndoDelete
public:
SwUndoDelete(
SwPaM&,
+ SwDeleteFlags flags,
bool bFullPara = false,
bool bCalledByTableCpy = false );
virtual ~SwUndoDelete() override;
diff --git a/sw/source/core/inc/UndoRedline.hxx b/sw/source/core/inc/UndoRedline.hxx
index 38ecd86314cb..ada3c34fad7f 100644
--- a/sw/source/core/inc/UndoRedline.hxx
+++ b/sw/source/core/inc/UndoRedline.hxx
@@ -22,6 +22,7 @@
#include <memory>
#include <undobj.hxx>
+#include <IDocumentContentOperations.hxx>
struct SwSortOptions;
class SwRangeRedline;
@@ -52,17 +53,22 @@ public:
class SwUndoRedlineDelete : public SwUndoRedline
{
+private:
+ std::unique_ptr<SwHistory> m_pHistory; ///< for moved fly anchors
+ //
bool bCanGroup : 1;
bool bIsDelim : 1;
bool bIsBackspace : 1;
OUString m_sRedlineText;
+ void InitHistory(SwPaM const& rRange);
+
virtual void UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
virtual void RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam) override;
public:
- SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUserId );
+ SwUndoRedlineDelete(const SwPaM& rRange, SwUndoId nUserId, SwDeleteFlags flags = SwDeleteFlags::Default);
virtual SwRewriter GetRewriter() const override;
bool CanGrouping( const SwUndoRedlineDelete& rPrev );
diff --git a/sw/source/core/inc/bookmrk.hxx b/sw/source/core/inc/bookmrk.hxx
index 3960ca4b3d8b..fe5bff942568 100644
--- a/sw/source/core/inc/bookmrk.hxx
+++ b/sw/source/core/inc/bookmrk.hxx
@@ -90,6 +90,8 @@ namespace sw {
virtual void ClearOtherMarkPos()
{ m_pPos2.reset(); }
+ virtual auto InvalidateFrames() -> void;
+
virtual OUString ToString( ) const override;
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
@@ -170,6 +172,8 @@ namespace sw {
virtual void DeregisterFromDoc(SwDoc* const io_pDoc) override;
+ virtual auto InvalidateFrames() -> void override;
+
virtual const OUString& GetShortName() const override
{ return m_sShortName; }
virtual const vcl::KeyCode& GetKeyCode() const override
@@ -182,10 +186,8 @@ namespace sw {
{ return m_bHidden; }
virtual const OUString& GetHideCondition() const override
{ return m_sHideCondition; }
- virtual void Hide(bool rHide) override
- { m_bHidden = rHide; }
- virtual void SetHideCondition(const OUString& rHideCondition) override
- { m_sHideCondition = rHideCondition; }
+ virtual void Hide(bool rHide) override;
+ virtual void SetHideCondition(const OUString& rHideCondition) override;
// ::sfx2::Metadatable
virtual ::sfx2::IXmlIdRegistry& GetRegistry() override;
diff --git a/sw/source/core/inc/docfld.hxx b/sw/source/core/inc/docfld.hxx
index 36cf3d86eba0..2ab96b1639c1 100644
--- a/sw/source/core/inc/docfld.hxx
+++ b/sw/source/core/inc/docfld.hxx
@@ -23,6 +23,7 @@
#include <calc.hxx>
#include <doc.hxx>
#include <IDocumentTimerAccess.hxx>
+#include <IMark.hxx>
#include <o3tl/sorted_vector.hxx>
#include <memory>
@@ -53,10 +54,11 @@ class SetGetExpField
const SwTableBox* pTBox;
const SwTextINetFormat* pTextINet;
const SwFlyFrameFormat* pFlyFormat;
+ ::sw::mark::IBookmark const* pBookmark;
} m_CNTNT;
enum SetGetExpFieldType
{
- TEXTFIELD, TEXTTOXMARK, SECTIONNODE, CRSRPOS, TABLEBOX,
+ TEXTFIELD, TEXTTOXMARK, SECTIONNODE, BOOKMARK, CRSRPOS, TABLEBOX,
TEXTINET, FLYFRAME
} m_eSetGetExpFieldType;
@@ -69,6 +71,9 @@ public:
SetGetExpField( const SwSectionNode& rSectNode,
const SwPosition* pPos = nullptr );
+ SetGetExpField( ::sw::mark::IBookmark const& rBookmark,
+ SwPosition const* pPos = nullptr );
+
SetGetExpField( const SwTableBox& rTableBox );
SetGetExpField( const SwNodeIndex& rNdIdx, const SwTextTOXMark& rTOX );
@@ -84,6 +89,8 @@ public:
{ return TEXTFIELD == m_eSetGetExpFieldType ? m_CNTNT.pTextField : nullptr; }
const SwSection* GetSection() const
{ return SECTIONNODE == m_eSetGetExpFieldType ? m_CNTNT.pSection : nullptr; }
+ ::sw::mark::IBookmark const* GetBookmark() const
+ { return BOOKMARK == m_eSetGetExpFieldType ? m_CNTNT.pBookmark : nullptr; }
const SwTextINetFormat* GetINetFormat() const
{ return TEXTINET == m_eSetGetExpFieldType ? m_CNTNT.pTextINet : nullptr; }
const SwFlyFrameFormat* GetFlyFormat() const
@@ -142,7 +149,8 @@ class SwDocUpdateField
void MakeFieldList_( SwDoc& pDoc, int eGetMode );
void GetBodyNode( const SwTextField& , SwFieldIds nFieldWhich );
- void GetBodyNode( const SwSectionNode&);
+ template<typename T>
+ void GetBodyNodeGeneric(SwNode const& rNode, T const&);
public:
SwDocUpdateField(SwDoc& rDocument);
diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index 18f263cfc1db..29a196944fcb 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -64,7 +64,7 @@ class SW_DLLPUBLIC SwFlyFrame : public SwLayoutFrame, public SwAnchoredObject
friend void Notify( SwFlyFrame *, SwPageFrame *pOld, const SwRect &rOld,
const SwRect* pOldPrt );
- void InitDrawObj(); // these to methods are called in the
+ void InitDrawObj(SwFrame const&); // these to methods are called in the
void FinitDrawObj(); // constructors
void UpdateAttr_( const SfxPoolItem*, const SfxPoolItem*, sal_uInt8 &,
@@ -134,6 +134,7 @@ protected:
page frame
*/
virtual void RegisterAtCorrectPage() override;
+ virtual void RegisterAtPage(SwPageFrame &) override;
virtual bool SetObjTop_( const SwTwips _nTop ) override;
virtual bool SetObjLeft_( const SwTwips _nLeft ) override;
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index 4c6940c28edc..cb94b7cbd259 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -151,6 +151,7 @@ public:
SwFlyLayFrame( SwFlyFrameFormat*, SwFrame*, SwFrame *pAnchor );
+ virtual void RegisterAtPage(SwPageFrame &) override;
protected:
virtual void Modify( const SfxPoolItem*, const SfxPoolItem* ) override;
};
@@ -170,6 +171,7 @@ protected:
#i28701#
*/
virtual void RegisterAtCorrectPage() override;
+ virtual void RegisterAtPage(SwPageFrame &) override;
virtual void Modify( const SfxPoolItem*, const SfxPoolItem* ) override;
public:
@@ -227,6 +229,7 @@ public:
//see layact.cxx
void AddRefOfst( long nOfst ) { aRef.AdjustY( nOfst ); }
+ void AddRefOfst(Point const& rOfst) { aRef += rOfst; }
// #i26791#
virtual void MakeObjPos() override;
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index ae5e8378ee4b..289a45fc922f 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -424,7 +424,7 @@ protected:
bool mbColLocked : 1; // lock Grow/Shrink for column-wise section
// or fly frames, will be set in Format
bool m_isInDestroy : 1;
- bool mbForbidDelete : 1;
+ int mnForbidDelete;
void ColLock() { mbColLocked = true; }
void ColUnlock() { mbColLocked = false; }
@@ -860,7 +860,7 @@ public:
bool IsProtected() const;
bool IsColLocked() const { return mbColLocked; }
- virtual bool IsDeleteForbidden() const { return mbForbidDelete; }
+ virtual bool IsDeleteForbidden() const { return mnForbidDelete > 0; }
/// this is the only way to delete a SwFrame instance
static void DestroyFrame(SwFrame *const pFrame);
@@ -900,8 +900,8 @@ public:
void RegisterToFormat( SwFormat& rFormat );
void ValidateThisAndAllLowers( const sal_uInt16 nStage );
- void ForbidDelete() { mbForbidDelete = true; }
- void AllowDelete() { mbForbidDelete = false; }
+ void ForbidDelete() { ++mnForbidDelete; }
+ void AllowDelete() { assert(mnForbidDelete > 0); --mnForbidDelete; }
drawinglayer::attribute::SdrAllFillAttributesHelperPtr getSdrAllFillAttributesHelper() const;
bool supportsFullDrawingLayerFillAttributeSet() const;
@@ -1238,8 +1238,7 @@ public:
//it in e.g. SwSectionFrame::MergeNext etc because we will need it
//again after the SwFrameDeleteGuard dtor
explicit SwFrameDeleteGuard(SwFrame* pFrame)
- : m_pForbidFrame((pFrame && !pFrame->IsDeleteForbidden()) ?
- pFrame : nullptr)
+ : m_pForbidFrame(pFrame)
{
if (m_pForbidFrame)
m_pForbidFrame->ForbidDelete();
diff --git a/sw/source/core/inc/layact.hxx b/sw/source/core/inc/layact.hxx
index 990c0e4b88f0..75a0523fda7f 100644
--- a/sw/source/core/inc/layact.hxx
+++ b/sw/source/core/inc/layact.hxx
@@ -68,6 +68,9 @@ class SwLayAction
std::unique_ptr<SwWait> m_pWait;
+ std::vector<SwFrame*> m_aFrameStack;
+ std::vector<std::unique_ptr<SwFrameDeleteGuard>> m_aFrameDeleteGuards;
+
// If a paragraph (or anything else) moved more than one page when
// formatting, it adds its new page number here.
// The InternalAction can then take the appropriate steps.
@@ -111,7 +114,7 @@ class SwLayAction
bool FormatLayout( OutputDevice* pRenderContext, SwLayoutFrame *, bool bAddRect = true );
bool FormatLayoutTab( SwTabFrame *, bool bAddRect );
- bool FormatContent( const SwPageFrame* pPage );
+ bool FormatContent(SwPageFrame * pPage);
void FormatContent_( const SwContentFrame* pContent,
const SwPageFrame* pPage );
bool IsShortCut( SwPageFrame *& );
@@ -124,6 +127,9 @@ class SwLayAction
bool RemoveEmptyBrowserPages();
+ void PushFormatLayout(SwFrame* pLow);
+ void PopFormatLayout();
+
public:
SwLayAction(SwRootFrame *pRt, SwViewShellImp *pImp, TaskStopwatch* pWatch = nullptr);
~SwLayAction();
@@ -148,7 +154,7 @@ public:
void SetReschedule ( bool bNew ) { m_bReschedule = bNew; }
void SetWaitAllowed ( bool bNew ) { m_bWaitAllowed = bNew; }
- void SetAgain() { m_bAgain = true; }
+ void SetAgain(bool bAgain);
void SetUpdateExpFields() {m_bUpdateExpFields = true; }
inline void SetCheckPageNum( sal_uInt16 nNew );
diff --git a/sw/source/core/inc/layfrm.hxx b/sw/source/core/inc/layfrm.hxx
index f7d90f00d8f6..835b20c0cfd6 100644
--- a/sw/source/core/inc/layfrm.hxx
+++ b/sw/source/core/inc/layfrm.hxx
@@ -100,6 +100,7 @@ public:
SwPrintData const*const pPrintData = nullptr ) const override;
const SwFrame *Lower() const { return m_pLower; }
SwFrame *Lower() { return m_pLower; }
+ bool ContainsDeleteForbiddenLayFrame() const;
const SwContentFrame *ContainsContent() const;
inline SwContentFrame *ContainsContent();
const SwCellFrame *FirstCell() const;
diff --git a/sw/source/core/inc/mvsave.hxx b/sw/source/core/inc/mvsave.hxx
index c472b6f7bc1a..5b84b5e10819 100644
--- a/sw/source/core/inc/mvsave.hxx
+++ b/sw/source/core/inc/mvsave.hxx
@@ -34,6 +34,7 @@ class SwDoc;
class SwFormatAnchor;
class SwFrameFormat;
class SwIndex;
+class SwHistory;
class SwNodeIndex;
class SwNodeRange;
class SwPaM;
@@ -116,10 +117,10 @@ struct SaveFly
typedef std::deque< SaveFly > SaveFlyArr;
void RestFlyInRange( SaveFlyArr& rArr, const SwPosition& rSttIdx,
- const SwNodeIndex* pInsPos );
+ const SwNodeIndex* pInsPos, bool isForceToStartPos = false);
void SaveFlyInRange( const SwNodeRange& rRg, SaveFlyArr& rArr );
void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
- SaveFlyArr& rArr, bool bMoveAllFlys );
+ SaveFlyArr& rArr, bool bMoveAllFlys, SwHistory * pHistory = nullptr);
void DelFlyInRange( const SwNodeIndex& rMkNdIdx,
const SwNodeIndex& rPtNdIdx,
diff --git a/sw/source/core/inc/pagefrm.hxx b/sw/source/core/inc/pagefrm.hxx
index 95d69bd699ee..878fae3a0520 100644
--- a/sw/source/core/inc/pagefrm.hxx
+++ b/sw/source/core/inc/pagefrm.hxx
@@ -435,6 +435,9 @@ SwTextGridItem const* GetGridItem(SwPageFrame const*const);
sal_uInt16 GetGridWidth(SwTextGridItem const&, SwDoc const&);
+namespace sw { bool IsPageFrameEmpty(SwPageFrame const& rPage); }
+
+
#endif // INCLUDED_SW_SOURCE_CORE_INC_PAGEFRM_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/rootfrm.hxx b/sw/source/core/inc/rootfrm.hxx
index 484ff172e25d..44d7a5800032 100644
--- a/sw/source/core/inc/rootfrm.hxx
+++ b/sw/source/core/inc/rootfrm.hxx
@@ -76,7 +76,7 @@ using SwDestroyList = std::set<SwSectionFrame*>;
/// The root element of a Writer document layout. Lower frames are expected to
/// be SwPageFrame instances.
-class SAL_DLLPUBLIC_RTTI SwRootFrame: public SwLayoutFrame
+class SW_DLLPUBLIC SwRootFrame: public SwLayoutFrame
{
// Needs to disable the Superfluous temporarily
friend void AdjustSizeChgNotify( SwRootFrame *pRoot );
diff --git a/sw/source/core/inc/tabfrm.hxx b/sw/source/core/inc/tabfrm.hxx
index 95da935cd079..6dfa6c743a13 100644
--- a/sw/source/core/inc/tabfrm.hxx
+++ b/sw/source/core/inc/tabfrm.hxx
@@ -43,6 +43,7 @@ class SwTabFrame: public SwLayoutFrame, public SwFlowFrame
bool m_bCalcLowers :1; /// For stability of the content in MakeAll
bool m_bLowersFormatted :1; /// Communication between MakeAll and Layact
bool m_bLockBackMove :1; /// The Master took care of the BackMove test
+ bool m_bWantBackMove :1; /// Table wants to move back but was locked
bool m_bResizeHTMLTable :1; /// Call the Resize of the HTMLTableLayout in the MakeAll
/// This is an optimization, so that we don't have to call
/// it in ContentFrame::Grow; there it might be called for
diff --git a/sw/source/core/inc/unofldmid.h b/sw/source/core/inc/unofldmid.h
index 2bb13a66faa3..43e30058d470 100644
--- a/sw/source/core/inc/unofldmid.h
+++ b/sw/source/core/inc/unofldmid.h
@@ -41,6 +41,7 @@
#define FIELD_PROP_BOOL4 28
#define FIELD_PROP_STRINGS 29
#define FIELD_PROP_PAR5 30
+#define FIELD_PROP_GRABBAG 31
#define FIELD_PROP_IS_FIELD_USED 32
#define FIELD_PROP_IS_FIELD_DISPLAYED 33
diff --git a/sw/source/core/layout/anchoreddrawobject.cxx b/sw/source/core/layout/anchoreddrawobject.cxx
index 079468fdf062..438759f765b2 100644
--- a/sw/source/core/layout/anchoreddrawobject.cxx
+++ b/sw/source/core/layout/anchoreddrawobject.cxx
@@ -840,10 +840,18 @@ void SwAnchoredDrawObject::RegisterAtCorrectPage()
}
if ( pPageFrame && GetPageFrame() != pPageFrame )
{
- if ( GetPageFrame() )
- GetPageFrame()->RemoveDrawObjFromPage( *this );
- pPageFrame->AppendDrawObjToPage( *this );
+ RegisterAtPage(*pPageFrame);
}
}
+void SwAnchoredDrawObject::RegisterAtPage(SwPageFrame & rPageFrame)
+{
+ assert(GetPageFrame() != &rPageFrame);
+ if (GetPageFrame())
+ {
+ GetPageFrame()->RemoveDrawObjFromPage( *this );
+ }
+ rPageFrame.AppendDrawObjToPage( *this );
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index 79235781896d..884d791caebe 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -3363,7 +3363,7 @@ SwHandleAnchorNodeChg::~SwHandleAnchorNodeChg() COVERITY_NOEXCEPT_FALSE
mpWrtShell->SwEditShell::Copy(mpWrtShell);
mpWrtShell->DestroyCursor();
- mpWrtShell->Delete();
+ mpWrtShell->Delete(false);
mpWrtShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
}
diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx
index a35af84d54a1..632e136fdd10 100644
--- a/sw/source/core/layout/findfrm.cxx
+++ b/sw/source/core/layout/findfrm.cxx
@@ -161,6 +161,27 @@ const SwFrame *SwLayoutFrame::ContainsAny( const bool _bInvestigateFootnoteForSe
return nullptr;
}
+bool SwLayoutFrame::ContainsDeleteForbiddenLayFrame() const
+{
+ if (IsDeleteForbidden())
+ {
+ return true;
+ }
+ for (SwFrame const* pFrame = Lower(); pFrame; pFrame = pFrame->GetNext())
+ {
+ if (!pFrame->IsLayoutFrame())
+ {
+ continue;
+ }
+ SwLayoutFrame const*const pLay(static_cast<SwLayoutFrame const*>(pFrame));
+ if (pLay->ContainsDeleteForbiddenLayFrame())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
const SwFrame* SwFrame::GetLower() const
{
return IsLayoutFrame() ? static_cast<const SwLayoutFrame*>(this)->Lower() : nullptr;
diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx
index d416b637c02f..2aaa2e2360fb 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -2034,7 +2034,7 @@ bool SwFlowFrame::MoveFwd( bool bMakePage, bool bPageBreak, bool bMoveAlways )
// #i106452#
// check page description not only in situation with sections.
if ( !bSamePage &&
- ( m_rThis.GetPageDescItem().GetPageDesc() ||
+ ((!IsFollow() && m_rThis.GetPageDescItem().GetPageDesc()) ||
pOldPage->GetPageDesc()->GetFollow() != pNewPage->GetPageDesc() ) )
{
SwFrame::CheckPageDescs( pNewPage, false );
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index 190e799dbc56..2b6973d14e97 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -165,7 +165,7 @@ SwFlyFrame::SwFlyFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch
// First the Init, then the Content:
// This is due to the fact that the Content may have Objects/Frames,
// which are then registered
- InitDrawObj();
+ InitDrawObj(*pAnch);
Chain( pAnch );
@@ -361,10 +361,10 @@ void SwFlyFrame::DeleteCnt()
InvalidatePage();
}
-void SwFlyFrame::InitDrawObj()
+void SwFlyFrame::InitDrawObj(SwFrame const& rAnchorFrame)
{
// OD 2004-03-22 #i26791#
- SetDrawObj(*SwFlyDrawContact::CreateNewRef(this, GetFormat()));
+ SetDrawObj(*SwFlyDrawContact::CreateNewRef(this, GetFormat(), rAnchorFrame));
// Set the right Layer
// OD 2004-01-19 #110582#
@@ -1469,6 +1469,7 @@ void CalcContent( SwLayoutFrame *pLay, bool bNoColl )
do
{
pLast = pFrame;
+ bool const wasFrameLowerOfLay(pLay->IsAnLower(pFrame));
if( pFrame->IsVertical() ?
( pFrame->GetUpper()->getFramePrintArea().Height() != pFrame->getFrameArea().Height() )
: ( pFrame->GetUpper()->getFramePrintArea().Width() != pFrame->getFrameArea().Width() ) )
@@ -1528,11 +1529,13 @@ void CalcContent( SwLayoutFrame *pLay, bool bNoColl )
{
bool bAgain = false;
bool bRestartLayoutProcess = false;
- SwPageFrame* pPageFrame = pFrame->FindPageFrame();
size_t nCnt = pFrame->GetDrawObjs()->size();
size_t i = 0;
while ( i < nCnt )
{
+ // pFrame can move to a different page in FormatObj()
+ SwPageFrame *const pPageFrame = pFrame->FindPageFrame();
+
// #i28701#
SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i];
assert(pAnchoredObj);
@@ -1610,7 +1613,10 @@ void CalcContent( SwLayoutFrame *pLay, bool bNoColl )
// #i28701# - restart layout process, if
// requested by floating screen object formatting
- if ( bRestartLayoutProcess )
+ if (bRestartLayoutProcess
+ // tdf#142080 if it was aleady on next page, and still is,
+ // ignore restart, as restart could cause infinite loop
+ && (wasFrameLowerOfLay || pLay->IsAnLower(pFrame)))
{
pFrame = pLay->ContainsAny();
pAgainObj1 = nullptr;
@@ -1653,8 +1659,17 @@ void CalcContent( SwLayoutFrame *pLay, bool bNoColl )
}
if ( pFrame->IsTabFrame() )
{
- if ( static_cast<SwTabFrame*>(pFrame)->IsFollow() )
+ if (static_cast<SwTabFrame*>(pFrame)->m_bLockBackMove)
+ {
+ assert(static_cast<SwTabFrame*>(pFrame)->IsFollow());
static_cast<SwTabFrame*>(pFrame)->m_bLockBackMove = false;
+ // tdf#150606 encourage it to move back in FormatLayout()
+ if (static_cast<SwTabFrame*>(pFrame)->m_bWantBackMove)
+ {
+ static_cast<SwTabFrame*>(pFrame)->m_bWantBackMove = false;
+ pFrame->InvalidatePos();
+ }
+ }
}
pFrame = bPrevInvalid ? pTmpPrev : pFrame->FindNext();
@@ -1674,10 +1689,10 @@ void CalcContent( SwLayoutFrame *pLay, bool bNoColl )
pFrame->InvalidatePos_();
}
}
- // Stay in the pLay
- // Except for SectionFrames with Follow: the first ContentFrame of the Follow
- // will be formatted, so that it gets a chance to load in the pLay.
- // As long as these Frames are loading in pLay, we continue
+ // Stay in the pLay.
+ // Except for SectionFrames with Follow: the first ContentFrame of the
+ // Follow will be formatted, so that it gets a chance to move back
+ // into the pLay. Continue as long as these Frames land in pLay.
} while ( pFrame &&
( pLay->IsAnLower( pFrame ) ||
( pSect &&
@@ -2839,6 +2854,11 @@ void SwFlyFrame::RegisterAtCorrectPage()
// default behaviour is to do nothing.
}
+void SwFlyFrame::RegisterAtPage(SwPageFrame &)
+{
+ // default behaviour is to do nothing.
+}
+
/** method to determine, if a <MakeAll()> on the Writer fly frame is possible
OD 2004-05-11 #i28701#
diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx
index f3c442ac8cfa..06baefd15fa7 100644
--- a/sw/source/core/layout/flycnt.cxx
+++ b/sw/source/core/layout/flycnt.cxx
@@ -421,11 +421,17 @@ void SwFlyAtContentFrame::MakeAll(vcl::RenderContext* pRenderContext)
// <SwObjectFormatterTextFrame::CheckMovedFwdCondition(..)>
sal_uInt32 nToPageNum( 0 );
bool bDummy( false );
+ bool bPageHasFlysAnchoredBelowThis(false);
if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition(
- *this, GetPageFrame()->GetPhyPageNum(),
- bAnchoredAtMaster, nToPageNum, bDummy ) )
+// TODO: what if this fly moved bc it's in table? does sth prevent that?
+ *this, *GetPageFrame(),
+ bAnchoredAtMaster, nToPageNum, bDummy,
+ bPageHasFlysAnchoredBelowThis) )
{
- bConsiderWrapInfluenceDueToMovedFwdAnchor = true;
+ if (!bPageHasFlysAnchoredBelowThis)
+ {
+ bConsiderWrapInfluenceDueToMovedFwdAnchor = true;
+ }
// mark anchor text frame
// directly, that it is moved forward by object positioning.
SwTextFrame* pAnchorTextFrame( static_cast<SwTextFrame*>(AnchorFrame()) );
@@ -436,14 +442,22 @@ void SwFlyAtContentFrame::MakeAll(vcl::RenderContext* pRenderContext)
rDoc, *pAnchorTextFrame, nAnchorFrameToPageNum ) )
{
if ( nAnchorFrameToPageNum < nToPageNum )
- SwLayouter::RemoveMovedFwdFrame( rDoc, *pAnchorTextFrame );
+ {
+ if (!bPageHasFlysAnchoredBelowThis)
+ {
+ SwLayouter::RemoveMovedFwdFrame(rDoc, *pAnchorTextFrame);
+ }
+ }
else
bInsert = false;
}
if ( bInsert )
{
- SwLayouter::InsertMovedFwdFrame( rDoc, *pAnchorTextFrame,
- nToPageNum );
+ if (!bPageHasFlysAnchoredBelowThis)
+ {
+ SwLayouter::InsertMovedFwdFrame(rDoc, *pAnchorTextFrame,
+ nToPageNum);
+ }
}
}
}
@@ -1333,7 +1347,7 @@ void SwFlyAtContentFrame::SetAbsPos( const Point &rNew )
{
const SwTextAttr *const pTextInputField =
pos.nNode.GetNode().GetTextNode()->GetTextAttrAt(
- pos.nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTextNode::PARENT );
+ pos.nContent.GetIndex(), RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent);
if (pTextInputField != nullptr)
{
pos.nContent = pTextInputField->GetStart();
@@ -1396,10 +1410,20 @@ void SwFlyAtContentFrame::RegisterAtCorrectPage()
}
if ( pPageFrame && GetPageFrame() != pPageFrame )
{
- if ( GetPageFrame() )
- GetPageFrame()->MoveFly( this, pPageFrame );
- else
- pPageFrame->AppendFlyToPage( this );
+ RegisterAtPage(*pPageFrame);
+ }
+}
+
+void SwFlyAtContentFrame::RegisterAtPage(SwPageFrame & rPageFrame)
+{
+ assert(GetPageFrame() != &rPageFrame);
+ if (GetPageFrame())
+ {
+ GetPageFrame()->MoveFly( this, &rPageFrame );
+ }
+ else
+ {
+ rPageFrame.AppendFlyToPage( this );
}
}
diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx
index 4a7030ea241e..c915ee82d95a 100644
--- a/sw/source/core/layout/flylay.cxx
+++ b/sw/source/core/layout/flylay.cxx
@@ -723,6 +723,19 @@ SwFlyLayFrame::SwFlyLayFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame
m_bLayout = true;
}
+void SwFlyLayFrame::RegisterAtPage(SwPageFrame & rPageFrame)
+{
+ assert(GetPageFrame() != &rPageFrame);
+ if (GetPageFrame())
+ {
+ GetPageFrame()->MoveFly( this, &rPageFrame );
+ }
+ else
+ {
+ rPageFrame.AppendFlyToPage( this );
+ }
+}
+
// #i28701#
void SwFlyLayFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index a861dd60013b..f702815b4010 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -69,6 +69,7 @@
#include <undobj.hxx>
#include <DocumentSettingManager.hxx>
#include <IDocumentDrawModelAccess.hxx>
+#include <IDocumentLayoutAccess.hxx>
#include <IDocumentTimerAccess.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
@@ -1018,7 +1019,7 @@ void AppendObj(SwFrame *const pFrame, SwPageFrame *const pPage, SwFrameFormat *c
pNew->GetAnchorFrame() != pFrame &&
!pNew->GetDrawObjectByAnchorFrame( *pFrame ) )
{
- SwDrawVirtObj* pDrawVirtObj = pNew->AddVirtObj();
+ SwDrawVirtObj* pDrawVirtObj = pNew->AddVirtObj(*pFrame);
pFrame->AppendDrawObj( *(pNew->GetAnchoredObj( pDrawVirtObj )) );
pDrawVirtObj->ActionChanged();
@@ -1067,6 +1068,12 @@ static bool IsShown(sal_uLong const nIndex,
assert(pFirstNode);
assert(pLastNode);
assert(rAnch.GetAnchorId() != RndStdIds::FLY_AT_FLY);
+ if (*pIter == *pEnd && rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
+ { // tdf#149595 special case - it *could* be shown if first == last
+ return !IsDestroyFrameAnchoredAtChar(*rAnch.GetContentAnchor(),
+ SwPosition(const_cast<SwTextNode&>(*pFirstNode), 0),
+ SwPosition(const_cast<SwTextNode&>(*pLastNode), pLastNode->Len()));
+ }
for (auto iter = *pIter; iter != *pEnd; ++iter)
{
assert(iter->nStart != iter->nEnd); // TODO possible?
@@ -1161,8 +1168,7 @@ void RemoveHiddenObjsOfNode(SwTextNode const& rNode,
{
SwFormatAnchor const& rAnchor = pFrameFormat->GetAnchor();
if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR
- || (rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR
- && RES_DRAWFRMFMT == pFrameFormat->Which()))
+ || rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
{
assert(rAnchor.GetContentAnchor()->nNode.GetIndex() == rNode.GetIndex());
if (!IsShown(rNode.GetIndex(), rAnchor, pIter, pEnd, pFirstNode, pLastNode))
@@ -1719,7 +1725,10 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
static_cast<SwTextFrame*>(pPrv)->Prepare( PREP_QUOVADIS, nullptr, false );
}
}
- if (nIndex + 1 == nEndIndex)
+
+ if (nIndex + 1 == nEndIndex
+ // tdf#136452 may also be needed at end of section
+ || pNode->EndOfSectionIndex() - 1 == nEndIndex)
{ // tdf#131684 tdf#132236 fix upper of frame moved in
// SwUndoDelete; can't be done there unfortunately
// because empty section frames are deleted here
@@ -1941,8 +1950,10 @@ void MakeFrames( SwDoc *pDoc, const SwNodeIndex &rSttIdx,
SwNodeIndex aTmp( rSttIdx );
sal_uLong nEndIdx = rEndIdx.GetIndex();
+ // TODO for multiple layouts there should be a loop here
SwNode* pNd = pDoc->GetNodes().FindPrvNxtFrameNode( aTmp,
- pDoc->GetNodes()[ nEndIdx-1 ]);
+ pDoc->GetNodes()[ nEndIdx-1 ],
+ pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
if ( pNd )
{
bool bApres = aTmp < rSttIdx;
diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx
index 9573944b71d1..964af2008868 100644
--- a/sw/source/core/layout/ftnfrm.cxx
+++ b/sw/source/core/layout/ftnfrm.cxx
@@ -572,10 +572,20 @@ void SwFootnoteFrame::Paste( SwFrame* pParent, SwFrame* pSibling )
if( aRectFnSet.GetWidth(getFrameArea())!=aRectFnSet.GetWidth(pParent->getFramePrintArea()) )
InvalidateSize_();
InvalidatePos_();
+ if (SwFrame *const pContent = ContainsContent())
+ { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
+ pContent->InvalidatePrt_();
+ }
SwPageFrame *pPage = FindPageFrame();
InvalidatePage( pPage );
- if ( GetNext() )
- GetNext()->InvalidatePos_();
+ if (SwFootnoteFrame *const pNext = static_cast<SwFootnoteFrame *>(GetNext()))
+ {
+ pNext->InvalidatePos_();
+ if (SwFrame *const pContent = pNext->ContainsContent())
+ { // tdf#139687 invalidate possibly stale top margin (computed from previous frame)
+ pContent->InvalidatePrt_();
+ }
+ }
if( aRectFnSet.GetHeight(getFrameArea()) )
pParent->Grow( aRectFnSet.GetHeight(getFrameArea()) );
@@ -2863,6 +2873,9 @@ bool SwContentFrame::MoveFootnoteCntFwd( bool bMakePage, SwFootnoteBossFrame *pO
OSL_ENSURE( pTmp->IsTabFrame(), "GetNextSctLeaf: Wrong Type" );
pTmpNxt = static_cast<SwTabFrame*>(pTmp);
}
+ // we will dereference pNewUp in the following MoveSubTree call
+ // so it certainly should not be deleted before that
+ SwFrameDeleteGuard aDeleteGuard(pNewUp);
pTmpNxt->MoveSubTree( pTmpFootnote, pNewUp->GetNext() );
}
}
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index 04201e1c6f5e..62d78d4c38e6 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -62,6 +62,8 @@
#include <sortedobjs.hxx>
#include <objectformatter.hxx>
#include <fntcache.hxx>
+#include <fmtanchr.hxx>
+#include <comphelper/scopeguard.hxx>
#include <vector>
#include <tools/diagnose_ex.h>
@@ -282,11 +284,12 @@ bool SwLayAction::IsInterrupt()
void SwLayAction::Reset()
{
+ SetAgain(false);
m_pOptTab = nullptr;
m_nStartTicks = std::clock();
m_nEndPage = m_nPreInvaPage = m_nCheckPageNum = USHRT_MAX;
m_bPaint = m_bComplete = m_bWaitAllowed = m_bCheckPages = true;
- m_bInterrupt = m_bAgain = m_bNextCycle = m_bCalcLayout = m_bReschedule =
+ m_bInterrupt = m_bNextCycle = m_bCalcLayout = m_bReschedule =
m_bUpdateExpFields = m_bBrowseActionStop = false;
m_pCurPage = nullptr;
}
@@ -303,7 +306,8 @@ bool SwLayAction::RemoveEmptyBrowserPages()
do
{
if ( (pPage->GetSortedObjs() && pPage->GetSortedObjs()->size()) ||
- pPage->ContainsContent() )
+ pPage->ContainsContent() ||
+ pPage->FindFootnoteCont() )
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
else
{
@@ -318,6 +322,53 @@ bool SwLayAction::RemoveEmptyBrowserPages()
return bRet;
}
+void SwLayAction::SetAgain(bool bAgain)
+{
+ if (bAgain == m_bAgain)
+ return;
+
+ m_bAgain = bAgain;
+
+ assert(m_aFrameStack.size() == m_aFrameDeleteGuards.size());
+ size_t nCount = m_aFrameStack.size();
+ if (m_bAgain)
+ {
+ // LayAction::FormatLayout is now flagged to exit early and will avoid
+ // dereferencing any SwFrames in the stack of FormatLayouts so allow
+ // their deletion
+ for (size_t i = 0; i < nCount; ++i)
+ m_aFrameDeleteGuards[i].reset();
+ }
+ else
+ {
+ // LayAction::FormatLayout is now continue normally and will
+ // dereference the top SwFrame in the stack of m_aFrameStack as each
+ // FormatLevel returns so disallow their deletion
+ for (size_t i = 0; i < nCount; ++i)
+ m_aFrameDeleteGuards[i] = std::make_unique<SwFrameDeleteGuard>(m_aFrameStack[i]);
+ }
+}
+
+void SwLayAction::PushFormatLayout(SwFrame* pLow)
+{
+ /* Workaround crash seen in crashtesting with fdo53985-1.docx
+
+ Lock pLow against getting deleted when it will be dereferenced
+ after FormatLayout
+
+ If SetAgain is called to make SwLayAction exit early to avoid that
+ dereference, then it clears these guards
+ */
+ m_aFrameStack.push_back(pLow);
+ m_aFrameDeleteGuards.push_back(std::make_unique<SwFrameDeleteGuard>(pLow));
+}
+
+void SwLayAction::PopFormatLayout()
+{
+ m_aFrameDeleteGuards.pop_back();
+ m_aFrameStack.pop_back();
+}
+
void SwLayAction::Action(OutputDevice* pRenderContext)
{
m_bActionInProgress = true;
@@ -344,12 +395,15 @@ void SwLayAction::Action(OutputDevice* pRenderContext)
SetCheckPages( false );
InternalAction(pRenderContext);
- m_bAgain |= RemoveEmptyBrowserPages();
+ if (RemoveEmptyBrowserPages())
+ SetAgain(true);
while ( IsAgain() )
{
- m_bAgain = m_bNextCycle = false;
+ SetAgain(false);
+ m_bNextCycle = false;
InternalAction(pRenderContext);
- m_bAgain |= RemoveEmptyBrowserPages();
+ if (RemoveEmptyBrowserPages())
+ SetAgain(true);
}
m_pRoot->DeleteEmptySct();
@@ -448,15 +502,19 @@ void SwLayAction::InternalAction(OutputDevice* pRenderContext)
sal_uInt16 nPercentPageNum = 0;
while ((!IsInterrupt() && pPage) || (m_nCheckPageNum != USHRT_MAX))
{
- if (!pPage && m_nCheckPageNum != USHRT_MAX)
+ // note: this is the only place that consumes and resets m_nCheckPageNum
+ if ((IsInterrupt() || !pPage) && m_nCheckPageNum != USHRT_MAX)
{
- SwPageFrame *pPg = static_cast<SwPageFrame*>(m_pRoot->Lower());
- while (pPg && pPg->GetPhyPageNum() < m_nCheckPageNum)
- pPg = static_cast<SwPageFrame*>(pPg->GetNext());
- if (pPg)
- pPage = pPg;
- if (!pPage)
- break;
+ if (!pPage || m_nCheckPageNum < pPage->GetPhyPageNum())
+ {
+ SwPageFrame *pPg = static_cast<SwPageFrame*>(m_pRoot->Lower());
+ while (pPg && pPg->GetPhyPageNum() < m_nCheckPageNum)
+ pPg = static_cast<SwPageFrame*>(pPg->GetNext());
+ if (pPg)
+ pPage = pPg;
+ if (!pPage)
+ break;
+ }
SwPageFrame *pTmp = pPage->GetPrev() ?
static_cast<SwPageFrame*>(pPage->GetPrev()) : pPage;
@@ -637,7 +695,7 @@ void SwLayAction::InternalAction(OutputDevice* pRenderContext)
{
bool bOld = IsAgain();
m_pRoot->RemoveSuperfluous();
- m_bAgain = bOld;
+ SetAgain(bOld);
}
if ( IsAgain() )
{
@@ -1370,7 +1428,11 @@ bool SwLayAction::FormatLayout( OutputDevice *pRenderContext, SwLayoutFrame *pLa
}
// Skip the ones already registered for deletion
else if( !pLow->IsSctFrame() || static_cast<SwSectionFrame*>(pLow)->GetSection() )
+ {
+ PushFormatLayout(pLow);
bChanged |= FormatLayout( pRenderContext, static_cast<SwLayoutFrame*>(pLow), bAddRect );
+ PopFormatLayout();
+ }
}
else if ( m_pImp->GetShell()->IsPaintLocked() )
// Shortcut to minimize the cycles. With Lock, the
@@ -1594,8 +1656,51 @@ bool SwLayAction::FormatLayoutTab( SwTabFrame *pTab, bool bAddRect )
return bChanged;
}
-bool SwLayAction::FormatContent( const SwPageFrame *pPage )
+bool SwLayAction::FormatContent(SwPageFrame *const pPage)
{
+ ::comphelper::ScopeGuard g([this, pPage]() {
+ if (IsAgain())
+ {
+ return; // pPage probably deleted
+ }
+ if (auto const* pObjs = pPage->GetSortedObjs())
+ {
+ std::vector<std::pair<SwAnchoredObject*, SwPageFrame*>> moved;
+ for (auto const pObj : *pObjs)
+ {
+ assert(!pObj->AnchorFrame()->IsTextFrame()
+ || !static_cast<SwTextFrame const*>(pObj->AnchorFrame())->IsFollow());
+ SwPageFrame *const pAnchorPage(pObj->AnchorFrame()->FindPageFrame());
+ assert(pAnchorPage);
+ if (pAnchorPage != pPage
+ && pPage->GetPhyPageNum() < pAnchorPage->GetPhyPageNum()
+ && pObj->GetFrameFormat().GetAnchor().GetAnchorId()
+ != RndStdIds::FLY_AS_CHAR)
+ {
+ moved.emplace_back(pObj, pAnchorPage);
+ }
+ }
+ for (auto const& [pObj, pAnchorPage] : moved)
+ {
+ SAL_INFO("sw.layout", "SwLayAction::FormatContent: move anchored " << pObj << " from " << pPage->GetPhyPageNum() << " to " << pAnchorPage->GetPhyPageNum());
+ pObj->RegisterAtPage(*pAnchorPage);
+ // tdf#143239 if the position remains valid, it may not be
+ // positioned again so would remain on the wrong page!
+ pObj->InvalidateObjPos();
+ ::Notify_Background(pObj->GetDrawObj(), pPage,
+ pObj->GetObjRect(), PREP_FLY_LEAVE, false);
+ }
+ if (!moved.empty())
+ {
+ pPage->InvalidateFlyLayout();
+ if (auto *const pContent = pPage->FindLastBodyContent())
+ {
+ pContent->InvalidateSize();
+ }
+ }
+ }
+ });
+
const SwContentFrame *pContent = pPage->ContainsContent();
const SwViewShell *pSh = m_pRoot->GetCurrShell();
const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
diff --git a/sw/source/core/layout/newfrm.cxx b/sw/source/core/layout/newfrm.cxx
index 1d1f4597fcf2..39ea1c9c2bc0 100644
--- a/sw/source/core/layout/newfrm.cxx
+++ b/sw/source/core/layout/newfrm.cxx
@@ -502,6 +502,11 @@ void SwRootFrame::Init( SwFrameFormat* pFormat )
::InsertCnt_( pLay, pDoc, aTmp.GetIndex(), true );
//Remove masters that haven't been replaced yet from the list.
RemoveMasterObjs( mpDrawPage );
+
+ // tdf#156077 create all pages for at-page anchored flys now because all
+ // these flys must be attached to some page when Init() is finished
+ AssertFlyPages();
+
if( rSettingAccess.get(DocumentSettingId::GLOBAL_DOCUMENT) )
rFieldsAccess.UpdateRefFields();
//b6433357: Update page fields after loading
diff --git a/sw/source/core/layout/objectformattertxtfrm.cxx b/sw/source/core/layout/objectformattertxtfrm.cxx
index 1ba020a84901..57c3c7680da0 100644
--- a/sw/source/core/layout/objectformattertxtfrm.cxx
+++ b/sw/source/core/layout/objectformattertxtfrm.cxx
@@ -29,6 +29,7 @@
#include <fmtwrapinfluenceonobjpos.hxx>
#include <fmtfollowtextflow.hxx>
#include <layact.hxx>
+#include <flyfrm.hxx>
#include <ftnfrm.hxx>
using namespace ::com::sun::star;
@@ -224,11 +225,16 @@ bool SwObjectFormatterTextFrame::DoFormatObj( SwAnchoredObject& _rAnchoredObj,
sal_uInt32 nToPageNum( 0 );
// #i43913#
bool bDummy( false );
- // #i58182# - consider new method signature
+ bool bPageHasFlysAnchoredBelowThis(false);
+ // see how SwObjectFormatter::FormatObjsAtFrame_() checks
+ // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
+ // this subclass
+ assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(nIdx));
if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( nIdx ),
- GetPgNumOfCollected( nIdx ),
+ GetPageFrame(),
IsCollectedAnchoredAtMaster( nIdx ),
- nToPageNum, bDummy ) )
+ nToPageNum, bDummy,
+ bPageHasFlysAnchoredBelowThis))
{
// #i49987# - consider, that anchor frame
// could already been marked to move forward.
@@ -239,7 +245,12 @@ bool SwObjectFormatterTextFrame::DoFormatObj( SwAnchoredObject& _rAnchoredObj,
rDoc, mrAnchorTextFrame, nMovedFwdToPageNum ) )
{
if ( nMovedFwdToPageNum < nToPageNum )
- SwLayouter::RemoveMovedFwdFrame( rDoc, mrAnchorTextFrame );
+ {
+ if (!bPageHasFlysAnchoredBelowThis)
+ {
+ SwLayouter::RemoveMovedFwdFrame(rDoc, mrAnchorTextFrame);
+ }
+ }
else
bInsert = false;
}
@@ -247,8 +258,11 @@ bool SwObjectFormatterTextFrame::DoFormatObj( SwAnchoredObject& _rAnchoredObj,
{
// Indicate that anchor text frame has to move forward and
// invalidate its position to force a re-format.
- SwLayouter::InsertMovedFwdFrame( rDoc, mrAnchorTextFrame,
- nToPageNum );
+ if (!bPageHasFlysAnchoredBelowThis)
+ {
+ SwLayouter::InsertMovedFwdFrame(rDoc,
+ mrAnchorTextFrame, nToPageNum);
+ }
mrAnchorTextFrame.InvalidatePos();
// Indicate restart of the layout process
@@ -293,7 +307,7 @@ bool SwObjectFormatterTextFrame::DoFormatObjs()
{
// notify layout action, thus is can restart the layout process on
// a previous page.
- GetLayAction()->SetAgain();
+ GetLayAction()->SetAgain(true);
}
else
{
@@ -350,13 +364,14 @@ bool SwObjectFormatterTextFrame::DoFormatObjs()
sal_uInt32 nToPageNum( 0 );
// #i43913#
bool bInFollow( false );
+ bool bPageHasFlysAnchoredBelowThis(false);
SwAnchoredObject* pObj = nullptr;
if ( !mrAnchorTextFrame.IsFollow() )
{
pObj = GetFirstObjWithMovedFwdAnchor(
// #i35017# - constant name has changed
text::WrapInfluenceOnPosition::ONCE_CONCURRENT,
- nToPageNum, bInFollow );
+ nToPageNum, bInFollow, bPageHasFlysAnchoredBelowThis );
}
// #i35911#
if ( pObj && pObj->HasClearedEnvironment() )
@@ -377,14 +392,22 @@ bool SwObjectFormatterTextFrame::DoFormatObjs()
rDoc, mrAnchorTextFrame, nTmpToPageNum ) )
{
if ( nTmpToPageNum < pAnchorPageFrame->GetPhyPageNum() )
- SwLayouter::RemoveMovedFwdFrame( rDoc, mrAnchorTextFrame );
+ {
+ if (!bPageHasFlysAnchoredBelowThis)
+ {
+ SwLayouter::RemoveMovedFwdFrame(rDoc, mrAnchorTextFrame);
+ }
+ }
else
bInsert = false;
}
if ( bInsert )
{
- SwLayouter::InsertMovedFwdFrame( rDoc, mrAnchorTextFrame,
- pAnchorPageFrame->GetPhyPageNum() );
+ if (!bPageHasFlysAnchoredBelowThis)
+ {
+ SwLayouter::InsertMovedFwdFrame(rDoc, mrAnchorTextFrame,
+ pAnchorPageFrame->GetPhyPageNum());
+ }
mrAnchorTextFrame.InvalidatePos();
bSuccess = false;
InvalidatePrevObjs( *pObj );
@@ -503,7 +526,8 @@ void SwObjectFormatterTextFrame::InvalidateFollowObjs( SwAnchoredObject& _rAncho
SwAnchoredObject* SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor(
const sal_Int16 _nWrapInfluenceOnPosition,
sal_uInt32& _noToPageNum,
- bool& _boInFollow )
+ bool& _boInFollow,
+ bool& o_rbPageHasFlysAnchoredBelowThis)
{
// #i35017# - constant names have changed
OSL_ENSURE( _nWrapInfluenceOnPosition == text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE ||
@@ -521,13 +545,17 @@ SwAnchoredObject* SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor(
// #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
GetWrapInfluenceOnObjPos( true ) == _nWrapInfluenceOnPosition )
{
+ // see how SwObjectFormatter::FormatObjsAtFrame_() checks
+ // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
+ // this subclass
+ assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(i));
// #i26945# - use new method <_CheckMovedFwdCondition(..)>
// #i43913#
- // #i58182# - consider new method signature
if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( i ),
- GetPgNumOfCollected( i ),
+ GetPageFrame(),
IsCollectedAnchoredAtMaster( i ),
- _noToPageNum, _boInFollow ) )
+ _noToPageNum, _boInFollow,
+ o_rbPageHasFlysAnchoredBelowThis) )
{
pRetAnchoredObj = pAnchoredObj;
break;
@@ -538,15 +566,49 @@ SwAnchoredObject* SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor(
return pRetAnchoredObj;
}
+static SwRowFrame const* FindTopLevelRowFrame(SwFrame const*const pFrame)
+{
+ SwRowFrame * pRow = const_cast<SwFrame*>(pFrame)->FindRowFrame();
+ // looks like SwTabFrame has mbInfTab = true so go up 2 levels
+ while (pRow->GetUpper()->GetUpper()->IsInTab())
+ {
+ pRow = pRow->GetUpper()->GetUpper()->FindRowFrame();
+ }
+ return pRow;
+}
+
+static SwContentFrame const* FindFrameInBody(SwAnchoredObject const& rAnchored)
+{
+ SwFrame const*const pAnchor(rAnchored.GetAnchorFrame());
+ assert(pAnchor);
+ if (pAnchor->IsPageFrame() || pAnchor->FindFooterOrHeader())
+ {
+ return nullptr;
+ }
+ if (pAnchor->IsInFly())
+ {
+ return FindFrameInBody(*pAnchor->FindFlyFrame());
+ }
+ if (pAnchor->IsInFootnote())
+ {
+ return pAnchor->FindFootnoteFrame()->GetRef();
+ }
+ assert(pAnchor->IsInDocBody());
+ assert(pAnchor->IsContentFrame());
+ return static_cast<SwContentFrame const*>(pAnchor);
+}
+
// #i58182#
// - replace private method by corresponding static public method
bool SwObjectFormatterTextFrame::CheckMovedFwdCondition(
SwAnchoredObject& _rAnchoredObj,
- const sal_uInt32 _nFromPageNum,
+ SwPageFrame const& rFromPageFrame,
const bool _bAnchoredAtMasterBeforeFormatAnchor,
sal_uInt32& _noToPageNum,
- bool& _boInFollow )
+ bool& _boInFollow,
+ bool& o_rbPageHasFlysAnchoredBelowThis)
{
+ const sal_uInt32 _nFromPageNum(rFromPageFrame.GetPhyPageNum());
bool bAnchorIsMovedForward( false );
SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor();
@@ -621,6 +683,69 @@ bool SwObjectFormatterTextFrame::CheckMovedFwdCondition(
}
}
+ if (bAnchorIsMovedForward)
+ {
+ // tdf#138518 try to determine if there is a fly on page rFromPageFrame
+ // which is anchored in a frame that is "below" the anchor frame
+ // of _rAnchoredObj, such that it should move to the next page before
+ // _rAnchoredObj does
+ if (auto * pObjs = rFromPageFrame.GetSortedObjs())
+ {
+ for (SwAnchoredObject *const pObj : *pObjs)
+ {
+ SwPageFrame const*const pObjAnchorPage(pObj->FindPageFrameOfAnchor());
+ assert(pObjAnchorPage);
+ if ((pObjAnchorPage == &rFromPageFrame
+ ? _boInFollow // same-page but will move forward
+ : rFromPageFrame.GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum())
+ && pObj->GetFrameFormat().GetAnchor().GetAnchorId()
+ != RndStdIds::FLY_AS_CHAR)
+ {
+ if (pPageFrameOfAnchor->GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum())
+ {
+ SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next page");
+ o_rbPageHasFlysAnchoredBelowThis = true;
+ break;
+ }
+ // on same page: check if it's in next-chain in the document body
+ // (in case both are in the same fly the flag must not be
+ // set because the whole fly moves at once)
+ SwContentFrame const*const pInBodyFrameObj(FindFrameInBody(*pObj));
+ SwContentFrame const*const pInBodyFrameAnchoredObj(FindFrameInBody(_rAnchoredObj));
+ if (pInBodyFrameObj && pInBodyFrameAnchoredObj)
+ {
+ bool isBreakMore(false);
+ // currently this ignores index of at-char flys
+ for (SwContentFrame const* pContentFrame = pInBodyFrameAnchoredObj->FindNextCnt();
+ pContentFrame;
+ pContentFrame = pContentFrame->FindNextCnt())
+ {
+ if (pInBodyFrameObj == pContentFrame)
+ {
+ // subsequent cells in a row are not automatically
+ // "below" and the row could potentially be split
+ // TODO refine check if needed
+ if (!pInBodyFrameAnchoredObj->IsInTab()
+ || FindTopLevelRowFrame(pInBodyFrameAnchoredObj)
+ != FindTopLevelRowFrame(pInBodyFrameAnchoredObj))
+ { // anchored in next chain on same page
+ SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next chain on same page");
+ o_rbPageHasFlysAnchoredBelowThis = true;
+ isBreakMore = true;
+ }
+ break;
+ }
+ }
+ if (isBreakMore)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
return bAnchorIsMovedForward;
}
@@ -641,6 +766,7 @@ static void lcl_FormatContentOfLayoutFrame( SwLayoutFrame* pLayFrame,
if ( pLowerFrame->IsLayoutFrame() )
{
SwFrameDeleteGuard aCrudeHack(pLowerFrame); // ??? any issue setting this for non-footnote frames?
+ // prevent moving footnotes by formatting if they are already being moved
lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pLowerFrame),
pLastLowerFrame );
}
@@ -686,21 +812,46 @@ void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame& _rAn
// for follow text frames.
if ( !_rAnchorTextFrame.IsFollow() )
{
+ // In case the anchor frame is in a column or section, format its
+ // previous frames first - but don't jump out of the current layout
+ // environment, e.g. from footnotes into the footnote boss.
+ SwFrame * pSectFrame(nullptr);
+ SwFrame * pColFrameOfAnchor(nullptr);
+ for (SwFrame* pUpper = _rAnchorTextFrame.GetUpper();
+ pUpper != nullptr; pUpper = pUpper->GetUpper())
+ {
+ if (pUpper->IsCellFrame())
+ {
+ break; // apparently nothing to be done?
+ }
+ if (pUpper->IsFootnoteFrame())
+ {
+ SAL_INFO_IF(pColFrameOfAnchor == nullptr && pUpper->FindColFrame(),
+ "sw.layout", "tdf#122894 skipping column for footnote in column");
+ break; // stop: prevent crash in case footnotes are being moved
+ }
+ if (pUpper->IsSctFrame())
+ {
+ pColFrameOfAnchor = nullptr;
+ pSectFrame = pUpper;
+ break;
+ }
+ if (pColFrameOfAnchor != nullptr)
+ { // parent of column not a section frame => column not in section
+ break;
+ }
+ if (pUpper->IsColumnFrame())
+ {
+ pColFrameOfAnchor = pUpper;
+ }
+ }
+
// if anchor frame is directly inside a section, format this section and
// its previous frames.
// Note: It's a very simple format without formatting objects.
- if ( _rAnchorTextFrame.IsInSct() )
+ if (pSectFrame)
{
- SwFrame* pSectFrame = _rAnchorTextFrame.GetUpper();
- while ( pSectFrame )
- {
- if ( pSectFrame->IsSctFrame() || pSectFrame->IsCellFrame() )
- {
- break;
- }
- pSectFrame = pSectFrame->GetUpper();
- }
- if ( pSectFrame && pSectFrame->IsSctFrame() )
+ assert(pSectFrame->IsSctFrame());
{
SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
// #i44049#
@@ -711,6 +862,8 @@ void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame& _rAn
// Thus, check for valid <pFrame>.
while ( pFrame && pFrame != pSectFrame )
{
+ SwFrameDeleteGuard aDeleteFrameGuard(pFrame);
+
if ( pFrame->IsLayoutFrame() )
lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
else
@@ -728,9 +881,9 @@ void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame& _rAn
// #i40140# - if anchor frame is inside a column,
// format the content of the previous columns.
// Note: It's a very simple format without formatting objects.
- SwFrame* pColFrameOfAnchor = _rAnchorTextFrame.FindColFrame();
- if ( pColFrameOfAnchor )
+ if (pColFrameOfAnchor)
{
+ assert(pColFrameOfAnchor->IsColumnFrame());
// #i44049#
_rAnchorTextFrame.LockJoin();
SwFrame* pColFrame = pColFrameOfAnchor->GetUpper()->GetLower();
diff --git a/sw/source/core/layout/objectformattertxtfrm.hxx b/sw/source/core/layout/objectformattertxtfrm.hxx
index cf3b955addb1..ae7b2efe227e 100644
--- a/sw/source/core/layout/objectformattertxtfrm.hxx
+++ b/sw/source/core/layout/objectformattertxtfrm.hxx
@@ -96,7 +96,8 @@ class SwObjectFormatterTextFrame : public SwObjectFormatter
SwAnchoredObject* GetFirstObjWithMovedFwdAnchor(
const sal_Int16 _nWrapInfluenceOnPosition,
sal_uInt32& _noToPageNum,
- bool& _boInFollow );
+ bool& _boInFollow,
+ bool& o_rbPageHasFlysAnchoredBelowThis);
/** method to format the anchor frame for checking of the move forward condition
@@ -169,15 +170,19 @@ class SwObjectFormatterTextFrame : public SwObjectFormatter
output parameter - boolean, indicating that anchor text frame is
currently on the same page, but it's a follow of in a follow row,
which will move forward. value only relevant, if method return <true>.
+ @param o_rbPageHasFlysAnchoredBelowThis
+ output parameter - indicates that the page has flys anchored
+ somewhere below the anchor of the passed _rAnchoredObj
@return boolean
indicating, if 'anchor is moved forward'
*/
static bool CheckMovedFwdCondition( SwAnchoredObject& _rAnchoredObj,
- const sal_uInt32 _nFromPageNum,
+ SwPageFrame const& rFromPageFrame,
const bool _bAnchoredAtMasterBeforeFormatAnchor,
sal_uInt32& _noToPageNum,
- bool& _boInFollow );
+ bool& _boInFollow,
+ bool& o_rbPageHasFlysAnchoredBelowThis);
};
#endif
diff --git a/sw/source/core/layout/pagechg.cxx b/sw/source/core/layout/pagechg.cxx
index a684b1602a1a..b1a04f0890c6 100644
--- a/sw/source/core/layout/pagechg.cxx
+++ b/sw/source/core/layout/pagechg.cxx
@@ -284,7 +284,7 @@ void SwPageFrame::DestroyImpl()
SwViewShellImp *pImp = pSh->Imp();
pImp->SetFirstVisPageInvalid();
if ( pImp->IsAction() )
- pImp->GetLayAction().SetAgain();
+ pImp->GetLayAction().SetAgain(true);
// #i9719# - retouche area of page
// including border and shadow area.
const bool bRightSidebar = (SidebarPosition() == sw::sidebarwindows::SidebarPosition::RIGHT);
@@ -990,11 +990,68 @@ void SwPageFrame::PrepareRegisterChg()
}
}
+namespace sw {
+
+/// check if there's content on the page that requires it to exist
+bool IsPageFrameEmpty(SwPageFrame const& rPage)
+{
+ bool bExistEssentialObjs = (nullptr != rPage.GetSortedObjs());
+ if (bExistEssentialObjs)
+ {
+ // Only because the page has Flys does not mean that it is needed. If all Flys are
+ // attached to generic content it is also superfluous (checking DocBody should be enough)
+ // OD 19.06.2003 - consider that drawing objects in
+ // header/footer are supported now.
+ bool bOnlySuperfluousObjs = true;
+ SwSortedObjs const& rObjs = *rPage.GetSortedObjs();
+ for (size_t i = 0; bOnlySuperfluousObjs && i < rObjs.size(); ++i)
+ {
+ // #i28701#
+ SwAnchoredObject* pAnchoredObj = rObjs[i];
+ // do not consider hidden objects
+ if ( rPage.GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(
+ pAnchoredObj->GetDrawObj()->GetLayer() ) &&
+ !pAnchoredObj->GetAnchorFrame()->FindFooterOrHeader() )
+ {
+ bOnlySuperfluousObjs = false;
+ }
+ }
+ bExistEssentialObjs = !bOnlySuperfluousObjs;
+ }
+
+ // optimization: check first if essential objects exist.
+ const SwLayoutFrame* pBody = nullptr;
+ if ( bExistEssentialObjs ||
+ rPage.FindFootnoteCont() ||
+ (nullptr != (pBody = rPage.FindBodyCont()) &&
+ ( pBody->ContainsContent() ||
+ // check for section frames that are being formatted on the stack
+ rPage.ContainsDeleteForbiddenLayFrame() ||
+ // #i47580#
+ // Do not delete page if there's an empty tabframe
+ // left. I think it might be correct to use ContainsAny()
+ // instead of ContainsContent() to cover the empty-table-case,
+ // but I'm not fully sure, since ContainsAny() also returns
+ // SectionFrames. Therefore I prefer to do it the safe way:
+ ( pBody->Lower() && pBody->Lower()->IsTabFrame() ) ) ) )
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+} // namespace sw
+
//FIXME: provide missing documentation
/** Check all pages (starting from the given one) if they use the appropriate frame format.
*
* If "wrong" pages are found, try to fix this as simple as possible.
*
+ * Also delete pages that don't have content on them.
+ *
* @param pStart the page from where to start searching
* @param bNotifyFields
* @param ppPrev
@@ -1032,7 +1089,10 @@ void SwFrame::CheckPageDescs( SwPageFrame *pStart, bool bNotifyFields, SwPageFra
SwPageFrame *pNextPage = static_cast<SwPageFrame*>(pPage->GetNext());
SwPageDesc *pDesc = pPage->FindPageDesc();
+ /// page is intentionally empty page
bool bIsEmpty = pPage->IsEmptyPage();
+ // false for intentionally empty pages, they need additional check
+ bool isPageFrameEmpty(!bIsEmpty && sw::IsPageFrameEmpty(*pPage));
bool bIsOdd = pPage->OnRightPage();
bool bWantOdd = pPage->WannaRightPage();
bool bFirst = pPage->OnFirstPage();
@@ -1129,6 +1189,7 @@ void SwFrame::CheckPageDescs( SwPageFrame *pStart, bool bNotifyFields, SwPageFra
pTmp->Paste( pRoot, pPage );
pTmp->PreparePage( false );
pPage = pTmp;
+ isPageFrameEmpty = false; // don't delete it right away!
}
else if ( pPage->GetPageDesc() != pDesc ) //4.
{
@@ -1172,16 +1233,21 @@ void SwFrame::CheckPageDescs( SwPageFrame *pStart, bool bNotifyFields, SwPageFra
}
#endif
}
- if ( bIsEmpty )
+ assert(!bIsEmpty || !isPageFrameEmpty);
+ if (bIsEmpty || isPageFrameEmpty)
{
// It also might be that an empty page is not needed at all.
// However, the algorithm above cannot determine that. It is not needed if the following
// page can live without it. Do obtain that information, we need to dig deeper...
SwPageFrame *pPg = static_cast<SwPageFrame*>(pPage->GetNext());
- if( !pPg || pPage->OnRightPage() == pPg->WannaRightPage() )
+ if (isPageFrameEmpty || !pPg || pPage->OnRightPage() == pPg->WannaRightPage())
{
// The following page can find a FrameFormat or has no successor -> empty page not needed
SwPageFrame *pTmp = static_cast<SwPageFrame*>(pPage->GetNext());
+ if (isPageFrameEmpty && pPage->GetPrev())
+ { // check previous *again* vs. its new next! see "ooo321_stylepagenumber.odt"
+ pTmp = static_cast<SwPageFrame*>(pPage->GetPrev());
+ }
pPage->Cut();
bool bUpdatePrev = false;
if (ppPrev && *ppPrev == pPage)
@@ -1441,44 +1507,7 @@ void SwRootFrame::RemoveSuperfluous()
// Check the corresponding last page if it is empty and stop loop at the last non-empty page.
do
{
- bool bExistEssentialObjs = ( nullptr != pPage->GetSortedObjs() );
- if ( bExistEssentialObjs )
- {
- // Only because the page has Flys does not mean that it is needed. If all Flys are
- // attached to generic content it is also superfluous (checking DocBody should be enough)
- // OD 19.06.2003 #108784# - consider that drawing objects in
- // header/footer are supported now.
- bool bOnlySuperfluosObjs = true;
- SwSortedObjs &rObjs = *pPage->GetSortedObjs();
- for ( size_t i = 0; bOnlySuperfluosObjs && i < rObjs.size(); ++i )
- {
- // #i28701#
- SwAnchoredObject* pAnchoredObj = rObjs[i];
- // OD 2004-01-19 #110582# - do not consider hidden objects
- if ( pPage->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(
- pAnchoredObj->GetDrawObj()->GetLayer() ) &&
- !pAnchoredObj->GetAnchorFrame()->FindFooterOrHeader() )
- {
- bOnlySuperfluosObjs = false;
- }
- }
- bExistEssentialObjs = !bOnlySuperfluosObjs;
- }
-
- // OD 19.06.2003 #108784# - optimization: check first, if essential objects
- // exists.
- const SwLayoutFrame* pBody = nullptr;
- if ( bExistEssentialObjs ||
- pPage->FindFootnoteCont() ||
- ( nullptr != ( pBody = pPage->FindBodyCont() ) &&
- ( pBody->ContainsContent() ||
- // #i47580#
- // Do not delete page if there's an empty tabframe
- // left. I think it might be correct to use ContainsAny()
- // instead of ContainsContent() to cover the empty-table-case,
- // but I'm not fully sure, since ContainsAny() also returns
- // SectionFrames. Therefore I prefer to do it the safe way:
- ( pBody->Lower() && pBody->Lower()->IsTabFrame() ) ) ) )
+ if (!sw::IsPageFrameEmpty(*pPage))
{
if ( pPage->IsFootnotePage() )
{
@@ -1976,6 +2005,11 @@ static void lcl_MoveAllLowerObjs( SwFrame* pFrame, const Point& rOffset )
{
SwFlyFrame* pFlyFrame( static_cast<SwFlyFrame*>(pAnchoredObj) );
lcl_MoveAllLowers( pFlyFrame, rOffset );
+ // tdf#138785 update position specific to as-char flys
+ if (pFlyFrame->IsFlyInContentFrame())
+ {
+ static_cast<SwFlyInContentFrame*>(pFlyFrame)->AddRefOfst(rOffset);
+ }
pFlyFrame->NotifyDrawObj();
// --> let the active embedded object be moved
SwFrame* pLower = pFlyFrame->Lower();
diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx
index 524562585bd1..48debbcc399a 100644
--- a/sw/source/core/layout/sectfrm.cxx
+++ b/sw/source/core/layout/sectfrm.cxx
@@ -2863,7 +2863,8 @@ void SwRootFrame::DeleteEmptySct_()
mpDestroy->erase( mpDestroy->begin() );
OSL_ENSURE( !pSect->IsColLocked() && !pSect->IsJoinLocked(),
"DeleteEmptySct: Locked SectionFrame" );
- if( !pSect->getFrameArea().HasArea() && !pSect->ContainsContent() )
+ SAL_WARN_IF(pSect->IsDeleteForbidden(), "sw.layout", "not allowed delete SwFrame");
+ if( !pSect->getFrameArea().HasArea() && !pSect->ContainsContent() && !pSect->IsDeleteForbidden() )
{
SwLayoutFrame* pUp = pSect->GetUpper();
pSect->RemoveFromLayout();
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 719f08e5a363..f39250dcc67b 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -23,6 +23,7 @@
#include <viewimp.hxx>
#include <fesh.hxx>
#include <swtable.hxx>
+#include <deletelistener.hxx>
#include <dflyobj.hxx>
#include <anchoreddrawobject.hxx>
#include <fmtanchr.hxx>
@@ -73,6 +74,7 @@ SwTabFrame::SwTabFrame( SwTable &rTab, SwFrame* pSib )
, m_bCalcLowers(false)
, m_bLowersFormatted(false)
, m_bLockBackMove(false)
+ , m_bWantBackMove(false)
, m_bResizeHTMLTable(false)
, m_bONECalcLowers(false)
, m_bHasFollowFlowLine(false)
@@ -112,6 +114,7 @@ SwTabFrame::SwTabFrame( SwTabFrame &rTab )
, m_bCalcLowers(false)
, m_bLowersFormatted(false)
, m_bLockBackMove(false)
+ , m_bWantBackMove(false)
, m_bResizeHTMLTable(false)
, m_bONECalcLowers(false)
, m_bHasFollowFlowLine(false)
@@ -1343,13 +1346,30 @@ bool SwTabFrame::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowK
return bRet;
}
+namespace
+{
+ bool CanDeleteFollow(SwTabFrame *pFoll)
+ {
+ if (pFoll->IsJoinLocked())
+ return false;
+
+ if (pFoll->IsDeleteForbidden())
+ {
+ SAL_WARN("sw.layout", "Delete Forbidden");
+ return false;
+ }
+
+ return true;
+ }
+}
+
void SwTabFrame::Join()
{
OSL_ENSURE( !HasFollowFlowLine(), "Joining follow flow line" );
SwTabFrame *pFoll = GetFollow();
- if (pFoll && !pFoll->IsJoinLocked())
+ if (pFoll && CanDeleteFollow(pFoll))
{
SwRectFnSet aRectFnSet(this);
pFoll->Cut(); //Cut out first to avoid unnecessary notifications.
@@ -1578,6 +1598,8 @@ static bool lcl_InnerCalcLayout( SwFrame *pFrame,
if ( pFrame->IsLayoutFrame() &&
( !_bOnlyRowsAndCells || pFrame->IsRowFrame() || pFrame->IsCellFrame() ) )
{
+ SwFrameDeleteGuard aDeleteGuard(pFrame);
+
// #130744# An invalid locked table frame will
// not be calculated => It will not become valid =>
// Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet.
@@ -1837,7 +1859,7 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
// is not locked. Otherwise, join will not be performed and this loop
// will be endless.
while ( GetNext() && GetNext() == GetFollow() &&
- !GetFollow()->IsJoinLocked()
+ CanDeleteFollow(GetFollow())
)
{
if ( HasFollowFlowLine() )
@@ -1990,8 +2012,6 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
pAccess.reset();
m_bCalcLowers |= pLayout->Resize(
pLayout->GetBrowseWidthByTabFrame( *this ) );
- pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
- pAttrs = pAccess->Get();
}
setFramePrintAreaValid(false);
@@ -2020,6 +2040,12 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
const long nOldPrtWidth = aRectFnSet.GetWidth(getFramePrintArea());
const long nOldFrameWidth = aRectFnSet.GetWidth(getFrameArea());
const Point aOldPrtPos = aRectFnSet.GetPos(getFramePrintArea());
+
+ if (!pAccess)
+ {
+ pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
+ pAttrs = pAccess->Get();
+ }
Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs );
SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
@@ -2030,8 +2056,6 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
pAccess.reset();
m_bCalcLowers |= pLayout->Resize(
pLayout->GetBrowseWidthByTabFrame( *this ) );
- pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
- pAttrs = pAccess->Get();
}
if ( aOldPrtPos != aRectFnSet.GetPos(getFramePrintArea()) )
aNotify.SetLowersComplete( false );
@@ -2059,12 +2083,18 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
}
SwFootnoteBossFrame *pOldBoss = bFootnotesInDoc ? FindFootnoteBossFrame( true ) : nullptr;
bool bReformat;
+ std::optional<SfxDeleteListener> oDeleteListener;
+ if (pOldBoss)
+ oDeleteListener.emplace(*pOldBoss);
+ SwFrameDeleteGuard g(this);
if ( MoveBwd( bReformat ) )
{
+ SAL_WARN_IF(oDeleteListener && oDeleteListener->WasDeleted(), "sw.layout", "SwFootnoteBossFrame unexpectedly deleted");
+
aRectFnSet.Refresh(this);
bMovedBwd = true;
aNotify.SetLowersComplete( false );
- if ( bFootnotesInDoc )
+ if (bFootnotesInDoc && !oDeleteListener->WasDeleted())
MoveLowerFootnotes( nullptr, pOldBoss, nullptr, true );
if ( bReformat || bKeep )
{
@@ -2079,15 +2109,22 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
pAccess.reset();
m_bCalcLowers |= pHTMLLayout->Resize(
pHTMLLayout->GetBrowseWidthByTabFrame( *this ) );
+ }
+
+ setFramePrintAreaValid(false);
+ if (!pAccess)
+ {
pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
pAttrs = pAccess->Get();
}
-
- setFramePrintAreaValid(false);
Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs );
}
+
+ pAccess.reset();
+
lcl_RecalcTable( *this, nullptr, aNotify );
+
m_bLowersFormatted = true;
if ( bKeep && KEEPTAB )
{
@@ -2251,11 +2288,18 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
// 6. There is no section change behind the table (see IsKeep)
// 7. The last table row wants to keep with its next.
const SwRowFrame* pLastRow = static_cast<const SwRowFrame*>(GetLastLower());
- if (pLastRow
- && IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), true)
- && pLastRow->ShouldRowKeepWithNext())
+ if (pLastRow)
{
- bFormat = true;
+ if (!pAccess)
+ {
+ pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
+ pAttrs = pAccess->Get();
+ }
+ if (IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), true)
+ && pLastRow->ShouldRowKeepWithNext())
+ {
+ bFormat = true;
+ }
}
}
@@ -2269,9 +2313,6 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
// is found, get its first content.
const SwFrame* pTmpNxt = sw_FormatNextContentForKeep( this );
- pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
- pAttrs = pAccess->Get();
-
// The last row wants to keep with the frame behind the table.
// Check if the next frame is on a different page and valid.
// In this case we do a magic trick:
@@ -2512,9 +2553,6 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
GetFollow()->MakeAll(pRenderContext);
- pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
- pAttrs = pAccess->Get();
-
GetFollow()->SetLowersFormatted(false);
// #i43913# - lock follow table
// to avoid its formatting during the format of
@@ -3513,9 +3551,17 @@ bool SwTabFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool &rReformat )
}
else if (!m_bLockBackMove)
bMoveAnyway = true;
+ else
+ {
+ m_bWantBackMove = true;
+ }
}
else if (!m_bLockBackMove)
bMoveAnyway = true;
+ else
+ {
+ m_bWantBackMove = true;
+ }
if ( bMoveAnyway )
{
@@ -3527,7 +3573,7 @@ bool SwTabFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool &rReformat )
// This frame fits into pNewUpper in case it has no space, but this
// frame is empty.
bFits = nSpace >= 0;
- if (!m_bLockBackMove && bFits)
+ if (bFits)
{
// #i26945# - check, if follow flow line
// contains frame, which are moved forward due to its object
@@ -3546,7 +3592,17 @@ bool SwTabFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool &rReformat )
// 'return nHeight <= nSpace' to 'return nTmpHeight < nSpace'.
// This obviously results in problems with table frames in
// sections. Remember: Every twip is sacred.
- return nTmpHeight <= nSpace;
+ if (nTmpHeight <= nSpace)
+ {
+ if (m_bLockBackMove)
+ {
+ m_bWantBackMove = true;
+ }
+ else
+ {
+ return true;
+ }
+ }
}
}
return false;
@@ -5506,9 +5562,12 @@ static SwTwips lcl_CalcHeightOfFirstContentLine( const SwRowFrame& rSourceLine )
const SwRowFrame* pTmpSourceRow = static_cast<const SwRowFrame*>(pCurrSourceCell->Lower());
nTmpHeight = lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow );
}
- else if ( pTmp->IsTabFrame() )
+ else if (pTmp->IsTabFrame() || (pTmp->IsSctFrame() && pTmp->GetLower() && pTmp->GetLower()->IsTabFrame()))
{
- nTmpHeight = static_cast<const SwTabFrame*>(pTmp)->CalcHeightOfFirstContentLine();
+ SwTabFrame const*const pTabFrame(pTmp->IsTabFrame()
+ ? static_cast<SwTabFrame const*>(pTmp)
+ : static_cast<SwTabFrame const*>(pTmp->GetLower()));
+ nTmpHeight = pTabFrame->CalcHeightOfFirstContentLine();
}
else if (pTmp->IsTextFrame() || (pTmp->IsSctFrame() && pTmp->GetLower() && pTmp->GetLower()->IsTextFrame()))
{
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index f17a7ba68870..14aa081621f1 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -57,6 +57,7 @@
#include <sortedobjs.hxx>
#include <frmatr.hxx>
#include <frmtool.hxx>
+#include <layact.hxx>
#include <ndtxt.hxx>
// RotateFlyFrame3
@@ -317,7 +318,7 @@ SwFrame::SwFrame( SwModify *pMod, SwFrame* pSib )
mbInfSct ( false ),
mbColLocked(false),
m_isInDestroy(false),
- mbForbidDelete(false)
+ mnForbidDelete(0)
{
OSL_ENSURE( pMod, "No frame format given." );
}
@@ -1200,6 +1201,23 @@ void SwContentFrame::Cut()
if ( pRoot )
{
pRoot->SetSuperfluous();
+ // RemoveSuperfluous can only remove empty pages at the end;
+ // find if there are pages without content following pPage
+ // and if so request a call to CheckPageDescs()
+ SwViewShell *pSh = pRoot->GetCurrShell();
+ // tdf#152983 pPage is null when called from SwHeadFootFrame ctor
+ if (pPage && pSh && pSh->Imp()->IsAction())
+ {
+ SwPageFrame const* pNext(pPage);
+ while ((pNext = static_cast<SwPageFrame const*>(pNext->GetNext())))
+ {
+ if (!sw::IsPageFrameEmpty(*pNext) && !pNext->IsFootnotePage())
+ {
+ pSh->Imp()->GetLayAction().SetCheckPageNum(pPage->GetPhyPageNum());
+ break;
+ }
+ }
+ }
GetUpper()->SetCompletePaint();
GetUpper()->InvalidatePage( pPage );
}
diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx
index 9000d6ef1b9e..8ff9b35967ce 100644
--- a/sw/source/core/ole/ndole.cxx
+++ b/sw/source/core/ole/ndole.cxx
@@ -147,6 +147,8 @@ void SAL_CALL SwOLEListener_Impl::disposing( const lang::EventObject& )
// TODO/LATER: actually SwEmbedObjectLink should be used here, but because different objects are used to control
// embedded object different link objects with the same functionality had to be implemented
+namespace {
+
class SwEmbedObjectLink : public sfx2::SvBaseLink
{
SwOLENode* pOleNode;
@@ -209,6 +211,44 @@ void SwEmbedObjectLink::Closed()
SvBaseLink::Closed();
}
+class SwIFrameLink : public sfx2::SvBaseLink
+{
+ SwOLENode* m_pOleNode;
+
+public:
+ explicit SwIFrameLink(SwOLENode* pNode)
+ : ::sfx2::SvBaseLink(::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB)
+ , m_pOleNode(pNode)
+ {
+ SetSynchron( false );
+ }
+
+ ::sfx2::SvBaseLink::UpdateResult DataChanged(
+ const OUString&, const uno::Any& )
+ {
+ uno::Reference<embed::XEmbeddedObject> xObject = m_pOleNode->GetOLEObj().GetOleRef();
+ uno::Reference<embed::XCommonEmbedPersist> xPersObj(xObject, uno::UNO_QUERY);
+ if (xPersObj.is())
+ {
+ // let the IFrameObject reload the link
+ try
+ {
+ xPersObj->reload(uno::Sequence<beans::PropertyValue>(), uno::Sequence<beans::PropertyValue>());
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ m_pOleNode->SetChanged();
+ }
+
+ return SUCCESS;
+ }
+
+};
+
+}
+
SwOLENode::SwOLENode( const SwNodeIndex &rWhere,
const svt::EmbeddedObjectRef& xObj,
SwGrfFormatColl *pGrfColl,
@@ -572,22 +612,22 @@ void SwOLENode::BreakFileLink_Impl()
{
SfxObjectShell* pPers = GetDoc()->GetPersist();
- if ( pPers )
+ if ( !pPers )
+ return;
+
+ uno::Reference< embed::XStorage > xStorage = pPers->GetStorage();
+ if ( !xStorage.is() )
+ return;
+
+ try
+ {
+ uno::Reference< embed::XLinkageSupport > xLinkSupport( maOLEObj.GetOleRef(), uno::UNO_QUERY_THROW );
+ xLinkSupport->breakLink( xStorage, maOLEObj.GetCurrentPersistName() );
+ DisconnectFileLink_Impl();
+ maLinkURL.clear();
+ }
+ catch( uno::Exception& )
{
- uno::Reference< embed::XStorage > xStorage = pPers->GetStorage();
- if ( xStorage.is() )
- {
- try
- {
- uno::Reference< embed::XLinkageSupport > xLinkSupport( maOLEObj.GetOleRef(), uno::UNO_QUERY_THROW );
- xLinkSupport->breakLink( xStorage, maOLEObj.GetCurrentPersistName() );
- DisconnectFileLink_Impl();
- maLinkURL.clear();
- }
- catch( uno::Exception& )
- {
- }
- }
}
}
@@ -602,28 +642,59 @@ void SwOLENode::DisconnectFileLink_Impl()
void SwOLENode::CheckFileLink_Impl()
{
- if ( maOLEObj.m_xOLERef.GetObject().is() && !mpObjectLink )
+ if ( !(maOLEObj.m_xOLERef.GetObject().is() && !mpObjectLink) )
+ return;
+
+ try
{
- try
+ uno::Reference<embed::XEmbeddedObject> xObject = maOLEObj.m_xOLERef.GetObject();
+ if (!xObject)
+ return;
+
+ bool bIFrame = false;
+
+ OUString aLinkURL;
+ uno::Reference<embed::XLinkageSupport> xLinkSupport(xObject, uno::UNO_QUERY);
+ if (xLinkSupport)
{
- uno::Reference< embed::XLinkageSupport > xLinkSupport( maOLEObj.m_xOLERef.GetObject(), uno::UNO_QUERY_THROW );
- if ( xLinkSupport->isLink() )
+ if (xLinkSupport->isLink())
+ aLinkURL = xLinkSupport->getLinkURL();
+ }
+ else
+ {
+ // get IFrame (Floating Frames) listed and updatable from the
+ // manage links dialog
+ SvGlobalName aClassId(xObject->getClassID());
+ if (aClassId == SvGlobalName(SO3_IFRAME_CLASSID))
{
- const OUString aLinkURL = xLinkSupport->getLinkURL();
- if ( !aLinkURL.isEmpty() )
- {
- // this is a file link so the model link manager should handle it
- mpObjectLink = new SwEmbedObjectLink( this );
- maLinkURL = aLinkURL;
- GetDoc()->getIDocumentLinksAdministration().GetLinkManager().InsertFileLink( *mpObjectLink, OBJECT_CLIENT_OLE, aLinkURL );
- mpObjectLink->Connect();
- }
+ uno::Reference<beans::XPropertySet> xSet(xObject->getComponent(), uno::UNO_QUERY);
+ if (xSet.is())
+ xSet->getPropertyValue("FrameURL") >>= aLinkURL;
+ bIFrame = true;
}
}
- catch( uno::Exception& )
+
+ if (!aLinkURL.isEmpty()) // this is a file link so the model link manager should handle it
{
+ SwEmbedObjectLink* pEmbedObjectLink = nullptr;
+ if (!bIFrame)
+ {
+ pEmbedObjectLink = new SwEmbedObjectLink(this);
+ mpObjectLink = pEmbedObjectLink;
+ }
+ else
+ {
+ mpObjectLink = new SwIFrameLink(this);
+ }
+ maLinkURL = aLinkURL;
+ GetDoc()->getIDocumentLinksAdministration().GetLinkManager().InsertFileLink( *mpObjectLink, OBJECT_CLIENT_OLE, aLinkURL );
+ if (pEmbedObjectLink)
+ pEmbedObjectLink->Connect();
}
}
+ catch( uno::Exception& )
+ {
+ }
}
// #i99665#
@@ -862,39 +933,39 @@ SwOLEObj::~SwOLEObj() COVERITY_NOEXCEPT_FALSE
void SwOLEObj::SetNode( SwOLENode* pNode )
{
m_pOLENode = pNode;
- if ( m_aName.isEmpty() )
- {
- SwDoc* pDoc = pNode->GetDoc();
-
- // If there's already a SvPersist instance, we use it
- SfxObjectShell* p = pDoc->GetPersist();
- if( !p )
- {
- // TODO/LATER: Isn't an EmbeddedObjectContainer sufficient here?
- // What happens to the document?
- OSL_ENSURE( false, "Why are we creating a DocShell here??" );
- p = new SwDocShell( pDoc, SfxObjectCreateMode::INTERNAL );
- p->DoInitNew();
- }
+ if ( !m_aName.isEmpty() )
+ return;
- OUString aObjName;
- uno::Reference < container::XChild > xChild( m_xOLERef.GetObject(), uno::UNO_QUERY );
- if ( xChild.is() && xChild->getParent() != p->GetModel() )
- // it is possible that the parent was set already
- xChild->setParent( p->GetModel() );
- if (!p->GetEmbeddedObjectContainer().InsertEmbeddedObject( m_xOLERef.GetObject(), aObjName ) )
- {
- OSL_FAIL( "InsertObject failed" );
- if ( xChild.is() )
- xChild->setParent( nullptr );
- }
- else
- m_xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aObjName );
+ SwDoc* pDoc = pNode->GetDoc();
- const_cast<SwOLENode*>(m_pOLENode)->CheckFileLink_Impl(); // for this notification nonconst access is required
+ // If there's already a SvPersist instance, we use it
+ SfxObjectShell* p = pDoc->GetPersist();
+ if( !p )
+ {
+ // TODO/LATER: Isn't an EmbeddedObjectContainer sufficient here?
+ // What happens to the document?
+ OSL_ENSURE( false, "Why are we creating a DocShell here??" );
+ p = new SwDocShell( pDoc, SfxObjectCreateMode::INTERNAL );
+ p->DoInitNew();
+ }
- m_aName = aObjName;
+ OUString aObjName;
+ uno::Reference < container::XChild > xChild( m_xOLERef.GetObject(), uno::UNO_QUERY );
+ if ( xChild.is() && xChild->getParent() != p->GetModel() )
+ // it is possible that the parent was set already
+ xChild->setParent( p->GetModel() );
+ if (!p->GetEmbeddedObjectContainer().InsertEmbeddedObject( m_xOLERef.GetObject(), aObjName ) )
+ {
+ OSL_FAIL( "InsertObject failed" );
+ if ( xChild.is() )
+ xChild->setParent( nullptr );
}
+ else
+ m_xOLERef.AssignToContainer( &p->GetEmbeddedObjectContainer(), aObjName );
+
+ const_cast<SwOLENode*>(m_pOLENode)->CheckFileLink_Impl(); // for this notification nonconst access is required
+
+ m_aName = aObjName;
}
OUString SwOLEObj::GetStyleString()
@@ -1167,7 +1238,7 @@ void SwOLELRUCache::Load()
if (nVal < m_nLRU_InitSize)
{
- std::shared_ptr<SwOLELRUCache> tmp(g_pOLELRU_Cache); // prevent delete this
+ std::shared_ptr<SwOLELRUCache> xKeepAlive(g_pOLELRU_Cache); // prevent delete this
// size of cache has been changed
sal_Int32 nCount = m_OleObjects.size();
sal_Int32 nPos = nCount;
@@ -1197,20 +1268,20 @@ void SwOLELRUCache::InsertObj( SwOLEObj& rObj )
m_OleObjects.erase(it);
it = m_OleObjects.end();
}
- if (it == m_OleObjects.end())
+ if (it != m_OleObjects.end())
+ return;
+
+ std::shared_ptr<SwOLELRUCache> xKeepAlive(g_pOLELRU_Cache); // prevent delete this
+ // try to remove objects if necessary
+ sal_Int32 nCount = m_OleObjects.size();
+ sal_Int32 nPos = nCount-1;
+ while (nPos >= 0 && nCount >= m_nLRU_InitSize)
{
- std::shared_ptr<SwOLELRUCache> tmp(g_pOLELRU_Cache); // prevent delete this
- // try to remove objects if necessary
- sal_Int32 nCount = m_OleObjects.size();
- sal_Int32 nPos = nCount-1;
- while (nPos >= 0 && nCount >= m_nLRU_InitSize)
- {
- pObj = m_OleObjects[ nPos-- ];
- if ( pObj->UnloadObject() )
- nCount--;
- }
- m_OleObjects.push_front(&rObj);
+ pObj = m_OleObjects[ nPos-- ];
+ if ( pObj->UnloadObject() )
+ nCount--;
}
+ m_OleObjects.push_front(&rObj);
}
void SwOLELRUCache::RemoveObj( SwOLEObj& rObj )
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index 69db90b6502d..3720c3117f9b 100755
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -1599,9 +1599,27 @@ void SwTextFrame::Format_( SwTextFormatter &rLine, SwTextFormatInfo &rInf,
// If we're finished formatting the text and we still
// have other line objects left, these are superfluous
// now because the text has gotten shorter.
+ bool bTruncLines = false;
if( rLine.GetStart() + rLine.GetLength() >= nStrLen &&
rLine.GetCurr()->GetNext() )
{
+ bTruncLines = true;
+ }
+ else if (GetMergedPara() && rLine.GetCurr()->GetNext())
+ {
+ // We can also have superfluous lines with redlining in case the current line is shorter
+ // than the text length, but the total length of lines is still more than expected.
+ // Truncate in this case as well.
+ TextFrameIndex nLen(0);
+ for (const SwLineLayout* pLine = pPara; pLine; pLine = pLine->GetNext())
+ {
+ nLen += pLine->GetLen();
+ }
+ bTruncLines = nLen > nStrLen;
+ }
+
+ if (bTruncLines)
+ {
rLine.TruncLines();
rLine.SetTruncLines( true );
}
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 4933bce92c9f..1a60ff2b42d6 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -447,7 +447,7 @@ static void InsertCharAttrs(SfxPoolItem const** pAttrs, SfxItemSet const& rItems
}
else if (nWhich == RES_TXTATR_UNKNOWN_CONTAINER)
{
- pAttrs[RES_CHRATR_END] = pItem;
+ pAttrs[RES_CHRATR_END - RES_CHRATR_BEGIN] = pItem;
}
}
}
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index f3178c2c7233..75cfc1e7e624 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -149,6 +149,16 @@ sal_uInt16 SwTextFormatter::GetFrameRstHeight() const
return sal_uInt16( nHeight );
}
+bool SwTextFormatter::ClearIfIsFirstOfBorderMerge(const SwLinePortion* pPortion)
+{
+ if (pPortion == m_pFirstOfBorderMerge)
+ {
+ m_pFirstOfBorderMerge = nullptr;
+ return true;
+ }
+ return false;
+}
+
SwLinePortion *SwTextFormatter::Underflow( SwTextFormatInfo &rInf )
{
// Save values and initialize rInf
@@ -277,11 +287,8 @@ SwLinePortion *SwTextFormatter::Underflow( SwTextFormatInfo &rInf )
SwLinePortion* pNext = pPor->GetNextPortion();
while (pNext)
{
- if (pNext == m_pFirstOfBorderMerge)
- {
- m_pFirstOfBorderMerge = nullptr;
+ if (ClearIfIsFirstOfBorderMerge(pNext))
break;
- }
pNext = pNext->GetNextPortion();
}
pPor->Truncate();
@@ -2516,7 +2523,11 @@ SwFlyCntPortion *SwTextFormatter::NewFlyCntPortion( SwTextFormatInfo &rInf,
SwFlyInContentFrame *pFly;
SwFrameFormat* pFrameFormat = static_cast<SwTextFlyCnt*>(pHint)->GetFlyCnt().GetFrameFormat();
if( RES_FLYFRMFMT == pFrameFormat->Which() )
+ {
+ // set Lock pFrame to avoid m_pCurr getting deleted
+ TextFrameLockGuard aGuard(m_pFrame);
pFly = static_cast<SwTextFlyCnt*>(pHint)->GetFlyFrame(pFrame);
+ }
else
pFly = nullptr;
// aBase is the document-global position, from which the new extra portion is placed
diff --git a/sw/source/core/text/itrform2.hxx b/sw/source/core/text/itrform2.hxx
index c9a14f566741..ceabbabeb47b 100644
--- a/sw/source/core/text/itrform2.hxx
+++ b/sw/source/core/text/itrform2.hxx
@@ -238,6 +238,8 @@ public:
* @param rInf contain information
**/
void MergeCharacterBorder( SwLinePortion& rPortion, SwLinePortion const *pPrev, SwTextFormatInfo& rInf );
+
+ bool ClearIfIsFirstOfBorderMerge(SwLinePortion const *pPortion);
};
#endif
diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx
index a5eb9b99ce9b..b1c7003764a7 100644
--- a/sw/source/core/text/porfld.cxx
+++ b/sw/source/core/text/porfld.cxx
@@ -175,10 +175,18 @@ SwFieldSlot::SwFieldSlot( const SwTextFormatInfo* pNew, const SwFieldPortion *pP
pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() );
pInf->SetIdx(TextFrameIndex(0));
}
- else if (nIdx < TextFrameIndex(pOldText->getLength()))
+ else
{
- sal_Int32 const nFieldLen(pPor->GetFieldLen());
- aText = (*pOldText).replaceAt(sal_Int32(nIdx), nFieldLen, aText);
+ TextFrameIndex nEnd(pOldText->getLength());
+ if (nIdx < nEnd)
+ {
+ sal_Int32 const nFieldLen(pPor->GetFieldLen());
+ aText = (*pOldText).replaceAt(sal_Int32(nIdx), nFieldLen, aText);
+ }
+ else if (nIdx == nEnd)
+ aText = *pOldText + aText;
+ else
+ SAL_WARN("sw.core", "SwFieldSlot bad SwFieldPortion index.");
}
pInf->SetText( aText );
}
@@ -1063,6 +1071,9 @@ void SwTextFrame::StopAnimation( OutputDevice* pOut )
*/
SwCombinedPortion::SwCombinedPortion( const OUString &rText )
: SwFieldPortion( rText )
+ , aWidth{ static_cast<sal_uInt16>(0),
+ static_cast<sal_uInt16>(0),
+ static_cast<sal_uInt16>(0) }
, nUpPos(0)
, nLowPos(0)
, nProportion(55)
diff --git a/sw/source/core/text/porfld.hxx b/sw/source/core/text/porfld.hxx
index bdb00652bbcc..e3d442509032 100644
--- a/sw/source/core/text/porfld.hxx
+++ b/sw/source/core/text/porfld.hxx
@@ -203,7 +203,7 @@ public:
class SwCombinedPortion : public SwFieldPortion
{
sal_uInt16 aPos[6]; // up to six X positions
- o3tl::enumarray<SwFontScript,sal_uInt16> aWidth = {}; // one width for every scripttype
+ o3tl::enumarray<SwFontScript,sal_uInt16> aWidth; // one width for every scripttype
SwFontScript aScrType[6]; // scripttype of every character
sal_uInt16 nUpPos; // the Y position of the upper baseline
sal_uInt16 nLowPos; // the Y position of the lower baseline
diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
index 2bb9e87bd2c9..5e0f75dada94 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -395,7 +395,9 @@ void SwLineLayout::CalcLine( SwTextFormatter &rLine, SwTextFormatInfo &rInf )
if( !GetAscent() )
SetAscent( pPos->GetAscent() );
}
- delete pLast->Cut( pPos );
+ SwLinePortion* pPortion = pLast->Cut( pPos );
+ rLine.ClearIfIsFirstOfBorderMerge(pPortion);
+ delete pPortion;
pPos = pLast->GetNextPortion();
continue;
}
@@ -2286,29 +2288,9 @@ void SwScriptInfo::selectHiddenTextProperty(const SwTextNode& rNode, MultiSelect
const sw::mark::IMark* pMark = pIndex->GetMark();
const sw::mark::IBookmark* pBookmark = dynamic_cast<const sw::mark::IBookmark*>(pMark);
- bool bHide = false;
+ // condition is evaluated in DocumentFieldsManager::UpdateExpFields()
if (pBookmark && pBookmark->IsHidden())
{
- // bookmark is marked as hidden
- bHide = true;
-
- // bookmark is marked as hidden with conditions
- if (!pBookmark->GetHideCondition().isEmpty())
- {
- SwDoc& rDoc = *const_cast<SwDoc*>(rNode.GetDoc());
- SwCalc aCalc(rDoc);
- rDoc.getIDocumentFieldsAccess().FieldsToCalc(aCalc, rNode.GetIndex(), USHRT_MAX);
-
- SwSbxValue aValue = aCalc.Calculate(pBookmark->GetHideCondition());
- if(!aValue.IsVoidValue())
- {
- bHide = aValue.GetBool();
- }
- }
- }
-
- if (bHide)
- {
// intersect bookmark range with textnode range and add the intersection to rHiddenMulti
const sal_Int32 nSt = pBookmark->GetMarkStart().nContent.GetIndex();
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 17636cda44e3..8d478867709e 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -1292,6 +1292,8 @@ void SwTextFrame::SetMergedPara(std::unique_ptr<sw::MergedPara> p)
pFirst->Add(this); // must register at node again
}
}
+ // postcondition: frame must be listening somewhere
+ assert(m_pMergedPara || GetDep());
}
const OUString& SwTextFrame::GetText() const
@@ -2970,7 +2972,13 @@ bool SwTextFrame::Prepare( const PrepareHint ePrep, const void* pVoid,
if( aTextFly.IsOn() )
{
// Does any free-flying frame overlap?
- bFormat = aTextFly.Relax() || IsUndersized();
+ const bool bRelaxed = aTextFly.Relax();
+ bFormat = bRelaxed || IsUndersized();
+ if (bRelaxed)
+ {
+ // It's possible that pPara was deleted above; retrieve it again
+ pPara = aAccess.GetPara();
+ }
}
}
}
diff --git a/sw/source/core/text/xmldump.cxx b/sw/source/core/text/xmldump.cxx
index 20f61111126a..147ed5a97eb7 100644
--- a/sw/source/core/text/xmldump.cxx
+++ b/sw/source/core/text/xmldump.cxx
@@ -15,6 +15,7 @@
#include <pagefrm.hxx>
#include <txtfrm.hxx>
#include <cellfrm.hxx>
+#include <flyfrm.hxx>
#include <hffrm.hxx>
#include <rootfrm.hxx>
#include <editsh.hxx>
@@ -67,6 +68,7 @@ class XmlPortionDumper:public SwPortionHandler
case PortionType::Meta: return "PortionType::Meta";
case PortionType::FieldMark: return "PortionType::FieldMark";
case PortionType::FieldFormCheckbox: return "PortionType::FieldFormCheckbox";
+ case PortionType::InputField: return "PortionType::InputField";
case PortionType::Expand: return "PortionType::Expand";
case PortionType::Blank: return "PortionType::Blank";
@@ -326,7 +328,7 @@ void SwFrame::dumpAsXml( xmlTextWriterPtr writer ) const
SwView* pView = static_cast<SwView*>(SfxViewShell::GetFirst(true, checkSfxViewShell<SwView>));
while (pView)
{
- if (pView->GetObjectShell() == pRootFrame->GetCurrShell()->GetSfxViewShell()->GetObjectShell())
+ if (pRootFrame->GetCurrShell()->GetSfxViewShell() && pView->GetObjectShell() == pRootFrame->GetCurrShell()->GetSfxViewShell()->GetObjectShell())
pView->dumpAsXml(writer);
pView = static_cast<SwView*>(SfxViewShell::GetNext(*pView, true, checkSfxViewShell<SwView>));
}
@@ -343,6 +345,35 @@ void SwFrame::dumpAsXml( xmlTextWriterPtr writer ) const
xmlTextWriterWriteAttribute(writer, BAD_CAST("ValidLayout"), BAD_CAST(OString::boolean(!pPageFrame->IsInvalidLayout()).getStr()));
xmlTextWriterWriteAttribute(writer, BAD_CAST("ValidContent"), BAD_CAST(OString::boolean(!pPageFrame->IsInvalidContent()).getStr()));
xmlTextWriterEndElement(writer);
+ xmlTextWriterStartElement(writer, BAD_CAST("page_info"));
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("phyNum"), "%d", pPageFrame->GetPhyPageNum());
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("virtNum"), "%d", pPageFrame->GetVirtPageNum());
+ OUString aFormatName = pPageFrame->GetPageDesc()->GetName();
+ xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("pageDesc"), "%s", BAD_CAST(OUStringToOString(aFormatName, RTL_TEXTENCODING_UTF8).getStr()));
+ xmlTextWriterEndElement(writer);
+#ifdef UNX
+ // disable for tests to avoid resolving loads of merge conflicts (var is only set on UNX in this branch)
+ if (!getenv("LO_TESTNAME")) if (auto const* pObjs = pPageFrame->GetSortedObjs())
+ {
+ (void)xmlTextWriterStartElement(writer, BAD_CAST("sorted_objs"));
+ for (SwAnchoredObject const*const pObj : *pObjs)
+ { // just print pointer, full details will be printed on its anchor frame
+ // this nonsense is needed because of multiple inheritance
+ if (SwFlyFrame const*const pFly = dynamic_cast<SwFlyFrame const*>(pObj))
+ {
+ (void)xmlTextWriterStartElement(writer, BAD_CAST("fly"));
+ (void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("ptr"), "%p", pFly);
+ }
+ else
+ {
+ (void)xmlTextWriterStartElement(writer, BAD_CAST(pObj->getElementName()));
+ (void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("ptr"), "%p", pObj);
+ }
+ (void)xmlTextWriterEndElement(writer);
+ }
+ (void)xmlTextWriterEndElement(writer);
+ }
+#endif
}
if (IsTextFrame())
@@ -421,22 +452,16 @@ void SwFrame::dumpInfosAsXml( xmlTextWriterPtr writer ) const
{
// output the Frame
xmlTextWriterStartElement( writer, BAD_CAST( "bounds" ) );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "left" ), "%ld", getFrameArea().Left() );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "top" ), "%ld", getFrameArea().Top() );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "width" ), "%ld", getFrameArea().Width() );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "height" ), "%ld", getFrameArea().Height() );
+ getFrameArea().dumpAsXmlAttributes(writer);
xmlTextWriterWriteAttribute(writer, BAD_CAST("mbFixSize"), BAD_CAST(OString::boolean(HasFixSize()).getStr()));
- xmlTextWriterWriteAttribute(writer, BAD_CAST("mbValidPos"), BAD_CAST(OString::boolean(isFrameAreaPositionValid()).getStr()));
- xmlTextWriterWriteAttribute(writer, BAD_CAST("mbValidSize"), BAD_CAST(OString::boolean(isFrameAreaSizeValid()).getStr()));
- xmlTextWriterWriteAttribute(writer, BAD_CAST("mbValidPrtArea"), BAD_CAST(OString::boolean(isFramePrintAreaValid()).getStr()));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST("mbFrameAreaPositionValid"), BAD_CAST(OString::boolean(isFrameAreaPositionValid()).getStr()));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST("mbFrameAreaSizeValid"), BAD_CAST(OString::boolean(isFrameAreaSizeValid()).getStr()));
+ xmlTextWriterWriteAttribute(writer, BAD_CAST("mbFramePrintAreaValid"), BAD_CAST(OString::boolean(isFramePrintAreaValid()).getStr()));
xmlTextWriterEndElement( writer );
- // output the Prt
+ // output the print area
xmlTextWriterStartElement( writer, BAD_CAST( "prtBounds" ) );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "left" ), "%ld", getFramePrintArea().Left() );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "top" ), "%ld", getFramePrintArea().Top() );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "width" ), "%ld", getFramePrintArea().Width() );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "height" ), "%ld", getFramePrintArea().Height() );
+ getFramePrintArea().dumpAsXmlAttributes(writer);
xmlTextWriterEndElement( writer );
}
@@ -466,6 +491,12 @@ void SwFrame::dumpAsXmlAttributes( xmlTextWriterPtr writer ) const
if (pFF->GetFollow())
xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("follow"), "%" SAL_PRIuUINT32, pFF->GetFollow()->GetFrameId() );
}
+ if (IsSctFrame())
+ {
+ SwSectionFrame const*const pFrame(static_cast<SwSectionFrame const*>(this));
+ SwSectionNode const*const pNode(pFrame->GetSection() ? pFrame->GetSection()->GetFormat()->GetSectionNode() : nullptr);
+ xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("sectionNodeIndex"), TMP_FORMAT, pNode ? pNode->GetIndex() : -1);
+ }
if ( IsTextFrame( ) )
{
const SwTextFrame *pTextFrame = static_cast<const SwTextFrame *>(this);
@@ -515,10 +546,8 @@ void SwAnchoredObject::dumpAsXml( xmlTextWriterPtr writer ) const
xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "ptr" ), "%p", this );
xmlTextWriterStartElement( writer, BAD_CAST( "bounds" ) );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "left" ), "%ld", GetObjBoundRect().Left() );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "top" ), "%ld", GetObjBoundRect().Top() );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "width" ), "%ld", GetObjBoundRect().Width() );
- xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "height" ), "%ld", GetObjBoundRect().Height() );
+ // don't call GetObjBoundRect(), it modifies the layout
+ SwRect(GetDrawObj()->GetLastBoundRect()).dumpAsXmlAttributes(writer);
xmlTextWriterEndElement( writer );
if (const SdrObject* pObject = GetDrawObj())
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index eb77942b6fe7..ce533a220bd9 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -64,6 +64,7 @@
#include <txtfrm.hxx>
#include <ftnfrm.hxx>
#include <ftnboss.hxx>
+#include <pagefrm.hxx>
#include <rootfrm.hxx>
#include <pagedesc.hxx>
#include <expfld.hxx>
@@ -666,9 +667,9 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
// Update the extents with new node; also inits merge flag,
// so the MakeFramesForAdjacentContentNode below respects it
pFrame->RegisterToNode(*pNode);
- if (pFrame->GetText().isEmpty())
+ if (nSplitPos == 0)
{
- // turns out it's empty - in this case, it was not
+ // in this case, it was not
// invalidated because Cut didn't sent it any hints,
// so we have to invalidate it here!
pFrame->Prepare(PREP_CLEAR, nullptr, false);
@@ -894,9 +895,18 @@ void CheckResetRedlineMergeFlag(SwTextNode & rNode, Recreate const eRecreateMerg
assert(rFirstNode.GetIndex() <= rNode.GetIndex());
pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
*pFrame, rFirstNode, eMode));
- assert(pFrame->GetMergedPara());
- assert(pFrame->GetMergedPara()->listener.IsListeningTo(&rNode));
- assert(rNode.GetIndex() <= pFrame->GetMergedPara()->pLastNode->GetIndex());
+ // there is no merged para in case the deleted node had one but
+ // nothing was actually hidden
+ if (pFrame->GetMergedPara())
+ {
+ assert(pFrame->GetMergedPara()->listener.IsListeningTo(&rNode));
+ assert(rNode.GetIndex() <= pFrame->GetMergedPara()->pLastNode->GetIndex());
+ // tdf#135978 Join: recreate fly frames anchored to subsequent nodes
+ if (eRecreateMerged == sw::Recreate::ThisNode)
+ {
+ AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, rNode, nullptr);
+ }
+ }
eMode = sw::FrameMode::New; // Existing is not idempotent!
}
}
@@ -1007,14 +1017,29 @@ SwContentNode *SwTextNode::JoinNext()
pDoc->CorrAbs( aIdx, SwPosition( *this ), nOldLen, true );
}
SwNode::Merge const eOldMergeFlag(pTextNode->GetRedlineMergeFlag());
+ auto eRecreateMerged(eOldMergeFlag == SwNode::Merge::First
+ ? sw::Recreate::ThisNode
+ : sw::Recreate::No);
+ if (eRecreateMerged == sw::Recreate::No)
+ {
+ // tdf#137318 if a delete is inside one node, flag is still None!
+ SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pTextNode);
+ for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
+ {
+ if (pFrame->GetMergedPara())
+ {
+ eRecreateMerged = sw::Recreate::ThisNode;
+ break;
+ }
+ }
+ }
+
rNds.Delete(aIdx);
SetWrong( pList, false );
SetGrammarCheck( pList3, false );
SetSmartTags( pList2, false );
InvalidateNumRule();
- CheckResetRedlineMergeFlag(*this, eOldMergeFlag == SwNode::Merge::First
- ? sw::Recreate::ThisNode
- : sw::Recreate::No);
+ CheckResetRedlineMergeFlag(*this, eRecreateMerged);
}
else {
OSL_FAIL( "No TextNode." );
@@ -1509,10 +1534,21 @@ void SwTextNode::Update(
//Any drawing objects anchored into this text node may be sorted by their
//anchor position which may have changed here, so resort them
- SwContentFrame* pContentFrame = getLayoutFrame(GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout());
- SwSortedObjs* pSortedObjs = pContentFrame ? pContentFrame->GetDrawObjs() : nullptr;
- if (pSortedObjs)
- pSortedObjs->UpdateAll();
+ SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> iter(*this);
+ for (SwTextFrame* pFrame = iter.First(); pFrame; pFrame = iter.Next())
+ {
+ SwSortedObjs * pSortedObjs(pFrame->GetDrawObjs());
+ if (pSortedObjs)
+ {
+ pSortedObjs->UpdateAll();
+ }
+ // also sort the objs on the page frame
+ pSortedObjs = pFrame->FindPageFrame()->GetSortedObjs();
+ if (pSortedObjs) // doesn't exist yet if called for inserting as-char fly
+ {
+ pSortedObjs->UpdateAll();
+ }
+ }
// Update the paragraph signatures.
if (SwEditShell* pEditShell = GetDoc()->GetEditShell())
@@ -1638,7 +1674,7 @@ lcl_GetTextAttrs(
SwTextAttr **const ppTextAttr,
SwpHints const *const pSwpHints,
sal_Int32 const nIndex, sal_uInt16 const nWhich,
- enum SwTextNode::GetTextAttrMode const eMode)
+ ::sw::GetTextAttrMode const eMode)
{
assert(nWhich >= RES_TXTATR_BEGIN && nWhich < RES_TXTATR_END);
if (!pSwpHints)
@@ -1648,9 +1684,12 @@ lcl_GetTextAttrs(
bool (*pMatchFunc)(sal_Int32, sal_Int32, sal_Int32)=nullptr;
switch (eMode)
{
- case SwTextNode::DEFAULT: pMatchFunc = &lcl_GetTextAttrDefault; break;
- case SwTextNode::EXPAND: pMatchFunc = &lcl_GetTextAttrExpand; break;
- case SwTextNode::PARENT: pMatchFunc = &lcl_GetTextAttrParent; break;
+ case ::sw::GetTextAttrMode::Default: pMatchFunc = &lcl_GetTextAttrDefault;
+ break;
+ case ::sw::GetTextAttrMode::Expand: pMatchFunc = &lcl_GetTextAttrExpand;
+ break;
+ case ::sw::GetTextAttrMode::Parent: pMatchFunc = &lcl_GetTextAttrParent;
+ break;
default: assert(false);
}
@@ -1700,13 +1739,13 @@ SwTextNode::GetTextAttrsAt(sal_Int32 const nIndex, sal_uInt16 const nWhich) cons
{
assert(nWhich >= RES_TXTATR_BEGIN && nWhich < RES_TXTATR_END);
std::vector<SwTextAttr *> ret;
- lcl_GetTextAttrs(&ret, nullptr, m_pSwpHints.get(), nIndex, nWhich, DEFAULT);
+ lcl_GetTextAttrs(&ret, nullptr, m_pSwpHints.get(), nIndex, nWhich, ::sw::GetTextAttrMode::Default);
return ret;
}
SwTextAttr *
SwTextNode::GetTextAttrAt(sal_Int32 const nIndex, sal_uInt16 const nWhich,
- enum GetTextAttrMode const eMode) const
+ ::sw::GetTextAttrMode const eMode) const
{
assert( (nWhich == RES_TXTATR_META)
|| (nWhich == RES_TXTATR_METAFIELD)
@@ -1724,11 +1763,11 @@ SwTextNode::GetTextAttrAt(sal_Int32 const nIndex, sal_uInt16 const nWhich,
const SwTextInputField* SwTextNode::GetOverlappingInputField( const SwTextAttr& rTextAttr ) const
{
- const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt( rTextAttr.GetStart(), RES_TXTATR_INPUTFIELD, PARENT ));
+ const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt(rTextAttr.GetStart(), RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent));
if ( pTextInputField == nullptr && rTextAttr.End() != nullptr )
{
- pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt( *(rTextAttr.End()), RES_TXTATR_INPUTFIELD, PARENT ));
+ pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt(*(rTextAttr.End()), RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent));
}
return pTextInputField;
@@ -1751,7 +1790,7 @@ void SwTextNode::DelFrames_TextNodePart()
SwTextField* SwTextNode::GetFieldTextAttrAt(
const sal_Int32 nIndex,
- const bool bIncludeInputFieldAtStart ) const
+ ::sw::GetTextAttrMode const eMode) const
{
SwTextField* pTextField = dynamic_cast<SwTextField*>(GetTextAttrForCharAt( nIndex, RES_TXTATR_FIELD ));
if ( pTextField == nullptr )
@@ -1764,7 +1803,7 @@ SwTextField* SwTextNode::GetFieldTextAttrAt(
dynamic_cast<SwTextField*>( GetTextAttrAt(
nIndex,
RES_TXTATR_INPUTFIELD,
- bIncludeInputFieldAtStart ? DEFAULT : EXPAND ));
+ eMode));
}
return pTextField;
@@ -2492,7 +2531,15 @@ void SwTextNode::CutImpl( SwTextNode * const pDest, const SwIndex & rDestStart,
}
else
{
- GetpSwAttrSet()->CopyToModify( *pDest );
+ // Copy all attrs except RES_PARATR_LIST_LEVEL: it was initialized before
+ // and current SwTextNode can contain not suitable for pDest value
+ SfxItemSet aCharSet(
+ pDest->GetDoc()->GetAttrPool(),
+ svl::Items<RES_CHRATR_BEGIN, RES_PARATR_LIST_LEVEL - 1,
+ RES_PARATR_LIST_LEVEL + 1, HINT_END>{});
+ aCharSet.Put(*GetpSwAttrSet());
+ if (aCharSet.Count())
+ pDest->SetAttr(aCharSet, nDestStart, nDestStart + nLen);
}
}
@@ -3072,11 +3119,11 @@ sal_uInt16 lcl_BoundListLevel(const int nActualLevel)
}
// -> #i29560#
-bool SwTextNode::HasNumber() const
+bool SwTextNode::HasNumber(SwRootFrame const*const pLayout) const
{
bool bResult = false;
- const SwNumRule* pRule = GetNum() ? GetNum()->GetNumRule() : nullptr;
+ const SwNumRule *const pRule = GetNum(pLayout) ? GetNum(pLayout)->GetNumRule() : nullptr;
if ( pRule )
{
const SwNumFormat& aFormat(pRule->Get(lcl_BoundListLevel(GetActualListLevel())));
diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx
index 5b363f2d9119..ba2889236f52 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -1180,6 +1180,12 @@ void SwTextNode::DestroyAttr( SwTextAttr* pAttr )
SwTextField *const pTextField(static_txtattr_cast<SwTextField*>(pAttr));
SwFieldType* pFieldType = pAttr->GetFormatField().GetField()->GetTyp();
+ if (SwFieldIds::Dde != pFieldType->Which()
+ && !pTextField->GetpTextNode())
+ {
+ break; // was not yet inserted
+ }
+
//JP 06-08-95: DDE-fields are an exception
assert(SwFieldIds::Dde == pFieldType->Which() ||
this == pTextField->GetpTextNode());
@@ -1599,6 +1605,7 @@ bool SwTextNode::InsertHint( SwTextAttr * const pAttr, const SetAttrMode nMode )
if ( pAttr->End() == nullptr )
{
bInsertHint = false;
+ DestroyAttr(pAttr);
}
else
{
@@ -2971,6 +2978,7 @@ bool SwpHints::TryInsertHint(
if ( MAX_HINTS <= Count() ) // we're sorry, this flight is overbooked...
{
OSL_FAIL("hints array full :-(");
+ rNode.DestroyAttr(pHint);
return false;
}
diff --git a/sw/source/core/txtnode/txatbase.cxx b/sw/source/core/txtnode/txatbase.cxx
index 188ec6f9a663..755391e940d7 100644
--- a/sw/source/core/txtnode/txatbase.cxx
+++ b/sw/source/core/txtnode/txatbase.cxx
@@ -152,9 +152,11 @@ void SwTextAttr::dumpAsXml(xmlTextWriterPtr pWriter) const
GetAutoFormat().dumpAsXml(pWriter);
break;
case RES_TXTATR_FIELD:
+ case RES_TXTATR_INPUTFIELD:
GetFormatField().dumpAsXml(pWriter);
break;
default:
+ SAL_WARN("sw.core", "Unhandled TXTATR");
break;
}
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index 5c599d78afab..73cb47930eac 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -375,10 +375,10 @@ void SwTextNode::RstTextAttr(
sal_Int32 nEnd = nStt + nLen;
{
// enlarge range for the reset of text attributes in case of an overlapping input field
- const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt( nStt, RES_TXTATR_INPUTFIELD, PARENT ));
+ const SwTextInputField* pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt(nStt, RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent));
if ( pTextInputField == nullptr )
{
- pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt(nEnd, RES_TXTATR_INPUTFIELD, PARENT ));
+ pTextInputField = dynamic_cast<const SwTextInputField*>(GetTextAttrAt(nEnd, RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent));
}
if ( pTextInputField != nullptr )
{
diff --git a/sw/source/core/undo/unbkmk.cxx b/sw/source/core/undo/unbkmk.cxx
index 6cc805d1518d..e9d41a7bcd3e 100644
--- a/sw/source/core/undo/unbkmk.cxx
+++ b/sw/source/core/undo/unbkmk.cxx
@@ -56,7 +56,7 @@ void SwUndoBookmark::ResetInDoc( SwDoc* pDoc )
{
if ( m_pHistoryBookmark->IsEqualBookmark( **ppBkmk ) )
{
- pMarkAccess->deleteMark( ppBkmk );
+ pMarkAccess->deleteMark(ppBkmk, false);
break;
}
}
diff --git a/sw/source/core/undo/undel.cxx b/sw/source/core/undo/undel.cxx
index 4e55a46196b4..cb819d5216c8 100644
--- a/sw/source/core/undo/undel.cxx
+++ b/sw/source/core/undo/undel.cxx
@@ -172,6 +172,7 @@ static void DelFullParaMoveFrames(SwDoc & rDoc, SwUndRng const& rRange,
// move the paragraph into this section and to record this in nSectDiff.
SwUndoDelete::SwUndoDelete(
SwPaM& rPam,
+ SwDeleteFlags const flags,
bool bFullPara,
bool bCalledByTableCpy )
: SwUndo(SwUndoId::DELETE, rPam.GetDoc()),
@@ -190,7 +191,9 @@ SwUndoDelete::SwUndoDelete(
m_bResetPgDesc( false ),
m_bResetPgBrk( false ),
m_bFromTableCopy( bCalledByTableCpy )
+ , m_DeleteFlags(flags)
{
+ assert(!m_bDelFullPara || !(m_DeleteFlags & SwDeleteFlags::ArtificialSelection));
m_bCacheComment = false;
@@ -226,7 +229,9 @@ SwUndoDelete::SwUndoDelete(
}
else
{
- DelContentIndex( *rPam.GetMark(), *rPam.GetPoint() );
+ DelContentIndex(*rPam.GetMark(), *rPam.GetPoint(),
+ DelContentType::AllMask
+ | ((m_DeleteFlags & SwDeleteFlags::ArtificialSelection) ? DelContentType::Replace : DelContentType(0)));
::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
if (m_nEndNode - m_nSttNode > 1) // check for fully selected nodes
{
@@ -1135,7 +1140,10 @@ void SwUndoDelete::UndoImpl(::sw::UndoRedoContext & rContext)
// don't include end node in the range: it may have been merged already
// by the start node, or it may be merged by one of the moved nodes,
// but if it isn't merged, its current frame(s) should be good...
- SwNodeIndex const end(rDoc.GetNodes(), m_bDelFullPara ? delFullParaEndNode : m_nEndNode);
+ SwNodeIndex const end(rDoc.GetNodes(), m_bDelFullPara
+ ? delFullParaEndNode
+ // tdf#147310 SwDoc::DeleteRowCol() may delete whole table - end must be node following table!
+ : (m_nEndNode + (rDoc.GetNodes()[m_nSttNode]->IsTableNode() && rDoc.GetNodes()[m_nEndNode]->IsEndNode() ? 1 : 0)));
::MakeFrames(&rDoc, start, end);
}
@@ -1197,7 +1205,11 @@ void SwUndoDelete::RedoImpl(::sw::UndoRedoContext & rContext)
DelBookmarks(rPam.GetMark()->nNode, rPam.GetPoint()->nNode);
}
else
- DelContentIndex( *rPam.GetMark(), *rPam.GetPoint() );
+ {
+ DelContentIndex(*rPam.GetMark(), *rPam.GetPoint(),
+ DelContentType::AllMask
+ | ((m_DeleteFlags & SwDeleteFlags::ArtificialSelection) ? DelContentType::Replace : DelContentType(0)));
+ }
m_nSetPos = m_pHistory ? m_pHistory->Count() : 0;
m_pHistory->Move( m_nSetPos, &aHstr );
@@ -1213,7 +1225,11 @@ void SwUndoDelete::RedoImpl(::sw::UndoRedoContext & rContext)
DelBookmarks( rPam.GetMark()->nNode, rPam.GetPoint()->nNode );
}
else
- DelContentIndex( *rPam.GetMark(), *rPam.GetPoint() );
+ {
+ DelContentIndex(*rPam.GetMark(), *rPam.GetPoint(),
+ DelContentType::AllMask
+ | ((m_DeleteFlags & SwDeleteFlags::ArtificialSelection) ? DelContentType::Replace : DelContentType(0)));
+ }
m_nSetPos = m_pHistory ? m_pHistory->Count() : 0;
}
@@ -1288,7 +1304,7 @@ void SwUndoDelete::RedoImpl(::sw::UndoRedoContext & rContext)
rDoc.getIDocumentContentOperations().DelFullPara( rPam );
}
else
- rDoc.getIDocumentContentOperations().DeleteAndJoin( rPam );
+ rDoc.getIDocumentContentOperations().DeleteAndJoin(rPam, m_DeleteFlags);
}
void SwUndoDelete::RepeatImpl(::sw::RepeatContext & rContext)
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index fa86072a3008..d611cb4a496b 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -981,10 +981,14 @@ void SwUndoSaveContent::DelContentIndex( const SwPosition& rMark,
// Moving the anchor?
else if (!((DelContentType::CheckNoCntnt|DelContentType::ExcludeFlyAtStartEnd)
& nDelContentType) &&
- // at least for calls from SwUndoDelete,
- // this should work - other Undos don't
- // remember the order of the cursor
- (rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex())
+ // for SwUndoDelete: rPoint is the node that
+ // will be Joined - so anchor should be moved
+ // off it - but UndoImpl() split will insert
+ // new node *before* existing one so a no-op
+ // may need to be done here to add it to
+ // history for Undo.
+ (rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex()
+ || pStt->nNode.GetIndex() == pAPos->nNode.GetIndex())
// Do not try to move the anchor to a table!
&& rMark.nNode.GetNode().IsTextNode())
{
@@ -1168,7 +1172,7 @@ void SwUndoSaveContent::DelContentIndex( const SwPosition& rMark,
&& ( bSaveOtherPos
|| !pBkmk->IsExpanded() ) )
{
- pMarkAccess->deleteMark(pMarkAccess->getAllMarksBegin()+n);
+ pMarkAccess->deleteMark(pMarkAccess->getAllMarksBegin()+n, false);
n--;
}
}
@@ -1558,9 +1562,14 @@ static bool IsNotBackspaceHeuristic(
SwPosition const& rStart, SwPosition const& rEnd)
{
// check if the selection is backspace/delete created by DelLeft/DelRight
- return rStart.nNode.GetIndex() + 1 != rEnd.nNode.GetIndex()
- || rEnd.nContent != 0
- || rStart.nContent != rStart.nNode.GetNode().GetTextNode()->Len();
+ if (rStart.nNode.GetIndex() + 1 != rEnd.nNode.GetIndex())
+ return true;
+ if (rEnd.nContent != 0)
+ return true;
+ const SwTextNode* pTextNode = rStart.nNode.GetNode().GetTextNode();
+ if (!pTextNode || rStart.nContent != pTextNode->Len())
+ return true;
+ return false;
}
bool IsDestroyFrameAnchoredAtChar(SwPosition const & rAnchorPos,
diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx
index 85b20fae911b..f1f7f48188aa 100644
--- a/sw/source/core/undo/unins.cxx
+++ b/sw/source/core/undo/unins.cxx
@@ -689,7 +689,8 @@ void SwUndoReplace::Impl::UndoImpl(::sw::UndoRedoContext & rContext)
if( m_bSplitNext )
{
- SwPosition aPos(*pNd, pNd->Len());
+ assert(m_nSttCnt + m_sOld.getLength() <= pNd->Len());
+ SwPosition aPos(*pNd, m_nSttCnt + m_sOld.getLength());
pDoc->getIDocumentContentOperations().SplitNode( aPos, false );
pNd->RestoreMetadata(m_pMetadataUndoEnd);
pNd = pDoc->GetNodes()[ m_nSttNd - m_nOffset ]->GetTextNode();
@@ -723,7 +724,7 @@ void SwUndoReplace::Impl::UndoImpl(::sw::UndoRedoContext & rContext)
}
rPam.GetPoint()->nNode = m_nSttNd;
- rPam.GetPoint()->nContent = m_nSttCnt;
+ rPam.GetPoint()->nContent.Assign(rPam.GetPoint()->nNode.GetNode().GetTextNode(), m_nSttCnt);
}
void SwUndoReplace::Impl::RedoImpl(::sw::UndoRedoContext & rContext)
@@ -917,7 +918,7 @@ void SwUndoInsertLabel::UndoImpl(::sw::UndoRedoContext & rContext)
aPam.GetPoint()->nNode = NODE.nNode;
aPam.SetMark();
aPam.GetPoint()->nNode = NODE.nNode + 1;
- NODE.pUndoInsNd = new SwUndoDelete( aPam, true );
+ NODE.pUndoInsNd = new SwUndoDelete(aPam, SwDeleteFlags::Default, true);
}
}
diff --git a/sw/source/core/undo/unredln.cxx b/sw/source/core/undo/unredln.cxx
index 8aae3c055b63..c66d8eed133e 100644
--- a/sw/source/core/undo/unredln.cxx
+++ b/sw/source/core/undo/unredln.cxx
@@ -26,6 +26,8 @@
#include <pam.hxx>
#include <ndtxt.hxx>
#include <txtfrm.hxx>
+#include <mvsave.hxx>
+#include <rolbck.hxx>
#include <UndoCore.hxx>
#include <UndoDelete.hxx>
#include <strings.hrc>
@@ -153,7 +155,8 @@ void SwUndoRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
rDoc.getIDocumentRedlineAccess().DeleteRedline(rPam, true, RedlineType::Any);
}
-SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUsrId )
+SwUndoRedlineDelete::SwUndoRedlineDelete(
+ const SwPaM& rRange, SwUndoId const nUsrId, SwDeleteFlags const flags)
: SwUndoRedline( nUsrId != SwUndoId::EMPTY ? nUsrId : SwUndoId::DELETE, rRange ),
bCanGroup( false ), bIsDelim( false ), bIsBackspace( false )
{
@@ -174,6 +177,24 @@ SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUsrId )
}
m_bCacheComment = false;
+ if (flags & SwDeleteFlags::ArtificialSelection)
+ {
+ InitHistory(rRange);
+ }
+}
+
+void SwUndoRedlineDelete::InitHistory(SwPaM const& rRedline)
+{
+ m_pHistory.reset(new SwHistory);
+ // try to rely on direction of rPam here so it works for
+ // backspacing/deleting consecutive characters
+ SaveFlyArr flys;
+ SaveFlyInRange(rRedline, *rRedline.GetMark(), flys, false, m_pHistory.get());
+ RestFlyInRange(flys, *rRedline.GetPoint(), &rRedline.GetPoint()->nNode, true);
+ if (m_pHistory->Count())
+ {
+ bCanGroup = false; // how to group history?
+ }
}
// bit of a hack, replace everything...
@@ -197,12 +218,21 @@ void SwUndoRedlineDelete::SetRedlineText(const OUString & rText)
void SwUndoRedlineDelete::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
{
rDoc.getIDocumentRedlineAccess().DeleteRedline(rPam, true, RedlineType::Any);
+ if (m_pHistory)
+ {
+ m_pHistory->TmpRollback(&rDoc, 0);
+ }
}
void SwUndoRedlineDelete::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
{
if (rPam.GetPoint() != rPam.GetMark())
{
+ if (m_pHistory) // if it was created before, it must be recreated now
+ {
+ rPam.Normalize(bIsBackspace); // to check the correct edge
+ InitHistory(rPam);
+ }
rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline(*mpRedlData, rPam), false );
}
sw::UpdateFramesForAddDeleteRedline(rDoc, rPam);
@@ -212,7 +242,7 @@ bool SwUndoRedlineDelete::CanGrouping( const SwUndoRedlineDelete& rNext )
{
bool bRet = false;
if( SwUndoId::DELETE == mnUserId && mnUserId == rNext.mnUserId &&
- bCanGroup == rNext.bCanGroup &&
+ bCanGroup && rNext.bCanGroup &&
bIsDelim == rNext.bIsDelim &&
bIsBackspace == rNext.bIsBackspace &&
m_nSttNode == m_nEndNode &&
@@ -449,7 +479,7 @@ void SwUndoCompDoc::UndoImpl(::sw::UndoRedoContext & rContext)
bool bJoinText, bJoinPrev;
sw_GetJoinFlags(rPam, bJoinText, bJoinPrev);
- pUnDel.reset( new SwUndoDelete(rPam, false) );
+ pUnDel.reset( new SwUndoDelete(rPam, SwDeleteFlags::Default, false) );
if( bJoinText )
sw_JoinText(rPam, bJoinPrev);
@@ -466,7 +496,7 @@ void SwUndoCompDoc::UndoImpl(::sw::UndoRedoContext & rContext)
++rPam.GetPoint()->nNode;
rPam.GetBound().nContent.Assign( nullptr, 0 );
rPam.GetBound( false ).nContent.Assign( nullptr, 0 );
- pUnDel2.reset( new SwUndoDelete(rPam, true) );
+ pUnDel2.reset( new SwUndoDelete(rPam, SwDeleteFlags::Default, true) );
}
}
rPam.DeleteMark();
diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx
index 9d1675c0f304..c7dbc781225b 100644
--- a/sw/source/core/undo/untbl.cxx
+++ b/sw/source/core/undo/untbl.cxx
@@ -2420,11 +2420,11 @@ void SwUndoTableCpyTable::UndoImpl(::sw::UndoRedoContext & rContext)
else
*aPam.GetPoint() = SwPosition( aTmpIdx );
}
- pUndo = std::make_unique<SwUndoDelete>( aPam, bDeleteCompleteParagraph, true );
+ pUndo = std::make_unique<SwUndoDelete>(aPam, SwDeleteFlags::Default, bDeleteCompleteParagraph, true);
}
else
{
- pUndo = std::make_unique<SwUndoDelete>( aPam, true );
+ pUndo = std::make_unique<SwUndoDelete>(aPam, SwDeleteFlags::Default, true);
if( pEntry->pUndo )
{
pEntry->pUndo->UndoImpl(rContext);
@@ -2501,7 +2501,9 @@ void SwUndoTableCpyTable::RedoImpl(::sw::UndoRedoContext & rContext)
// b62341295: Redline for copying tables - Start.
rDoc.GetNodes().MakeTextNode( aInsIdx, rDoc.GetDfltTextFormatColl() );
SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode());
- std::unique_ptr<SwUndo> pUndo = IDocumentRedlineAccess::IsRedlineOn( GetRedlineFlags() ) ? nullptr : std::make_unique<SwUndoDelete>( aPam, true );
+ std::unique_ptr<SwUndo> pUndo(IDocumentRedlineAccess::IsRedlineOn(GetRedlineFlags())
+ ? nullptr
+ : std::make_unique<SwUndoDelete>(aPam, SwDeleteFlags::Default, true));
if( pEntry->pUndo )
{
pEntry->pUndo->UndoImpl(rContext);
@@ -2582,7 +2584,7 @@ void SwUndoTableCpyTable::AddBoxBefore( const SwTableBox& rBox, bool bDelContent
SwPaM aPam( aInsIdx.GetNode(), *rBox.GetSttNd()->EndOfSectionNode() );
if( !pDoc->getIDocumentRedlineAccess().IsRedlineOn() )
- pEntry->pUndo = std::make_unique<SwUndoDelete>( aPam, true );
+ pEntry->pUndo = std::make_unique<SwUndoDelete>(aPam, SwDeleteFlags::Default, true);
}
pEntry->pBoxNumAttr = std::make_unique<SfxItemSet>(
@@ -2682,7 +2684,7 @@ std::unique_ptr<SwUndo> SwUndoTableCpyTable::PrepareRedline( SwDoc* pDoc, const
aCellEnd = SwPosition(
SwNodeIndex( *rBox.GetSttNd()->EndOfSectionNode() ));
SwPaM aTmpPam( aDeleteStart, aCellEnd );
- pUndo = std::make_unique<SwUndoDelete>( aTmpPam, true );
+ pUndo = std::make_unique<SwUndoDelete>(aTmpPam, SwDeleteFlags::Default, true);
}
SwPosition aCellStart( SwNodeIndex( *rBox.GetSttNd(), 2 ) );
pText = aCellStart.nNode.GetNode().GetTextNode();
@@ -2754,7 +2756,7 @@ void SwUndoCpyTable::UndoImpl(::sw::UndoRedoContext & rContext)
}
SwPaM aPam( *pTNd, *pTNd->EndOfSectionNode(), 0 , 1 );
- pDel.reset( new SwUndoDelete( aPam, true ) );
+ pDel.reset( new SwUndoDelete( aPam, SwDeleteFlags::Default, true ) );
}
void SwUndoCpyTable::RedoImpl(::sw::UndoRedoContext & rContext)
diff --git a/sw/source/core/unocore/unobkm.cxx b/sw/source/core/unocore/unobkm.cxx
index ddeaccf1966b..a4d719016f68 100644
--- a/sw/source/core/unocore/unobkm.cxx
+++ b/sw/source/core/unocore/unobkm.cxx
@@ -410,6 +410,8 @@ void SAL_CALL
SwXBookmark::setPropertyValue(const OUString& PropertyName,
const uno::Any& rValue)
{
+ SolarMutexGuard g;
+
if (PropertyName == UNO_NAME_BOOKMARK_HIDDEN)
{
bool bNewValue = false;
diff --git a/sw/source/core/unocore/unochart.cxx b/sw/source/core/unocore/unochart.cxx
index 38241c451a67..bb43665ec6a2 100644
--- a/sw/source/core/unocore/unochart.cxx
+++ b/sw/source/core/unocore/unochart.cxx
@@ -1427,7 +1427,7 @@ void SwChartDataProvider::RemoveDataSequence( const SwTable &rTable, uno::Refere
aDataSequences[ &rTable ].erase( rxDataSequence );
}
-void SwChartDataProvider::InvalidateTable( const SwTable *pTable )
+void SwChartDataProvider::InvalidateTable( const SwTable *pTable, bool bImmediate )
{
OSL_ENSURE( pTable, "table pointer is NULL" );
if (pTable)
@@ -1447,6 +1447,10 @@ void SwChartDataProvider::InvalidateTable( const SwTable *pTable )
}
}
}
+
+ // tdf#122995 added Immediate-mode to allow non-timer-delayed Chart invalidation
+ if (bImmediate && !bDisposed)
+ pTable->GetFrameFormat()->GetDoc()->getIDocumentChartDataProviderAccess().GetChartControllerHelper().Disconnect();
}
void SwChartDataProvider::DeleteBox( const SwTable *pTable, const SwTableBox &rBox )
diff --git a/sw/source/core/unocore/unocrsrhelper.cxx b/sw/source/core/unocore/unocrsrhelper.cxx
index d7634e2a2713..9d0710cf3384 100644
--- a/sw/source/core/unocore/unocrsrhelper.cxx
+++ b/sw/source/core/unocore/unocrsrhelper.cxx
@@ -283,8 +283,8 @@ GetNestedTextContent(SwTextNode const & rTextNode, sal_Int32 const nIndex,
bool const bParent)
{
// these should be unambiguous because of the dummy character
- SwTextNode::GetTextAttrMode const eMode( bParent
- ? SwTextNode::PARENT : SwTextNode::EXPAND );
+ auto const eMode( bParent
+ ? ::sw::GetTextAttrMode::Parent : ::sw::GetTextAttrMode::Expand );
SwTextAttr *const pMetaTextAttr =
rTextNode.GetTextAttrAt(nIndex, RES_TXTATR_META, eMode);
SwTextAttr *const pMetaFieldTextAttr =
@@ -582,7 +582,7 @@ bool getCursorPropertyValue(const SfxItemPropertySimpleEntry& rEntry
const SwTextNode *pTextNd =
rPam.GetDoc()->GetNodes()[pPos->nNode.GetIndex()]->GetTextNode();
const SwTextAttr* pTextAttr = pTextNd
- ? pTextNd->GetFieldTextAttrAt( pPos->nContent.GetIndex(), true )
+ ? pTextNd->GetFieldTextAttrAt(pPos->nContent.GetIndex(), ::sw::GetTextAttrMode::Default)
: nullptr;
if ( pTextAttr != nullptr )
{
diff --git a/sw/source/core/unocore/unodraw.cxx b/sw/source/core/unocore/unodraw.cxx
index fed0e4a55d6a..1d7cc5fea594 100644
--- a/sw/source/core/unocore/unodraw.cxx
+++ b/sw/source/core/unocore/unodraw.cxx
@@ -1147,6 +1147,8 @@ void SwXShape::setPropertyValue(const OUString& rPropertyName, const uno::Any& a
SwFormatFlyCnt aFormat( pFormat );
pNd->InsertItem(aFormat, pInternalPam->GetPoint()
->nContent.GetIndex(), 0 );
+ //Refetch in case SwTextNode::InsertItem causes it to be deleted
+ pFormat = GetFrameFormat();
}
else
{
diff --git a/sw/source/core/unocore/unofield.cxx b/sw/source/core/unocore/unofield.cxx
index b5b7f4e1a88e..d5061ea58658 100644
--- a/sw/source/core/unocore/unofield.cxx
+++ b/sw/source/core/unocore/unofield.cxx
@@ -1327,7 +1327,7 @@ void SwXTextField::TransmuteLeadToInputField(SwSetExpField & rField)
bool bSuccess = rIDCO.InsertPoolItem(*pPamForTextField, tempFormat);
assert(bSuccess);
(void) bSuccess;
- SwTextField const* pNewAttr(rNode.GetFieldTextAttrAt(nStart, true));
+ SwTextField const* pNewAttr(rNode.GetFieldTextAttrAt(nStart, ::sw::GetTextAttrMode::Default));
assert(pNewAttr);
SwFormatField const& rNewFormat(pNewAttr->GetFormatField());
assert(rNewFormat.Which() == (static_cast<SwSetExpField const*>(rNewFormat.GetField())->GetInputFlag() ? RES_TXTATR_INPUTFIELD : RES_TXTATR_FIELD));
@@ -2011,7 +2011,7 @@ void SAL_CALL SwXTextField::attach(
else
pDoc->getIDocumentContentOperations().InsertPoolItem(aPam, aFormat, nInsertFlags);
- SwTextAttr* pTextAttr = aPam.GetNode().GetTextNode()->GetFieldTextAttrAt( aPam.GetPoint()->nContent.GetIndex()-1, true );
+ SwTextAttr* pTextAttr = aPam.GetNode().GetTextNode()->GetFieldTextAttrAt(aPam.GetPoint()->nContent.GetIndex()-1, ::sw::GetTextAttrMode::Default);
// What about updating the fields? (see fldmgr.cxx)
if (!pTextAttr)
@@ -2075,7 +2075,7 @@ void SAL_CALL SwXTextField::attach(
}
// keep inserted annotation
{
- SwTextField* pTextAttr = aEnd.GetNode().GetTextNode()->GetFieldTextAttrAt( aEnd.End()->nContent.GetIndex()-1, true );
+ SwTextField *const pTextAttr = aEnd.GetNode().GetTextNode()->GetFieldTextAttrAt(aEnd.End()->nContent.GetIndex()-1, ::sw::GetTextAttrMode::Default);
if ( pTextAttr != nullptr )
{
m_pImpl->SetFormatField(const_cast<SwFormatField*>(&pTextAttr->GetFormatField()), m_pImpl->m_pDoc);
diff --git a/sw/source/core/unocore/unoframe.cxx b/sw/source/core/unocore/unoframe.cxx
index e2e5c9411715..e5ced2a27fd0 100644
--- a/sw/source/core/unocore/unoframe.cxx
+++ b/sw/source/core/unocore/unoframe.cxx
@@ -2771,8 +2771,13 @@ void SwXFrame::attachToRange(uno::Reference<text::XTextRange> const& xTextRange,
aFrameSet.Put( SwFormatAnchor( RndStdIds::FLY_AT_PAGE, 1 ));
}
- aPam.DeleteMark(); // mark position node will be deleted!
- aIntPam.DeleteMark(); // mark position node will be deleted!
+ // park these no longer needed PaMs somewhere safe so MakeFlyAndMove
+ // can delete what it likes without any assert these are pointing to
+ // that content
+ aPam.DeleteMark();
+ aIntPam.DeleteMark();
+ *aPam.GetPoint() = *aIntPam.GetPoint() = SwPosition(pDoc->GetNodes());
+
pFormat = pDoc->MakeFlyAndMove( *pCopySource, aFrameSet,
nullptr,
pParentFrameFormat );
diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx
index 05695e8585b2..63fbd6e78c13 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -952,6 +952,7 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s
{OUString(UNO_NAME_HINT), FIELD_PROP_PAR2, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0},
{OUString(UNO_NAME_HELP), FIELD_PROP_PAR3, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0},
{OUString(UNO_NAME_TOOLTIP), FIELD_PROP_PAR4, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0},
+ {OUString(UNO_NAME_MISC_OBJ_INTEROPGRABBAG), FIELD_PROP_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0},
COMMON_FLDTYP_PROPERTIES
{ OUString(), 0, css::uno::Type(), 0, 0 }
};
diff --git a/sw/source/core/unocore/unosett.cxx b/sw/source/core/unocore/unosett.cxx
index 1f68135f7a4a..6d1752881418 100644
--- a/sw/source/core/unocore/unosett.cxx
+++ b/sw/source/core/unocore/unosett.cxx
@@ -1148,6 +1148,7 @@ void SwXNumberingRules::replaceByIndex(sal_Int32 nIndex, const uno::Any& rElemen
SwXNumberingRules::SetNumberingRuleByIndex( aNumRule,
*rProperties, nIndex);
// set character format if needed
+ // this code appears to be dead - except when a style is assigned for BITMAP numbering?
const SwCharFormats* pFormats = m_pDocShell->GetDoc()->GetCharFormats();
const size_t nChCount = pFormats->size();
for(sal_uInt16 i = 0; i < MAXLEVEL;i++)
@@ -1492,7 +1493,7 @@ void SwXNumberingRules::SetNumberingRuleByIndex(
SetPropertiesToNumFormat(aFormat, m_sNewCharStyleNames[nIndex],
&m_sNewBulletFontNames[nIndex],
&sHeadingStyleName, &sParagraphStyleName,
- m_pDoc, rProperties);
+ m_pDoc, m_pDocShell, rProperties);
if (m_pDoc && !sParagraphStyleName.isEmpty())
@@ -1539,8 +1540,11 @@ void SwXNumberingRules::SetPropertiesToNumFormat(
OUString *const pHeadingStyleName,
OUString *const pParagraphStyleName,
SwDoc *const pDoc,
+ SwDocShell *const pDocShell,
const uno::Sequence<beans::PropertyValue>& rProperties)
{
+ assert(pDoc == nullptr || pDocShell == nullptr); // can't be both ordinary and chapter numbering
+
bool bWrongArg = false;
std::unique_ptr<SvxBrushItem> pSetBrush;
std::unique_ptr<Size> pSetSize;
@@ -1588,14 +1592,15 @@ void SwXNumberingRules::SetPropertiesToNumFormat(
rProp.Value >>= uTmp;
OUString sCharFormatName;
SwStyleNameMapper::FillUIName( uTmp, sCharFormatName, SwGetPoolIdFromName::ChrFmt );
+ SwDoc *const pLocalDoc = pDocShell ? pDocShell->GetDoc() : pDoc;
if (sCharFormatName == UNO_NAME_CHARACTER_FORMAT_NONE)
{
rCharStyleName = aInvalidStyle;
aFormat.SetCharFormat(nullptr);
}
- else if(pDoc)
+ else if (pLocalDoc)
{
- const SwCharFormats* pFormats = pDoc->GetCharFormats();
+ const SwCharFormats* pFormats = pLocalDoc->GetCharFormats();
const size_t nChCount = pFormats->size();
SwCharFormat* pCharFormat = nullptr;
@@ -1614,7 +1619,7 @@ void SwXNumberingRules::SetPropertiesToNumFormat(
{
SfxStyleSheetBase* pBase;
- SfxStyleSheetBasePool* pPool = pDoc->GetDocShell()->GetStyleSheetPool();
+ SfxStyleSheetBasePool* pPool = pLocalDoc->GetDocShell()->GetStyleSheetPool();
pBase = pPool->Find(sCharFormatName, SfxStyleFamily::Char);
if(!pBase)
pBase = &pPool->Make(sCharFormatName, SfxStyleFamily::Char);
@@ -1626,7 +1631,7 @@ void SwXNumberingRules::SetPropertiesToNumFormat(
// If the character format has been found its name should not be in the
// char style names array
rCharStyleName.clear();
- }
+ }
else
rCharStyleName = sCharFormatName;
}
@@ -1779,7 +1784,7 @@ void SwXNumberingRules::SetPropertiesToNumFormat(
{
OUString sBulletFontName;
rProp.Value >>= sBulletFontName;
- SwDocShell* pLclDocShell = pDoc->GetDocShell();
+ SwDocShell *const pLclDocShell = pDocShell ? pDocShell : pDoc ? pDoc->GetDocShell() : nullptr;
if( !sBulletFontName.isEmpty() && pLclDocShell )
{
const SvxFontListItem* pFontListItem =
@@ -1878,7 +1883,8 @@ void SwXNumberingRules::SetPropertiesToNumFormat(
}
pSetVOrient->PutValue(rProp.Value, MID_VERTORIENT_ORIENT);
}
- else if (rProp.Name == UNO_NAME_HEADING_STYLE_NAME)
+ else if (rProp.Name == UNO_NAME_HEADING_STYLE_NAME
+ && pDocShell) // only on chapter numbering
{
if (pHeadingStyleName)
{
diff --git a/sw/source/core/unocore/unotext.cxx b/sw/source/core/unocore/unotext.cxx
index 3887a11191d7..a4dfe5422af1 100644
--- a/sw/source/core/unocore/unotext.cxx
+++ b/sw/source/core/unocore/unotext.cxx
@@ -1566,6 +1566,8 @@ SwXText::convertToTextFrame(
}
bool bParaAfterInserted = false;
bool bParaBeforeInserted = false;
+ ::std::optional<SwPaM> oAnchorCheckPam;
+ oAnchorCheckPam.emplace(*pStartPam->Start(), *pEndPam->End());
if (
pStartStartNode && pEndStartNode &&
(pStartStartNode != pEndStartNode || pStartStartNode != GetStartNode())
@@ -1646,6 +1648,7 @@ SwXText::convertToTextFrame(
bParaAfterInserted = GetDoc()->getIDocumentContentOperations().AppendTextNode( aEnd );
pEndPam->DeleteMark();
*pEndPam->GetPoint() = aEnd;
+ *oAnchorCheckPam->End() = aEnd;
}
pStartPam->SetMark();
*pStartPam->End() = *pEndPam->End();
@@ -1660,10 +1663,17 @@ SwXText::convertToTextFrame(
{
const SwFrameFormat* pFrameFormat = (*m_pImpl->m_pDoc->GetSpzFrameFormats())[i];
const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
- if ( !isGraphicNode(pFrameFormat) &&
- (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId() || RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) &&
- pStartPam->Start()->nNode.GetIndex() <= rAnchor.GetContentAnchor()->nNode.GetIndex() &&
- pStartPam->End()->nNode.GetIndex() >= rAnchor.GetContentAnchor()->nNode.GetIndex())
+ // note: Word can do at-char anchors in text frames - sometimes!
+ // see testFlyInFly for why this checks only the edges of the selection,
+ // and testFloatingTablesAnchor for why it excludes pre/post table
+ // added nodes
+ if (!isGraphicNode(pFrameFormat)
+ && ( (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()
+ && ( oAnchorCheckPam->Start()->nNode.GetIndex() == rAnchor.GetContentAnchor()->nNode.GetIndex()
+ || oAnchorCheckPam->End()->nNode.GetIndex() == rAnchor.GetContentAnchor()->nNode.GetIndex()))
+ || (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()
+ && ( *oAnchorCheckPam->Start() == *rAnchor.GetContentAnchor()
+ || *oAnchorCheckPam->End() == *rAnchor.GetContentAnchor()))))
{
if (pFrameFormat->GetName().isEmpty())
{
@@ -1675,6 +1685,7 @@ SwXText::convertToTextFrame(
}
}
}
+ oAnchorCheckPam.reset(); // clear SwIndex before deleting nodes
const uno::Reference<text::XTextFrame> xNewFrame(
SwXTextFrame::CreateXTextFrame(*m_pImpl->m_pDoc, nullptr));
@@ -1692,7 +1703,7 @@ SwXText::convertToTextFrame(
new SwXTextRange(*pStartPam, this);
assert(rNewFrame.IsDescriptor());
rNewFrame.attachToRange(xInsertTextRange, pStartPam.get());
- rNewFrame.setName(m_pImpl->m_pDoc->GetUniqueFrameName());
+ assert(!rNewFrame.getName().isEmpty());
}
SwTextNode *const pTextNode(pStartPam->GetNode().GetTextNode());
diff --git a/sw/source/core/view/printdata.cxx b/sw/source/core/view/printdata.cxx
index a2da5005cc38..a92f3661c990 100644
--- a/sw/source/core/view/printdata.cxx
+++ b/sw/source/core/view/printdata.cxx
@@ -301,8 +301,7 @@ SwPrintUIOptions::SwPrintUIOptions(
aWidgetIds[4] = "rbRangeSelection";
m_aUIProperties[nIdx++].Value = setChoiceRadiosControlOpt(aWidgetIds, OUString(),
aHelpIds, aPrintRangeName,
- aChoices,
- bHasSelection ? 4 : 0,
+ aChoices, 0 /* always default to 'All pages' */,
aChoicesDisabled);
// show an Edit dependent on "Pages" selected
diff --git a/sw/source/filter/basflt/fltshell.cxx b/sw/source/filter/basflt/fltshell.cxx
index 7d96867acb00..8a94cd48d5b3 100644
--- a/sw/source/filter/basflt/fltshell.cxx
+++ b/sw/source/filter/basflt/fltshell.cxx
@@ -660,7 +660,7 @@ void SwFltControlStack::SetAttrInDoc(const SwPosition& rTmpPos,
SwTextNode const*const pTextNode(
aRegion.End()->nNode.GetNode().GetTextNode());
SwTextField const*const pField = pTextNode ? pTextNode->GetFieldTextAttrAt(
- aRegion.End()->nContent.GetIndex() - 1, true) : nullptr;
+ aRegion.End()->nContent.GetIndex() - 1, ::sw::GetTextAttrMode::Default) : nullptr;
if (pField)
{
SwPostItField const*const pPostIt(
diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx
index a0da671de733..112975f98511 100644
--- a/sw/source/filter/html/htmlplug.cxx
+++ b/sw/source/filter/html/htmlplug.cxx
@@ -1087,7 +1087,12 @@ void SwHTMLParser::InsertFloatingFrame()
bool bHasBorder = aFrameDesc.HasFrameBorder();
Size aMargin = aFrameDesc.GetMargin();
- xSet->setPropertyValue("FrameURL", uno::makeAny( aFrameDesc.GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
+ OUString sHRef = aFrameDesc.GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if (INetURLObject(sHRef).IsExoticProtocol())
+ NotifyMacroEventRead();
+
+ xSet->setPropertyValue("FrameURL", uno::makeAny( sHRef ) );
xSet->setPropertyValue("FrameName", uno::makeAny( aName ) );
if ( eScroll == ScrollingMode::Auto )
diff --git a/sw/source/filter/html/htmltab.cxx b/sw/source/filter/html/htmltab.cxx
index ce689df01b9d..f0edba59c107 100644
--- a/sw/source/filter/html/htmltab.cxx
+++ b/sw/source/filter/html/htmltab.cxx
@@ -34,6 +34,7 @@
#include <svtools/htmlkywd.hxx>
#include <svl/urihelper.hxx>
#include <svl/listener.hxx>
+#include <svx/sdrobjectuser.hxx>
#include <sal/log.hxx>
#include <dcontact.hxx>
@@ -372,7 +373,7 @@ typedef std::vector<HTMLTableColumn> HTMLTableColumns;
typedef std::vector<SdrObject *> SdrObjects;
-class HTMLTable
+class HTMLTable : public sdr::ObjectUser
{
OUString m_aId;
OUString m_aStyle;
@@ -520,6 +521,8 @@ private:
sal_uInt16 GetBorderWidth( const SvxBorderLine& rBLine,
bool bWithDistance=false ) const;
+ virtual void ObjectInDestruction(const SdrObject& rObject) override;
+
public:
bool m_bFirstCell; // is there a cell created already?
@@ -529,7 +532,7 @@ public:
bool bHasToFly,
const HTMLTableOptions& rOptions);
- ~HTMLTable();
+ virtual ~HTMLTable();
// Identifying of a cell
const HTMLTableCell& GetCell(sal_uInt16 nRow, sal_uInt16 nCell) const;
@@ -968,14 +971,8 @@ void HTMLTable::InitCtor(const HTMLTableOptions& rOptions)
m_aRightBorderLine = m_aLeftBorderLine;
if( rOptions.nCellSpacing != 0 )
- {
m_aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
- m_aBorderLine.SetWidth( DEF_LINE_WIDTH_0 );
- }
- else
- {
- m_aBorderLine.SetWidth( DEF_LINE_WIDTH_0 );
- }
+ m_aBorderLine.SetWidth(SvxBorderLineWidth::Hairline);
m_aBorderLine.SetColor( rBorderColor );
if( m_nCellPadding )
@@ -1065,11 +1062,33 @@ bool SwHTMLParser::IsReqIF() const
return m_bReqIF;
}
+// if any m_pResizeDrawObjects members are deleted during parse, remove them
+// from m_pResizeDrawObjects and m_pDrawObjectPrcWidths
+void HTMLTable::ObjectInDestruction(const SdrObject& rObject)
+{
+ auto it = std::find(m_pResizeDrawObjects->begin(), m_pResizeDrawObjects->end(), &rObject);
+ assert(it != m_pResizeDrawObjects->end());
+ auto nIndex = std::distance(m_pResizeDrawObjects->begin(), it);
+ m_pResizeDrawObjects->erase(it);
+ auto otherit = m_pDrawObjectPrcWidths->begin() + nIndex * 3;
+ m_pDrawObjectPrcWidths->erase(otherit, otherit + 3);
+}
+
HTMLTable::~HTMLTable()
{
m_pParser->DeregisterHTMLTable(this);
- m_pResizeDrawObjects.reset();
+ if (m_pResizeDrawObjects)
+ {
+ size_t nCount = m_pResizeDrawObjects->size();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ SdrObject *pObj = (*m_pResizeDrawObjects)[i];
+ pObj->RemoveObjectUser(*this);
+ }
+ m_pResizeDrawObjects.reset();
+ }
+
m_pDrawObjectPrcWidths.reset();
m_pContext.reset();
@@ -2483,6 +2502,7 @@ void HTMLTable::RegisterDrawObject( SdrObject *pObj, sal_uInt8 nPrcWidth )
if( !m_pResizeDrawObjects )
m_pResizeDrawObjects.reset(new SdrObjects);
m_pResizeDrawObjects->push_back( pObj );
+ pObj->AddObjectUser(*this);
if( !m_pDrawObjectPrcWidths )
m_pDrawObjectPrcWidths.reset(new std::vector<sal_uInt16>);
diff --git a/sw/source/filter/html/htmltabw.cxx b/sw/source/filter/html/htmltabw.cxx
index 577a9f5c7b11..18ad069e605b 100644
--- a/sw/source/filter/html/htmltabw.cxx
+++ b/sw/source/filter/html/htmltabw.cxx
@@ -811,9 +811,9 @@ void SwHTMLWrtTable::Write( SwHTMLWriter& rWrt, sal_Int16 eAlign,
OutTableCells( rWrt, pRow2->GetCells(), pRow2->GetBackground() );
if( !m_nCellSpacing && nRow < m_aRows.size()-1 && pRow2->bBottomBorder &&
- pRow2->nBottomBorder > DEF_LINE_WIDTH_1 )
+ pRow2->nBottomBorder > SvxBorderLineWidth::Hairline )
{
- for( auto nCnt = (pRow2->nBottomBorder / DEF_LINE_WIDTH_1) - 1; nCnt; --nCnt )
+ for( auto nCnt = (pRow2->nBottomBorder / SvxBorderLineWidth::Hairline) - 1; nCnt; --nCnt )
{
rWrt.OutNewLine();
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_tablerow );
diff --git a/sw/source/filter/html/svxcss1.cxx b/sw/source/filter/html/svxcss1.cxx
index c1a6f7312d30..e570d1a92c54 100644
--- a/sw/source/filter/html/svxcss1.cxx
+++ b/sw/source/filter/html/svxcss1.cxx
@@ -244,9 +244,9 @@ static CSS1PropertyEnum const aBulletStyleTable[] =
static sal_uInt16 const aBorderWidths[] =
{
- DEF_LINE_WIDTH_0,
- DEF_LINE_WIDTH_5,
- DEF_LINE_WIDTH_1
+ SvxBorderLineWidth::Hairline,
+ SvxBorderLineWidth::VeryThin,
+ SvxBorderLineWidth::Thin
};
#undef SBORDER_ENTRY
diff --git a/sw/source/filter/html/swhtml.cxx b/sw/source/filter/html/swhtml.cxx
index 3f72a8a044e3..1a08be28684a 100644
--- a/sw/source/filter/html/swhtml.cxx
+++ b/sw/source/filter/html/swhtml.cxx
@@ -5305,12 +5305,12 @@ void SwHTMLParser::InsertHorzRule()
}
else if( bNoShade )
{
- aBorderLine.SetWidth( DEF_LINE_WIDTH_2 );
+ aBorderLine.SetWidth( SvxBorderLineWidth::Medium );
}
else
{
aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::DOUBLE);
- aBorderLine.SetWidth( DEF_LINE_WIDTH_0 );
+ aBorderLine.SetWidth(SvxBorderLineWidth::Hairline);
}
SvxBoxItem aBoxItem(RES_BOX);
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 5dbb02ce9eb5..f45de340f91d 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -301,6 +301,28 @@ static bool lcl_isOnelinerSdt(const OUString& rName)
return rName == "Title" || rName == "Subtitle" || rName == "Company";
}
+static void AddToAttrList(rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrs, ...)
+{
+ if (!pAttrList.is())
+ pAttrList = FastSerializerHelper::createAttrList();
+
+ va_list args;
+ va_start(args, nAttrs);
+ for (sal_Int32 i = 0; i < nAttrs; i++)
+ {
+ sal_Int32 nName = va_arg(args, sal_Int32);
+ const char* pValue = va_arg(args, const char*);
+ if (pValue)
+ pAttrList->add(nName, pValue);
+ }
+ va_end(args);
+}
+
+static void AddToAttrList(rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrName, const char* sAttrValue)
+{
+ AddToAttrList(pAttrList, 1, nAttrName, sAttrValue);
+}
+
// write a floating table directly to docx without the surrounding frame
void DocxAttributeOutput::WriteFloatingTable(ww8::Frame const* pParentFrame)
{
@@ -438,7 +460,7 @@ void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pText
// would normally arrive, it would be too late (would be after the
// paragraph start has been written).
bool bEndParaSdt = false;
- if (m_bStartedParaSdt)
+ if (m_aParagraphSdt.m_bStartedSdt)
{
SwTextNode* pTextNode = m_rExport.m_pCurPam->GetNode().GetTextNode();
if (pTextNode && pTextNode->GetpSwAttrSet())
@@ -448,17 +470,16 @@ void DocxAttributeOutput::StartParagraph( ww8::WW8TableNodeInfo::Pointer_t pText
{
const SfxGrabBagItem& rParaGrabBag = static_cast<const SfxGrabBagItem&>(*pItem);
const std::map<OUString, css::uno::Any>& rMap = rParaGrabBag.GetGrabBag();
- bEndParaSdt = m_bStartedParaSdt && rMap.find("ParaSdtEndBefore") != rMap.end();
+ bEndParaSdt = m_aParagraphSdt.m_bStartedSdt && rMap.find("ParaSdtEndBefore") != rMap.end();
}
}
}
// TODO also avoid multiline paragraphs in those SDT types for shape text
- bool bOneliner = m_bStartedParaSdt && !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen() && lcl_isOnelinerSdt(m_aStartedParagraphSdtPrAlias);
- if (bEndParaSdt || (m_bStartedParaSdt && m_bHadSectPr) || bOneliner)
+ bool bOneliner = m_aParagraphSdt.m_bStartedSdt && !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen() && lcl_isOnelinerSdt(m_aStartedParagraphSdtPrAlias);
+ if (bEndParaSdt || (m_aParagraphSdt.m_bStartedSdt && m_bHadSectPr) || bOneliner)
{
// This is the common case: "close sdt before the current paragraph" was requested by the next paragraph.
- EndSdtBlock();
- m_bStartedParaSdt = false;
+ m_aParagraphSdt.EndSdtBlock(m_pSerializer);
m_aStartedParagraphSdtPrAlias.clear();
}
m_bHadSectPr = false;
@@ -551,14 +572,270 @@ static OString convertToOOXMLHoriOrientRel(sal_Int16 nOrientRel)
}
}
-static void lcl_deleteAndResetTheLists( rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenChildren, rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs, OUString& rSdtPrAlias)
+void SdtBlockHelper::DeleteAndResetTheLists()
+{
+ if (m_pTokenChildren.is() )
+ m_pTokenChildren.clear();
+ if (m_pDataBindingAttrs.is() )
+ m_pDataBindingAttrs.clear();
+ if (m_pTextAttrs.is())
+ m_pTextAttrs.clear();
+ if (!m_aAlias.isEmpty())
+ m_aAlias.clear();
+ if (!m_aPlaceHolderDocPart.isEmpty())
+ m_aPlaceHolderDocPart.clear();
+ if (!m_aColor.isEmpty())
+ m_aColor.clear();
+ m_bHasId = false;
+}
+
+void SdtBlockHelper::WriteSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer, bool bRunTextIsOn, bool bParagraphHasDrawing)
+{
+ if (m_nSdtPrToken <= 0 && !m_pDataBindingAttrs.is() && !m_bHasId)
+ return;
+
+ // sdt start mark
+ pSerializer->mark(Tag_WriteSdtBlock);
+
+ pSerializer->startElementNS(XML_w, XML_sdt);
+
+ // output sdt properties
+ pSerializer->startElementNS(XML_w, XML_sdtPr);
+
+ if (m_nSdtPrToken > 0 && m_pTokenChildren.is())
+ {
+ if (!m_pTokenAttributes.is())
+ pSerializer->startElement(m_nSdtPrToken);
+ else
+ {
+ XFastAttributeListRef xAttrList( m_pTokenAttributes.get() );
+ m_pTokenAttributes.clear();
+ pSerializer->startElement(m_nSdtPrToken, xAttrList);
+ }
+
+ if (m_nSdtPrToken == FSNS(XML_w, XML_date) || m_nSdtPrToken == FSNS(XML_w, XML_docPartObj) || m_nSdtPrToken == FSNS(XML_w, XML_docPartList) || m_nSdtPrToken == FSNS(XML_w14, XML_checkbox)) {
+ const uno::Sequence<xml::FastAttribute> aChildren = m_pTokenChildren->getFastAttributes();
+ for (const auto& rChild : aChildren)
+ pSerializer->singleElement(rChild.Token, FSNS(XML_w, XML_val), rChild.Value.toUtf8() );
+ }
+
+ pSerializer->endElement(m_nSdtPrToken);
+ }
+ else if ((m_nSdtPrToken > 0) && m_nSdtPrToken != FSNS(XML_w, XML_id) && !(bRunTextIsOn && bParagraphHasDrawing))
+ {
+ if (!m_pTokenAttributes.is())
+ pSerializer->singleElement(m_nSdtPrToken);
+ else
+ {
+ XFastAttributeListRef xAttrList( m_pTokenAttributes.get() );
+ m_pTokenAttributes.clear();
+ pSerializer->singleElement(m_nSdtPrToken, xAttrList);
+ }
+ }
+
+ WriteExtraParams(pSerializer);
+
+ pSerializer->endElementNS(XML_w, XML_sdtPr);
+
+ // sdt contents start tag
+ pSerializer->startElementNS(XML_w, XML_sdtContent);
+
+ // prepend the tags since the sdt start mark before the paragraph
+ pSerializer->mergeTopMarks(Tag_WriteSdtBlock, sax_fastparser::MergeMarks::PREPEND);
+
+ // write the ending tags after the paragraph
+ m_bStartedSdt = true;
+
+ // clear sdt status
+ m_nSdtPrToken = 0;
+ m_pTokenChildren.clear();
+ m_pDataBindingAttrs.clear();
+ m_pTextAttrs.clear();
+ m_aAlias.clear();
+ m_bHasId = false;
+}
+
+void SdtBlockHelper::WriteExtraParams(::sax_fastparser::FSHelperPtr& pSerializer)
+{
+ if (m_nSdtPrToken == FSNS(XML_w, XML_id) || m_bHasId)
+ //Word won't open a document with an empty id tag, we fill it with a random number
+ pSerializer->singleElementNS(XML_w, XML_id, FSNS(XML_w, XML_val),
+ OString::number(comphelper::rng::uniform_int_distribution(0, std::numeric_limits<int>::max())));
+
+ if (m_pDataBindingAttrs.is())
+ {
+ XFastAttributeListRef xAttrList( m_pDataBindingAttrs.get() );
+ m_pDataBindingAttrs.clear();
+ pSerializer->singleElementNS(XML_w, XML_dataBinding, xAttrList);
+ }
+
+ if (m_pTextAttrs.is())
+ {
+ XFastAttributeListRef xAttrList( m_pTextAttrs.get() );
+ m_pTextAttrs.clear();
+ pSerializer->singleElementNS(XML_w, XML_text, xAttrList);
+ }
+
+ if (!m_aPlaceHolderDocPart.isEmpty())
+ {
+ pSerializer->startElementNS(XML_w, XML_placeholder);
+ pSerializer->singleElementNS(XML_w, XML_docPart, FSNS(XML_w, XML_val), m_aPlaceHolderDocPart.toUtf8() );
+ pSerializer->endElementNS(XML_w, XML_placeholder);
+ }
+ if (!m_aColor.isEmpty())
+ {
+ pSerializer->singleElementNS(XML_w15, XML_color, FSNS(XML_w, XML_val), m_aColor.toUtf8() );
+ }
+
+ if (!m_aAlias.isEmpty())
+ pSerializer->singleElementNS(XML_w, XML_alias, FSNS(XML_w, XML_val), m_aAlias.toUtf8() );
+}
+
+void SdtBlockHelper::EndSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer)
{
- if( pSdtPrTokenChildren.is() )
- pSdtPrTokenChildren.clear();
- if( pSdtPrDataBindingAttrs.is() )
- pSdtPrDataBindingAttrs.clear();
- if (!rSdtPrAlias.isEmpty())
- rSdtPrAlias.clear();
+ pSerializer->endElementNS(XML_w, XML_sdtContent);
+ pSerializer->endElementNS(XML_w, XML_sdt);
+ m_bStartedSdt = false;
+}
+
+void SdtBlockHelper::GetSdtParamsFromGrabBag(const uno::Sequence<beans::PropertyValue>& aGrabBagSdt)
+{
+ for (const beans::PropertyValue& aPropertyValue : aGrabBagSdt)
+ {
+ if (aPropertyValue.Name == "ooxml:CT_SdtPr_checkbox")
+ {
+ m_nSdtPrToken = FSNS(XML_w14, XML_checkbox);
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ aPropertyValue.Value >>= aGrabBag;
+ for (const auto& rProp : std::as_const(aGrabBag))
+ {
+ OUString sValue = rProp.Value.get<OUString>();
+ if (rProp.Name == "ooxml:CT_SdtCheckbox_checked")
+ AddToAttrList(m_pTokenChildren,
+ FSNS(XML_w14, XML_checked),
+ OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr());
+ else if (rProp.Name == "ooxml:CT_SdtCheckbox_checkedState")
+ AddToAttrList(m_pTokenChildren,
+ FSNS(XML_w14, XML_checkedState),
+ OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr());
+ else if (rProp.Name == "ooxml:CT_SdtCheckbox_uncheckedState")
+ AddToAttrList(m_pTokenChildren,
+ FSNS(XML_w14, XML_uncheckedState),
+ OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_dataBinding" && !m_pDataBindingAttrs.is())
+ {
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ aPropertyValue.Value >>= aGrabBag;
+ for (const auto& rProp : std::as_const(aGrabBag))
+ {
+ OUString sValue = rProp.Value.get<OUString>();
+ if (rProp.Name == "ooxml:CT_DataBinding_prefixMappings")
+ AddToAttrList( m_pDataBindingAttrs,
+ FSNS( XML_w, XML_prefixMappings ),
+ OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
+ else if (rProp.Name == "ooxml:CT_DataBinding_xpath")
+ AddToAttrList( m_pDataBindingAttrs,
+ FSNS( XML_w, XML_xpath ),
+ OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
+ else if (rProp.Name == "ooxml:CT_DataBinding_storeItemID")
+ AddToAttrList( m_pDataBindingAttrs,
+ FSNS( XML_w, XML_storeItemID ),
+ OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
+ }
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_text")
+ {
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ aPropertyValue.Value >>= aGrabBag;
+ if (aGrabBag.hasElements())
+ {
+ for (const auto& rProp : std::as_const(aGrabBag))
+ {
+ OUString sValue = rProp.Value.get<OUString>();
+ if (rProp.Name == "ooxml:CT_SdtText_multiLine")
+ AddToAttrList(m_pTextAttrs,
+ FSNS(XML_w, XML_multiLine),
+ OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+ else
+ {
+ // We still have w:text, but no attrs
+ m_nSdtPrToken = FSNS(XML_w, XML_text);
+ }
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPlaceholder_docPart")
+ {
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ aPropertyValue.Value >>= aGrabBag;
+ for (const auto& rProp : std::as_const(aGrabBag))
+ {
+ OUString sValue = rProp.Value.get<OUString>();
+ if (rProp.Name == "ooxml:CT_SdtPlaceholder_docPart_val")
+ m_aPlaceHolderDocPart = sValue;
+ }
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_color")
+ {
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ aPropertyValue.Value >>= aGrabBag;
+ for (const auto& rProp : std::as_const(aGrabBag))
+ {
+ OUString sValue = rProp.Value.get<OUString>();
+ if (rProp.Name == "ooxml:CT_SdtColor_val")
+ m_aColor = sValue;
+ }
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_alias" && m_aAlias.isEmpty())
+ {
+ if (!(aPropertyValue.Value >>= m_aAlias))
+ SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt alias value");
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_id")
+ m_bHasId = true;
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_citation")
+ m_nSdtPrToken = FSNS(XML_w, XML_citation);
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_docPartObj" ||
+ aPropertyValue.Name == "ooxml:CT_SdtPr_docPartList")
+ {
+ if (aPropertyValue.Name == "ooxml:CT_SdtPr_docPartObj")
+ m_nSdtPrToken = FSNS(XML_w, XML_docPartObj);
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_docPartList")
+ m_nSdtPrToken = FSNS(XML_w, XML_docPartList);
+
+ uno::Sequence<beans::PropertyValue> aGrabBag;
+ aPropertyValue.Value >>= aGrabBag;
+ for (const auto& rProp : std::as_const(aGrabBag))
+ {
+ OUString sValue = rProp.Value.get<OUString>();
+ if (rProp.Name == "ooxml:CT_SdtDocPart_docPartGallery")
+ AddToAttrList(m_pTokenChildren,
+ FSNS(XML_w, XML_docPartGallery),
+ OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr());
+ else if (rProp.Name == "ooxml:CT_SdtDocPart_docPartCategory")
+ AddToAttrList(m_pTokenChildren,
+ FSNS(XML_w, XML_docPartCategory),
+ OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr());
+ else if (rProp.Name == "ooxml:CT_SdtDocPart_docPartUnique")
+ {
+ if (sValue.isEmpty())
+ sValue = "true";
+ AddToAttrList(m_pTokenChildren, FSNS(XML_w, XML_docPartUnique),
+ OUStringToOString(sValue, RTL_TEXTENCODING_UTF8).getStr());
+ }
+ }
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_equation")
+ m_nSdtPrToken = FSNS(XML_w, XML_equation);
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_picture")
+ m_nSdtPrToken = FSNS(XML_w, XML_picture);
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_group")
+ m_nSdtPrToken = FSNS(XML_w, XML_group);
+ else
+ SAL_WARN("sw.ww8", "GetSdtParamsFromGrabBag unhandled SdtPr grab bag property " << aPropertyValue.Name);
+ }
}
void DocxAttributeOutput::PopulateFrameProperties(const SwFrameFormat* pFrameFormat, const Size& rSize)
@@ -636,7 +913,7 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
++m_nTextFrameLevel;
if( m_nTextFrameLevel == 1 && !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen() )
{
- comphelper::FlagRestorationGuard aStartedParaSdtGuard(m_bStartedParaSdt, false);
+ comphelper::FlagRestorationGuard aStartedParaSdtGuard(m_aParagraphSdt.m_bStartedSdt, false);
assert(!m_pPostponedCustomShape);
m_pPostponedCustomShape.reset(new std::vector<PostponedDrawing>);
@@ -648,11 +925,10 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
if (!TextBoxIsFramePr(rFrameFormat) || m_bWritingHeaderFooter)
{
- if (m_bStartedCharSdt)
+ if (m_aRunSdt.m_bStartedSdt)
{
// Run-level SDT still open? Close it before AlternateContent.
- EndSdtBlock();
- m_bStartedCharSdt = false;
+ m_aRunSdt.EndSdtBlock(m_pSerializer);
}
m_pSerializer->startElementNS(XML_w, XML_r);
m_pSerializer->startElementNS(XML_mc, XML_AlternateContent);
@@ -738,11 +1014,10 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
m_nHyperLinkCount = 0;
}
- if (m_bStartedCharSdt)
+ if (m_aRunSdt.m_bStartedSdt)
{
// Run-level SDT still open? Close it now.
- EndSdtBlock();
- m_bStartedCharSdt = false;
+ m_aRunSdt.EndSdtBlock(m_pSerializer);
}
if (m_bPageBreakAfter)
@@ -754,15 +1029,25 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
m_pSerializer->endElementNS( XML_w, XML_p );
// on export sdt blocks are never nested ATM
- if( !m_bAnchorLinkedToNode && !m_bStartedParaSdt )
- WriteSdtBlock( m_nParagraphSdtPrToken, m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrTokenAttributes, m_pParagraphSdtPrDataBindingAttrs, m_aParagraphSdtPrAlias, /*bPara=*/true );
+ if (!m_bAnchorLinkedToNode && !m_aParagraphSdt.m_bStartedSdt)
+ {
+ m_aParagraphSdt.WriteSdtBlock(m_pSerializer, m_bRunTextIsOn, m_rExport.SdrExporter().IsParagraphHasDrawing());
+
+ if (m_aParagraphSdt.m_bStartedSdt)
+ {
+ if (m_tableReference->m_bTableCellOpen)
+ m_tableReference->m_bTableCellParaSdtOpen = true;
+ if (m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen())
+ m_rExport.SdrExporter().setParagraphSdtOpen(true);
+ }
+ }
else
{
//These should be written out to the actual Node and not to the anchor.
//Clear them as they will be repopulated when the node is processed.
- m_nParagraphSdtPrToken = 0;
- m_bParagraphSdtHasId = false;
- lcl_deleteAndResetTheLists( m_pParagraphSdtPrTokenChildren, m_pParagraphSdtPrDataBindingAttrs, m_aParagraphSdtPrAlias );
+ m_aParagraphSdt.m_nSdtPrToken = 0;
+ m_aParagraphSdt.m_bHasId = false;
+ m_aParagraphSdt.DeleteAndResetTheLists();
}
//sdtcontent is written so Set m_bParagraphHasDrawing to false
@@ -790,107 +1075,6 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
m_aBookmarksOfParagraphEnd.clear();
}
-void DocxAttributeOutput::WriteSdtBlock( sal_Int32& nSdtPrToken,
- rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenChildren,
- rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenAttributes,
- rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs,
- OUString& rSdtPrAlias,
- bool bPara )
-{
- if( nSdtPrToken <= 0 && !pSdtPrDataBindingAttrs.is() )
- return;
-
- // sdt start mark
- m_pSerializer->mark(Tag_WriteSdtBlock);
-
- m_pSerializer->startElementNS(XML_w, XML_sdt);
-
- // output sdt properties
- m_pSerializer->startElementNS(XML_w, XML_sdtPr);
-
- if( nSdtPrToken > 0 && pSdtPrTokenChildren.is() )
- {
- if (!pSdtPrTokenAttributes.is())
- m_pSerializer->startElement(nSdtPrToken);
- else
- {
- XFastAttributeListRef xAttrList(pSdtPrTokenAttributes.get());
- pSdtPrTokenAttributes.clear();
- m_pSerializer->startElement(nSdtPrToken, xAttrList);
- }
-
- if (nSdtPrToken == FSNS( XML_w, XML_date ) || nSdtPrToken == FSNS( XML_w, XML_docPartObj ) || nSdtPrToken == FSNS( XML_w, XML_docPartList ) || nSdtPrToken == FSNS( XML_w14, XML_checkbox )) {
- const uno::Sequence<xml::FastAttribute> aChildren = pSdtPrTokenChildren->getFastAttributes();
- for( const auto& rChild : aChildren )
- m_pSerializer->singleElement( rChild.Token,
- FSNS(XML_w, XML_val), rChild.Value.toUtf8() );
- }
-
- m_pSerializer->endElement( nSdtPrToken );
- }
- else if( (nSdtPrToken > 0) && nSdtPrToken != FSNS( XML_w, XML_id ) && !(m_bRunTextIsOn && m_rExport.SdrExporter().IsParagraphHasDrawing()))
- {
- if (!pSdtPrTokenAttributes.is())
- m_pSerializer->singleElement(nSdtPrToken);
- else
- {
- XFastAttributeListRef xAttrList(pSdtPrTokenAttributes.get());
- pSdtPrTokenAttributes.clear();
- m_pSerializer->singleElement(nSdtPrToken, xAttrList);
- }
- }
-
- if( nSdtPrToken == FSNS( XML_w, XML_id ) || ( bPara && m_bParagraphSdtHasId ) )
- //Word won't open a document with an empty id tag, we fill it with a random number
- m_pSerializer->singleElementNS(XML_w, XML_id, FSNS(XML_w, XML_val),
- OString::number(comphelper::rng::uniform_int_distribution(0, std::numeric_limits<int>::max())));
-
- if( pSdtPrDataBindingAttrs.is() && !m_rExport.SdrExporter().IsParagraphHasDrawing())
- {
- XFastAttributeListRef xAttrList( pSdtPrDataBindingAttrs.get() );
- pSdtPrDataBindingAttrs.clear();
- m_pSerializer->singleElementNS(XML_w, XML_dataBinding, xAttrList);
- }
-
- if (!rSdtPrAlias.isEmpty())
- m_pSerializer->singleElementNS(XML_w, XML_alias, FSNS(XML_w, XML_val),
- rSdtPrAlias.toUtf8());
-
- m_pSerializer->endElementNS( XML_w, XML_sdtPr );
-
- // sdt contents start tag
- m_pSerializer->startElementNS(XML_w, XML_sdtContent);
-
- // prepend the tags since the sdt start mark before the paragraph
- m_pSerializer->mergeTopMarks(Tag_WriteSdtBlock, sax_fastparser::MergeMarks::PREPEND);
-
- // write the ending tags after the paragraph
- if (bPara)
- {
- m_bStartedParaSdt = true;
- if (m_tableReference->m_bTableCellOpen)
- m_tableReference->m_bTableCellParaSdtOpen = true;
- if (m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen())
- m_rExport.SdrExporter().setParagraphSdtOpen(true);
- }
- else
- // Support multiple runs inside a run-level SDT: don't close the SDT block yet.
- m_bStartedCharSdt = true;
-
- // clear sdt status
- nSdtPrToken = 0;
- pSdtPrTokenChildren.clear();
- pSdtPrDataBindingAttrs.clear();
- rSdtPrAlias.clear();
-
-}
-
-void DocxAttributeOutput::EndSdtBlock()
-{
- m_pSerializer->endElementNS( XML_w, XML_sdtContent );
- m_pSerializer->endElementNS( XML_w, XML_sdt );
-}
-
#define MAX_CELL_IN_WORD 62
void DocxAttributeOutput::SyncNodelessCells(ww8::WW8TableNodeInfoInner::Pointer_t const & pInner, sal_Int32 nCell, sal_uInt32 nRow)
@@ -991,7 +1175,7 @@ void DocxAttributeOutput::SectionBreaks(const SwNode& rNode)
if (aNextIndex.GetNode().IsTextNode())
{
const SwTextNode* pTextNode = static_cast<SwTextNode*>(&aNextIndex.GetNode());
- m_rExport.OutputSectionBreaks(pTextNode->GetpSwAttrSet(), *pTextNode, m_tableReference->m_bTableCellOpen, pTextNode->GetText().isEmpty());
+ m_rExport.OutputSectionBreaks(pTextNode->GetpSwAttrSet(), *pTextNode, m_tableReference->m_bTableCellOpen);
}
else if (aNextIndex.GetNode().IsTableNode())
{
@@ -1008,7 +1192,7 @@ void DocxAttributeOutput::SectionBreaks(const SwNode& rNode)
// Also handle section endings
const SwTextNode* pTextNode = aNextIndex.GetNode().GetTextNode();
if (rNode.StartOfSectionNode()->IsTableNode() || rNode.StartOfSectionNode()->IsSectionNode())
- m_rExport.OutputSectionBreaks(pTextNode->GetpSwAttrSet(), *pTextNode, m_tableReference->m_bTableCellOpen, pTextNode->GetText().isEmpty());
+ m_rExport.OutputSectionBreaks(pTextNode->GetpSwAttrSet(), *pTextNode, m_tableReference->m_bTableCellOpen);
}
}
}
@@ -1326,7 +1510,10 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin() + nFieldsInPrevHyperlink; pIt != m_Fields.end(); )
{
// Add the fields starts for all but hyperlinks and TOCs
- if (pIt->bOpen && pIt->pField && pIt->eType != ww::eFORMDROPDOWN)
+ if (pIt->bOpen && pIt->pField && pIt->eType != ww::eFORMDROPDOWN &&
+ // it is not an input field with extra grabbag params (sdt field)
+ (!(pIt->eType == ww::eFILLIN && static_cast<const SwInputField*>(pIt->pField.get())->getGrabBagParams().hasElements()))
+ )
{
StartField_Impl( pNode, nPos, *pIt );
@@ -1360,12 +1547,11 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
// if another sdt starts in this run, then wait
// as closing the sdt now, might cause nesting of sdts
- if (m_nRunSdtPrToken > 0)
+ if (m_aRunSdt.m_nSdtPrToken > 0)
bCloseEarlierSDT = true;
else
- EndSdtBlock();
+ m_aRunSdt.EndSdtBlock(m_pSerializer);
m_bEndCharSdt = false;
- m_bStartedCharSdt = false;
}
if ( m_closeHyperlinkInPreviousRun )
@@ -1391,7 +1577,9 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
for ( std::vector<FieldInfos>::iterator pIt = m_Fields.begin(); pIt != m_Fields.end(); )
{
// Add the fields starts for hyperlinks, TOCs and index marks
- if (pIt->bOpen && (!pIt->pField || pIt->eType == ww::eFORMDROPDOWN))
+ if (pIt->bOpen && (!pIt->pField || pIt->eType == ww::eFORMDROPDOWN ||
+ // InputField with extra grabbag params - it is sdt field
+ (pIt->eType == ww::eFILLIN && static_cast<const SwInputField*>(pIt->pField.get())->getGrabBagParams().hasElements())))
{
StartRedline( m_pRedlineData );
StartField_Impl( pNode, nPos, *pIt, true );
@@ -1523,23 +1711,22 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
// enclose in a sdt block, if necessary: if one is already started, then don't do it for now
// (so on export sdt blocks are never nested ATM)
- if ( !m_bAnchorLinkedToNode && !m_bStartedCharSdt )
+ if ( !m_bAnchorLinkedToNode && !m_aRunSdt.m_bStartedSdt)
{
- rtl::Reference<sax_fastparser::FastAttributeList> pRunSdtPrTokenAttributes;
- WriteSdtBlock( m_nRunSdtPrToken, m_pRunSdtPrTokenChildren, pRunSdtPrTokenAttributes, m_pRunSdtPrDataBindingAttrs, m_aRunSdtPrAlias, /*bPara=*/false );
+ m_aRunSdt.WriteSdtBlock(m_pSerializer, m_bRunTextIsOn, m_rExport.SdrExporter().IsParagraphHasDrawing());
}
else
{
//These should be written out to the actual Node and not to the anchor.
//Clear them as they will be repopulated when the node is processed.
- m_nRunSdtPrToken = 0;
- lcl_deleteAndResetTheLists( m_pRunSdtPrTokenChildren, m_pRunSdtPrDataBindingAttrs, m_aRunSdtPrAlias );
+ m_aRunSdt.m_nSdtPrToken = 0;
+ m_aRunSdt.DeleteAndResetTheLists();
}
if (bCloseEarlierSDT)
{
m_pSerializer->mark(Tag_EndRun_2);
- EndSdtBlock();
+ m_aRunSdt.EndSdtBlock(m_pSerializer);
m_pSerializer->mergeTopMarks(Tag_EndRun_2, sax_fastparser::MergeMarks::PREPEND);
}
@@ -1898,7 +2085,7 @@ void DocxAttributeOutput::WriteFFData( const FieldInfos& rInfos )
}
}
-void DocxAttributeOutput::WriteFormDateStart(const OUString& sFullDate, const OUString& sDateFormat, const OUString& sLang)
+void DocxAttributeOutput::WriteFormDateStart(const OUString& sFullDate, const OUString& sDateFormat, const OUString& sLang, const uno::Sequence<beans::PropertyValue>& aGrabBagSdt)
{
m_pSerializer->startElementNS(XML_w, XML_sdt);
m_pSerializer->startElementNS(XML_w, XML_sdtPr);
@@ -1919,8 +2106,64 @@ void DocxAttributeOutput::WriteFormDateStart(const OUString& sFullDate, const OU
FSNS(XML_w, XML_val), "dateTime");
m_pSerializer->singleElementNS(XML_w, XML_calendar,
FSNS(XML_w, XML_val), "gregorian");
-
m_pSerializer->endElementNS(XML_w, XML_date);
+
+ if (aGrabBagSdt.hasElements())
+ {
+ // There are some extra sdt parameters came from grab bag
+ SdtBlockHelper aSdtBlock;
+ aSdtBlock.GetSdtParamsFromGrabBag(aGrabBagSdt);
+ aSdtBlock.WriteExtraParams(m_pSerializer);
+ }
+
+ m_pSerializer->endElementNS(XML_w, XML_sdtPr);
+
+ m_pSerializer->startElementNS(XML_w, XML_sdtContent);
+}
+
+void DocxAttributeOutput::WriteSdtPlainText(const OUString & sValue, const uno::Sequence<beans::PropertyValue>& aGrabBagSdt)
+{
+ m_pSerializer->startElementNS(XML_w, XML_sdt);
+ m_pSerializer->startElementNS(XML_w, XML_sdtPr);
+
+ if (aGrabBagSdt.hasElements())
+ {
+ // There are some extra sdt parameters came from grab bag
+ SdtBlockHelper aSdtBlock;
+ aSdtBlock.GetSdtParamsFromGrabBag(aGrabBagSdt);
+ aSdtBlock.WriteExtraParams(m_pSerializer);
+
+ if (aSdtBlock.m_nSdtPrToken && aSdtBlock.m_nSdtPrToken != FSNS(XML_w, XML_id))
+ {
+ // Write <w:text/> or whatsoever from grabbag
+ m_pSerializer->singleElement(aSdtBlock.m_nSdtPrToken);
+ }
+
+ // Store databindings data for later writing to corresponding XMLs
+ OUString sPrefixMapping, sXpath;
+ for (const auto& rProp : std::as_const(aGrabBagSdt))
+ {
+ if (rProp.Name == "ooxml:CT_SdtPr_dataBinding")
+ {
+ uno::Sequence<beans::PropertyValue> aDataBindingProps;
+ rProp.Value >>= aDataBindingProps;
+ for (const auto& rDBProp : std::as_const(aDataBindingProps))
+ {
+ if (rDBProp.Name == "ooxml:CT_DataBinding_prefixMappings")
+ sPrefixMapping = rDBProp.Value.get<OUString>();
+ else if (rDBProp.Name == "ooxml:CT_DataBinding_xpath")
+ sXpath = rDBProp.Value.get<OUString>();
+ }
+ }
+ }
+
+ if (sXpath.getLength())
+ {
+ // Given xpath is sufficient
+ m_rExport.AddSdtData(sPrefixMapping, sXpath, sValue);
+ }
+ }
+
m_pSerializer->endElementNS(XML_w, XML_sdtPr);
m_pSerializer->startElementNS(XML_w, XML_sdtContent);
@@ -1996,6 +2239,7 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
{
// Expand unsupported fields
RunText( rInfos.pField->GetFieldName() );
+ return;
}
else if ( rInfos.eType == ww::eFORMDATE )
{
@@ -2023,7 +2267,11 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
OUString sLang;
params.extractParam( ODF_FORMDATE_DATEFORMAT_LANGUAGE, sLang );
- WriteFormDateStart( sFullDate, sDateFormat, sLang );
+ uno::Sequence<beans::PropertyValue> aSdtParams;
+ params.extractParam(UNO_NAME_MISC_OBJ_INTEROPGRABBAG, aSdtParams);
+
+ WriteFormDateStart( sFullDate, sDateFormat, sLang, aSdtParams);
+ return;
}
else if (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField)
{
@@ -2032,8 +2280,20 @@ void DocxAttributeOutput::StartField_Impl( const SwTextNode* pNode, sal_Int32 nP
WriteSdtDropDownStart(rField2.GetName(),
rField2.GetSelectedItem(),
rField2.GetItemSequence());
+ return;
+ }
+ else if (rInfos.eType == ww::eFILLIN)
+ {
+ SwInputField const& rField(*static_cast<SwInputField const*>(rInfos.pField.get()));
+ if (rField.getGrabBagParams().hasElements())
+ {
+ WriteSdtPlainText(rField.GetPar1(), rField.getGrabBagParams());
+ m_sRawText = rField.GetPar1(); // Write field content also as a fallback
+ return;
+ }
}
- else if ( rInfos.eType != ww::eNONE ) // HYPERLINK fields are just commands
+
+ if ( rInfos.eType != ww::eNONE ) // HYPERLINK fields are just commands
{
if ( bWriteRun )
m_pSerializer->startElementNS(XML_w, XML_r);
@@ -2239,7 +2499,7 @@ void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos
WriteSdtEnd();
return;
}
- if (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField)
+ else if (rInfos.eType == ww::eFORMDROPDOWN && rInfos.pField)
{
// write selected item from End not Start to ensure that any bookmarks
// precede it
@@ -2247,7 +2507,15 @@ void DocxAttributeOutput::EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos
WriteSdtDropDownEnd(rField.GetSelectedItem(), rField.GetItemSequence());
return;
}
-
+ else if (rInfos.eType == ww::eFILLIN && rInfos.pField)
+ {
+ SwInputField const& rField(*static_cast<SwInputField const*>(rInfos.pField.get()));
+ if (rField.getGrabBagParams().hasElements())
+ {
+ WriteSdtEnd();
+ return;
+ }
+ }
// The command has to be written before for the hyperlinks
if ( rInfos.pField )
{
@@ -2688,7 +2956,7 @@ void DocxAttributeOutput::GetSdtEndBefore(const SdrObject* pSdrObj)
auto pProp = std::find_if(aGrabBag.begin(), aGrabBag.end(),
[this](const beans::PropertyValue& rProp) {
- return "SdtEndBefore" == rProp.Name && m_bStartedCharSdt && !m_bEndCharSdt; });
+ return "SdtEndBefore" == rProp.Name && m_aRunSdt.m_bStartedSdt && !m_bEndCharSdt; });
if (pProp != aGrabBag.end())
pProp->Value >>= m_bEndCharSdt;
}
@@ -5787,8 +6055,10 @@ void DocxAttributeOutput::pushToTableExportContext(DocxTableExportContext& rCont
rContext.m_nTableDepth = m_tableReference->m_nTableDepth;
m_tableReference->m_nTableDepth = 0;
- rContext.m_bStartedParaSdt = m_bStartedParaSdt;
- m_bStartedParaSdt = false;
+ rContext.m_bStartedParaSdt = m_aParagraphSdt.m_bStartedSdt;
+ m_aParagraphSdt.m_bStartedSdt = false;
+ rContext.m_bStartedRunSdt = m_aRunSdt.m_bStartedSdt;
+ m_aRunSdt.m_bStartedSdt = false;
}
void DocxAttributeOutput::popFromTableExportContext(DocxTableExportContext const & rContext)
@@ -5796,7 +6066,8 @@ void DocxAttributeOutput::popFromTableExportContext(DocxTableExportContext const
m_rExport.m_pTableInfo = rContext.m_pTableInfo;
m_tableReference->m_bTableCellOpen = rContext.m_bTableCellOpen;
m_tableReference->m_nTableDepth = rContext.m_nTableDepth;
- m_bStartedParaSdt = rContext.m_bStartedParaSdt;
+ m_aParagraphSdt.m_bStartedSdt = rContext.m_bStartedParaSdt;
+ m_aRunSdt.m_bStartedSdt = rContext.m_bStartedRunSdt;
}
void DocxAttributeOutput::WriteTextBox(uno::Reference<drawing::XShape> xShape)
@@ -6127,11 +6398,10 @@ void DocxAttributeOutput::SectionBreak( sal_uInt8 nC, bool bBreakAfter, const WW
void DocxAttributeOutput::EndParaSdtBlock()
{
- if (m_bStartedParaSdt)
+ if (m_aParagraphSdt.m_bStartedSdt)
{
// Paragraph-level SDT still open? Close it now.
- EndSdtBlock();
- m_bStartedParaSdt = false;
+ m_aParagraphSdt.EndSdtBlock(m_pSerializer);
}
}
@@ -8966,102 +9236,8 @@ void DocxAttributeOutput::ParaGrabBag(const SfxGrabBagItem& rItem)
{
const uno::Sequence<beans::PropertyValue> aGrabBagSdt =
rGrabBagElement.second.get< uno::Sequence<beans::PropertyValue> >();
- for (const beans::PropertyValue& aPropertyValue : aGrabBagSdt)
- {
- if (aPropertyValue.Name == "ooxml:CT_SdtPr_docPartObj" ||
- aPropertyValue.Name == "ooxml:CT_SdtPr_docPartList")
- {
- if (aPropertyValue.Name == "ooxml:CT_SdtPr_docPartObj")
- m_nParagraphSdtPrToken = FSNS( XML_w, XML_docPartObj );
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_docPartList")
- m_nParagraphSdtPrToken = FSNS( XML_w, XML_docPartList );
-
- uno::Sequence<beans::PropertyValue> aGrabBag;
- aPropertyValue.Value >>= aGrabBag;
- for (const auto& rProp : std::as_const(aGrabBag))
- {
- OUString sValue = rProp.Value.get<OUString>();
- if (rProp.Name == "ooxml:CT_SdtDocPart_docPartGallery")
- AddToAttrList( m_pParagraphSdtPrTokenChildren,
- FSNS( XML_w, XML_docPartGallery ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_SdtDocPart_docPartCategory")
- AddToAttrList( m_pParagraphSdtPrTokenChildren,
- FSNS( XML_w, XML_docPartCategory ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_SdtDocPart_docPartUnique")
- {
- if (sValue.isEmpty())
- sValue = "true";
- AddToAttrList( m_pParagraphSdtPrTokenChildren, FSNS( XML_w, XML_docPartUnique ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- }
- }
- }
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_equation")
- m_nParagraphSdtPrToken = FSNS( XML_w, XML_equation );
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_picture")
- m_nParagraphSdtPrToken = FSNS( XML_w, XML_picture );
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_citation")
- m_nParagraphSdtPrToken = FSNS( XML_w, XML_citation );
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_group")
- m_nParagraphSdtPrToken = FSNS( XML_w, XML_group );
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_text")
- m_nParagraphSdtPrToken = FSNS(XML_w, XML_text);
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_dataBinding" && !m_pParagraphSdtPrDataBindingAttrs.is())
- {
- uno::Sequence<beans::PropertyValue> aGrabBag;
- aPropertyValue.Value >>= aGrabBag;
- for (const auto& rProp : std::as_const(aGrabBag))
- {
- OUString sValue = rProp.Value.get<OUString>();
- if (rProp.Name == "ooxml:CT_DataBinding_prefixMappings")
- AddToAttrList( m_pParagraphSdtPrDataBindingAttrs,
- FSNS( XML_w, XML_prefixMappings ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_DataBinding_xpath")
- AddToAttrList( m_pParagraphSdtPrDataBindingAttrs,
- FSNS( XML_w, XML_xpath ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_DataBinding_storeItemID")
- AddToAttrList( m_pParagraphSdtPrDataBindingAttrs,
- FSNS( XML_w, XML_storeItemID ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- }
- }
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_alias" && m_aParagraphSdtPrAlias.isEmpty())
- {
- if (!(aPropertyValue.Value >>= m_aParagraphSdtPrAlias))
- SAL_WARN("sw.ww8", "DocxAttributeOutput::ParaGrabBag: unexpected sdt alias value");
- m_aStartedParagraphSdtPrAlias = m_aParagraphSdtPrAlias;
- }
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_checkbox")
- {
- m_nParagraphSdtPrToken = FSNS( XML_w14, XML_checkbox );
- uno::Sequence<beans::PropertyValue> aGrabBag;
- aPropertyValue.Value >>= aGrabBag;
- for (const auto& rProp : std::as_const(aGrabBag))
- {
- OUString sValue = rProp.Value.get<OUString>();
- if (rProp.Name == "ooxml:CT_SdtCheckbox_checked")
- AddToAttrList( m_pParagraphSdtPrTokenChildren,
- FSNS( XML_w14, XML_checked ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_SdtCheckbox_checkedState")
- AddToAttrList( m_pParagraphSdtPrTokenChildren,
- FSNS( XML_w14, XML_checkedState ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_SdtCheckbox_uncheckedState")
- AddToAttrList( m_pParagraphSdtPrTokenChildren,
- FSNS( XML_w14, XML_uncheckedState ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- }
- }
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_id")
- m_bParagraphSdtHasId = true;
- else
- SAL_WARN("sw.ww8", "DocxAttributeOutput::ParaGrabBag: unhandled SdtPr grab bag property " << aPropertyValue.Name);
- }
+ m_aParagraphSdt.GetSdtParamsFromGrabBag(aGrabBagSdt);
+ m_aStartedParagraphSdtPrAlias = m_aParagraphSdt.m_aAlias;
}
else if (rGrabBagElement.first == "ParaCnfStyle")
{
@@ -9192,72 +9368,14 @@ void DocxAttributeOutput::CharGrabBag( const SfxGrabBagItem& rItem )
}
else if (rGrabBagElement.first == "SdtEndBefore")
{
- if (m_bStartedCharSdt)
+ if (m_aRunSdt.m_bStartedSdt)
m_bEndCharSdt = true;
}
else if (rGrabBagElement.first == "SdtPr" && FLY_NOT_PROCESSED != m_nStateOfFlyFrame )
{
const uno::Sequence<beans::PropertyValue> aGrabBagSdt =
rGrabBagElement.second.get< uno::Sequence<beans::PropertyValue> >();
- for (const beans::PropertyValue& aPropertyValue : aGrabBagSdt)
- {
- if (aPropertyValue.Name == "ooxml:CT_SdtPr_checkbox")
- {
- m_nRunSdtPrToken = FSNS( XML_w14, XML_checkbox );
- uno::Sequence<beans::PropertyValue> aGrabBag;
- aPropertyValue.Value >>= aGrabBag;
- for (const auto& rProp : std::as_const(aGrabBag))
- {
- OUString sValue = rProp.Value.get<OUString>();
- if (rProp.Name == "ooxml:CT_SdtCheckbox_checked")
- AddToAttrList( m_pRunSdtPrTokenChildren,
- FSNS( XML_w14, XML_checked ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_SdtCheckbox_checkedState")
- AddToAttrList( m_pRunSdtPrTokenChildren,
- FSNS( XML_w14, XML_checkedState ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_SdtCheckbox_uncheckedState")
- AddToAttrList( m_pRunSdtPrTokenChildren,
- FSNS( XML_w14, XML_uncheckedState ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- }
- }
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_dataBinding" && !m_pRunSdtPrDataBindingAttrs.is())
- {
- uno::Sequence<beans::PropertyValue> aGrabBag;
- aPropertyValue.Value >>= aGrabBag;
- for (const auto& rProp : std::as_const(aGrabBag))
- {
- OUString sValue = rProp.Value.get<OUString>();
- if (rProp.Name == "ooxml:CT_DataBinding_prefixMappings")
- AddToAttrList( m_pRunSdtPrDataBindingAttrs,
- FSNS( XML_w, XML_prefixMappings ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_DataBinding_xpath")
- AddToAttrList( m_pRunSdtPrDataBindingAttrs,
- FSNS( XML_w, XML_xpath ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- else if (rProp.Name == "ooxml:CT_DataBinding_storeItemID")
- AddToAttrList( m_pRunSdtPrDataBindingAttrs,
- FSNS( XML_w, XML_storeItemID ),
- OUStringToOString( sValue, RTL_TEXTENCODING_UTF8 ).getStr() );
- }
- }
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_alias" && m_aRunSdtPrAlias.isEmpty())
- {
- if (!(aPropertyValue.Value >>= m_aRunSdtPrAlias))
- SAL_WARN("sw.ww8", "DocxAttributeOutput::CharGrabBag: unexpected sdt alias value");
- }
- //do not overwrite the parent node.
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_text" && !m_pRunSdtPrTokenChildren.is())
- m_nRunSdtPrToken = FSNS( XML_w, XML_text );
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_id" && m_nRunSdtPrToken == 0)
- // only write id token as a marker if no other exist
- m_nRunSdtPrToken = FSNS( XML_w, XML_id );
- else if (aPropertyValue.Name == "ooxml:CT_SdtPr_citation")
- m_nRunSdtPrToken = FSNS( XML_w, XML_citation );
- }
+ m_aRunSdt.GetSdtParamsFromGrabBag(aGrabBagSdt);
}
else
SAL_INFO("sw.ww8", "DocxAttributeOutput::CharGrabBag: unhandled grab bag property " << rGrabBagElement.first);
@@ -9270,8 +9388,6 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, const FSHelperPtr
m_pSerializer( pSerializer ),
m_rDrawingML( *pDrawingML ),
m_bEndCharSdt(false),
- m_bStartedCharSdt(false),
- m_bStartedParaSdt(false),
m_endPageRef( false ),
m_pFootnotesList( new ::docx::FootnotesList() ),
m_pEndnotesList( new ::docx::FootnotesList() ),
@@ -9317,10 +9433,7 @@ DocxAttributeOutput::DocxAttributeOutput( DocxExport &rExport, const FSHelperPtr
m_nParaBeforeSpacing(0),
m_nParaAfterSpacing(0),
m_setFootnote(false)
- , m_nParagraphSdtPrToken(0)
- , m_nRunSdtPrToken(0)
, m_nStateOfFlyFrame( FLY_NOT_PROCESSED )
- , m_bParagraphSdtHasId(false)
{
// Push initial items to the RelId cache. In case the document contains no
// special streams (headers, footers, etc.) then these items are used
@@ -9383,26 +9496,4 @@ void DocxAttributeOutput::BulletDefinition(int nId, const Graphic& rGraphic, Siz
m_pSerializer->endElementNS(XML_w, XML_numPicBullet);
}
-void DocxAttributeOutput::AddToAttrList( rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrName, const sal_Char* sAttrValue )
-{
- AddToAttrList( pAttrList, 1, nAttrName, sAttrValue );
-}
-
-void DocxAttributeOutput::AddToAttrList( rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrs, ... )
-{
- if( !pAttrList.is() )
- pAttrList = FastSerializerHelper::createAttrList();
-
- va_list args;
- va_start( args, nAttrs );
- for( sal_Int32 i = 0; i<nAttrs; i++)
- {
- sal_Int32 nName = va_arg( args, sal_Int32 );
- const char* pValue = va_arg( args, const char* );
- if( pValue )
- pAttrList->add( nName, pValue );
- }
- va_end( args );
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index a7733d62209b..08b2aa9c8cf5 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -119,6 +119,37 @@ struct TableReference
}
};
+class SdtBlockHelper
+{
+public:
+ SdtBlockHelper()
+ : m_bHasId(false)
+ , m_bStartedSdt(false)
+ , m_nSdtPrToken(0)
+ {}
+
+ bool m_bHasId;
+ bool m_bStartedSdt;
+ rtl::Reference<sax_fastparser::FastAttributeList> m_pTokenChildren;
+ rtl::Reference<sax_fastparser::FastAttributeList> m_pTokenAttributes;
+ rtl::Reference<sax_fastparser::FastAttributeList> m_pTextAttrs;
+ rtl::Reference<sax_fastparser::FastAttributeList> m_pDataBindingAttrs;
+ OUString m_aColor;
+ OUString m_aPlaceHolderDocPart;
+ OUString m_aAlias;
+ sal_Int32 m_nSdtPrToken;
+
+ void DeleteAndResetTheLists();
+
+ void WriteSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer, bool bRunTextIsOn, bool bParagraphHasDrawing);
+ void WriteExtraParams(::sax_fastparser::FSHelperPtr& pSerializer);
+
+ /// Closes a currently open SDT block.
+ void EndSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer);
+
+ void GetSdtParamsFromGrabBag(const uno::Sequence<beans::PropertyValue>& aGrabBagSdt);
+};
+
/// The class that has handlers for various resource types when exporting as DOCX.
class DocxAttributeOutput : public AttributeOutputBase, public oox::vml::VMLTextExport, public oox::drawingml::DMLTextExport
{
@@ -708,16 +739,8 @@ private:
void WritePostponedDMLDrawing();
void WritePostponedCustomShape();
- void WriteSdtBlock(sal_Int32& nSdtPrToken,
- rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenChildren,
- rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrTokenAttributes,
- rtl::Reference<sax_fastparser::FastAttributeList>& pSdtPrDataBindingAttrs,
- OUString& rSdtPrAlias,
- bool bPara);
- /// Closes a currently open SDT block.
- void EndSdtBlock();
-
- void WriteFormDateStart(const OUString& sFullDate, const OUString& sDateFormat, const OUString& sLang);
+ void WriteFormDateStart(const OUString& sFullDate, const OUString& sDateFormat, const OUString& sLang, const uno::Sequence<beans::PropertyValue>& aGrabBagSdt);
+ void WriteSdtPlainText(const OUString& sValue, const uno::Sequence<beans::PropertyValue>& aGrabBagSdt);
void WriteSdtDropDownStart(OUString const& rName, OUString const& rSelected, uno::Sequence<OUString> const& rListItems);
void WriteSdtDropDownEnd(OUString const& rSelected, uno::Sequence<OUString> const& rListItems);
void WriteSdtEnd();
@@ -729,9 +752,6 @@ private:
void EndField_Impl( const SwTextNode* pNode, sal_Int32 nPos, FieldInfos& rInfos );
void DoWriteFieldRunProperties( const SwTextNode* pNode, sal_Int32 nPos, bool bWriteCombChars = false );
- static void AddToAttrList( rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nAttrName, const sal_Char* sAttrValue );
- static void AddToAttrList( rtl::Reference<sax_fastparser::FastAttributeList>& pAttrList, sal_Int32 nArgs, ... );
-
rtl::Reference<sax_fastparser::FastAttributeList> m_pFontsAttrList;
rtl::Reference<sax_fastparser::FastAttributeList> m_pEastAsianLayoutAttrList;
rtl::Reference<sax_fastparser::FastAttributeList> m_pCharLangAttrList;
@@ -740,10 +760,6 @@ private:
rtl::Reference<sax_fastparser::FastAttributeList> m_pHyperlinkAttrList;
/// If the current SDT around runs should be ended before the current run.
bool m_bEndCharSdt;
- /// If an SDT around runs is currently open.
- bool m_bStartedCharSdt;
- /// If an SDT around paragraphs is currently open.
- bool m_bStartedParaSdt;
/// Attributes of the run color
rtl::Reference<sax_fastparser::FastAttributeList> m_pColorAttrList;
/// Attributes of the paragraph background
@@ -954,24 +970,14 @@ private:
/// RelId <-> BitmapChecksum cache, similar to m_aRelIdCache, but used for non-Writer graphics, handled in oox.
std::stack< std::map<BitmapChecksum, OUString> > m_aSdrRelIdCache;
- /// members to control the existence of grabbagged SDT properties in the paragraph
- sal_Int32 m_nParagraphSdtPrToken;
- rtl::Reference<sax_fastparser::FastAttributeList> m_pParagraphSdtPrTokenChildren;
- rtl::Reference<sax_fastparser::FastAttributeList> m_pParagraphSdtPrTokenAttributes;
- rtl::Reference<sax_fastparser::FastAttributeList> m_pParagraphSdtPrDataBindingAttrs;
- /// members to control the existence of grabbagged SDT properties in the text run
- sal_Int32 m_nRunSdtPrToken;
+ SdtBlockHelper m_aParagraphSdt;
+ SdtBlockHelper m_aRunSdt;
+
/// State of the Fly at current position
FlyProcessingState m_nStateOfFlyFrame;
- rtl::Reference<sax_fastparser::FastAttributeList> m_pRunSdtPrTokenChildren;
- rtl::Reference<sax_fastparser::FastAttributeList> m_pRunSdtPrDataBindingAttrs;
- /// Value of the <w:alias> paragraph SDT element.
- OUString m_aParagraphSdtPrAlias;
+
/// Same as m_aParagraphSdtPrAlias, but its content is available till the SDT is closed.
OUString m_aStartedParagraphSdtPrAlias;
- OUString m_aRunSdtPrAlias;
- /// Currently paragraph SDT has a <w:id> child element.
- bool m_bParagraphSdtHasId;
std::map<SvxBoxItemLine, css::table::BorderLine2> m_aTableStyleConf;
@@ -1039,6 +1045,7 @@ struct DocxTableExportContext
ww8::WW8TableInfo::Pointer_t m_pTableInfo;
bool m_bTableCellOpen;
bool m_bStartedParaSdt;
+ bool m_bStartedRunSdt;
sal_uInt32 m_nTableDepth;
DocxTableExportContext(DocxAttributeOutput& rOutput) : m_rOutput(rOutput) { m_rOutput.pushToTableExportContext(*this); }
~DocxTableExportContext() { m_rOutput.popFromTableExportContext(*this); }
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index a48f4fb7b59e..20a021ab1dfe 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -34,6 +34,12 @@
#include <com/sun/star/xml/sax/Writer.hpp>
#include <com/sun/star/awt/XControlModel.hpp>
#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/io/XStreamListener.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/xml/xslt/XSLTTransformer.hpp>
#include <oox/token/namespaces.hxx>
#include <oox/token/tokens.hxx>
@@ -49,6 +55,8 @@
#include <map>
#include <algorithm>
+#include <condition_variable>
+#include <mutex>
#include <IMark.hxx>
#include <IDocumentSettingAccess.hxx>
@@ -1340,6 +1348,77 @@ void DocxExport::WriteGlossary()
}
}
+namespace {
+ class XsltTransformListener : public ::cppu::WeakImplHelper<io::XStreamListener>
+ {
+ public:
+ XsltTransformListener() : m_bDone(false) {}
+
+ void wait() {
+ std::unique_lock<std::mutex> g(m_mutex);
+ m_cond.wait(g, [this]() { return m_bDone; });
+ }
+
+ private:
+ std::mutex m_mutex;
+ std::condition_variable m_cond;
+ bool m_bDone;
+
+ virtual void SAL_CALL disposing(const lang::EventObject&) noexcept override {}
+ virtual void SAL_CALL started() noexcept override {}
+ virtual void SAL_CALL closed() noexcept override { notifyDone(); }
+ virtual void SAL_CALL terminated() noexcept override { notifyDone(); }
+ virtual void SAL_CALL error(const uno::Any& e) override
+ {
+ notifyDone(); // set on error too, otherwise main thread waits forever
+ SAL_WARN("sw.ww8", e);
+ }
+
+ void notifyDone() {
+ std::scoped_lock<std::mutex> g(m_mutex);
+ m_bDone = true;
+ m_cond.notify_all();
+ }
+ };
+}
+
+static void lcl_UpdateXmlValues(const SdtData& sdtData, const uno::Reference<css::io::XInputStream>& xInputStream, const uno::Reference<css::io::XOutputStream>& xOutputStream)
+{
+ uno::Sequence<uno::Any> aArgs{
+ // XSLT transformation stylesheet:
+ // - write all elements as is
+ // - but if element mathes sdtData.xpath, replace it's text content by sdtData.xpath
+ uno::Any(beans::NamedValue("StylesheetText", uno::Any(OUString("<?xml version=\"1.0\" encoding=\"UTF-8\"?> \
+<xsl:stylesheet\
+ xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\
+ " + sdtData.namespaces + "\
+ version=\"1.0\">\
+ <xsl:template match=\"@* | node()\">\
+ <xsl:copy>\
+ <xsl:apply-templates select=\"@* | node()\"/>\
+ </xsl:copy>\
+ </xsl:template>\
+ <xsl:template match = \"" + sdtData.xpath + "\">\
+ <xsl:copy>\
+ <xsl:text>" + sdtData.data + "</xsl:text>\
+ </xsl:copy>\
+ </xsl:template>\
+</xsl:stylesheet>\
+"))))
+ };
+
+ css::uno::Reference<css::xml::xslt::XXSLTTransformer> xTransformer =
+ css::xml::xslt::XSLTTransformer::create(comphelper::getProcessComponentContext(), aArgs);
+ xTransformer->setInputStream(xInputStream);
+ xTransformer->setOutputStream(xOutputStream);
+
+ rtl::Reference<XsltTransformListener> xListener = new XsltTransformListener();
+ xTransformer->addListener(xListener.get());
+
+ xTransformer->start();
+ xListener->wait();
+}
+
void DocxExport::WriteCustomXml()
{
uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
@@ -1375,10 +1454,54 @@ void DocxExport::WriteCustomXml()
uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDom, uno::UNO_QUERY );
uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
- writer->setOutputStream( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
- "application/xml" ) );
- serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
- uno::Sequence< beans::StringPair >() );
+
+ uno::Reference < css::io::XOutputStream > xOutStream = GetFilter().openFragmentStream("customXml/item" + OUString::number(j + 1) + ".xml",
+ "application/xml");
+ if (m_SdtData.size())
+ {
+ // There are some SDT blocks data with data bindings which can update some custom xml values
+ uno::Reference< io::XStream > xMemStream(
+ comphelper::getProcessComponentContext()->getServiceManager()->createInstanceWithContext("com.sun.star.comp.MemoryStream",
+ comphelper::getProcessComponentContext()),
+ uno::UNO_QUERY_THROW);
+
+ writer->setOutputStream(xMemStream->getOutputStream());
+
+ serializer->serialize(uno::Reference< xml::sax::XDocumentHandler >(writer, uno::UNO_QUERY_THROW),
+ uno::Sequence< beans::StringPair >());
+
+ uno::Reference< io::XStream > xXSLTInStream = xMemStream;
+ uno::Reference< io::XStream > xXSLTOutStream;
+ // Apply XSLT transformations for each SDT data binding
+ // Seems it is not possible to do this as one transformation: each data binding
+ // can have different namespaces, but with conflicting names (ns0, ns1, etc..)
+ for (size_t i = 0; i < m_SdtData.size(); i++)
+ {
+ if (i == m_SdtData.size() - 1)
+ {
+ // last transformation
+ lcl_UpdateXmlValues(m_SdtData[i], xXSLTInStream->getInputStream(), xOutStream);
+ }
+ else
+ {
+ xXSLTOutStream.set(
+ comphelper::getProcessComponentContext()->getServiceManager()->createInstanceWithContext("com.sun.star.comp.MemoryStream",
+ comphelper::getProcessComponentContext()),
+ uno::UNO_QUERY_THROW);
+ lcl_UpdateXmlValues(m_SdtData[i], xXSLTInStream->getInputStream(), xXSLTOutStream->getOutputStream());
+ // Use previous output as an input for next run
+ xXSLTInStream.set( xXSLTOutStream );
+ }
+ }
+
+ }
+ else
+ {
+ writer->setOutputStream(xOutStream);
+
+ serializer->serialize(uno::Reference< xml::sax::XDocumentHandler >(writer, uno::UNO_QUERY_THROW),
+ uno::Sequence< beans::StringPair >());
+ }
}
if (customXmlDomProps.is())
@@ -1591,7 +1714,8 @@ XFastAttributeListRef DocxExport::MainXmlNamespaces()
pAttr->add( FSNS( XML_xmlns, XML_mc ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_wp14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wp14)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_w14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(w14)), RTL_TEXTENCODING_UTF8).getStr() );
- pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14" );
+ pAttr->add( FSNS( XML_xmlns, XML_w15 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(w15)), RTL_TEXTENCODING_UTF8).getStr() );
+ pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14 w15" );
return XFastAttributeListRef( pAttr );
}
diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx
index 00b908dc7efa..dc2dba5b14cb 100644
--- a/sw/source/filter/ww8/docxexport.hxx
+++ b/sw/source/filter/ww8/docxexport.hxx
@@ -61,6 +61,14 @@ struct DocxSettingsData
bool trackRevisions; // Should 'Track Revisions' be set
};
+/// Data to keep and write to XMLs
+struct SdtData
+{
+ OUString namespaces;
+ OUString xpath;
+ OUString data;
+};
+
/// The class that does all the actual DOCX export-related work.
class DocxExport : public MSWordExportBase
{
@@ -114,6 +122,9 @@ class DocxExport : public MSWordExportBase
/// Pointer to the Frame of a floating table it is nested in
const ww8::Frame *m_pFloatingTableFrame = nullptr;
+ /// Storage for sdt data which need to be written to other XMLs
+ std::vector<SdtData> m_SdtData;
+
public:
DocxExportFilter& GetFilter() { return *m_pFilter; };
@@ -195,6 +206,11 @@ public:
virtual ExportFormat GetExportFormat() const override { return ExportFormat::DOCX; }
+ void AddSdtData(const OUString & namespaces, const OUString & xpath, const OUString & data)
+ {
+ m_SdtData.push_back({ namespaces, xpath, data });
+ }
+
protected:
/// Format-dependent part of the actual export.
virtual ErrCode ExportDocument_Impl() override;
diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx
index 7cacc4eb3173..dd0455674649 100644
--- a/sw/source/filter/ww8/docxsdrexport.cxx
+++ b/sw/source/filter/ww8/docxsdrexport.cxx
@@ -17,6 +17,7 @@
#include <editeng/boxitem.hxx>
#include <svx/svdogrp.hxx>
#include <oox/token/namespaces.hxx>
+#include <oox/token/relationship.hxx>
#include <textboxhelper.hxx>
#include <fmtanchr.hxx>
#include <fmtsrnd.hxx>
@@ -873,8 +874,21 @@ void DocxSdrExport::writeDMLDrawing(const SdrObject* pSdrObject, const SwFrameFo
&& pFrameFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
pDocPrAttrList->add(XML_hidden, OString::number(1).getStr());
- sax_fastparser::XFastAttributeListRef xDocPrAttrListRef(pDocPrAttrList);
- pFS->singleElementNS(XML_wp, XML_docPr, xDocPrAttrListRef);
+
+ pFS->startElementNS(XML_wp, XML_docPr, pDocPrAttrList);
+ OUString sHyperlink = pSdrObject->getHyperlink();
+ if (!sHyperlink.isEmpty())
+ {
+ OUString sRelId = m_pImpl->getExport().GetFilter().addRelation(
+ pFS->getOutputStream(), oox::getRelationship(Relationship::HYPERLINK),
+ oox::drawingml::URLTransformer().getTransformedString(sHyperlink),
+ oox::drawingml::URLTransformer().isExternalURL(sHyperlink));
+ pFS->singleElementNS(
+ XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId.toUtf8().getStr(),
+ FSNS(XML_xmlns, XML_a),
+ m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)).toUtf8());
+ }
+ pFS->endElementNS(XML_wp, XML_docPr);
uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
const char* pNamespace = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape";
@@ -1212,7 +1226,24 @@ void DocxSdrExport::writeDMLTextFrame(ww8::Frame const* pParentFrame, int nAncho
pDocPrAttrList->add(
XML_name, OUStringToOString(rFrameFormat.GetName(), RTL_TEXTENCODING_UTF8).getStr());
sax_fastparser::XFastAttributeListRef xDocPrAttrListRef(pDocPrAttrList);
- pFS->singleElementNS(XML_wp, XML_docPr, xDocPrAttrListRef);
+ pFS->startElementNS(XML_wp, XML_docPr, pDocPrAttrList);
+
+ OUString sHyperlink;
+ if (xPropertySet.is())
+ xPropertySet->getPropertyValue("HyperLinkURL") >>= sHyperlink;
+ if (!sHyperlink.isEmpty())
+ {
+ OUString sRelId = m_pImpl->getExport().GetFilter().addRelation(
+ pFS->getOutputStream(), oox::getRelationship(Relationship::HYPERLINK),
+ oox::drawingml::URLTransformer().getTransformedString(sHyperlink),
+ oox::drawingml::URLTransformer().isExternalURL(sHyperlink));
+ pFS->singleElementNS(
+ XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId.toUtf8().getStr(),
+ FSNS(XML_xmlns, XML_a),
+ m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)).toUtf8());
+ }
+
+ pFS->endElementNS(XML_wp, XML_docPr);
pFS->startElementNS(XML_a, XML_graphic, FSNS(XML_xmlns, XML_a),
m_pImpl->getExport().GetFilter().getNamespaceURL(OOX_NS(dml)).toUtf8());
@@ -1493,6 +1524,16 @@ void DocxSdrExport::writeVMLTextFrame(ww8::Frame const* pParentFrame, bool bText
if (!sAnchorId.isEmpty())
m_pImpl->getFlyAttrList()->addNS(XML_w14, XML_anchorId,
OUStringToOString(sAnchorId, RTL_TEXTENCODING_UTF8));
+
+ uno::Reference<drawing::XShape> xShape(const_cast<SdrObject*>(pObject)->getUnoShape(),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ OUString sHyperlink;
+ if (xShapeProps.is())
+ xShapeProps->getPropertyValue("HyperLinkURL") >>= sHyperlink;
+ if (!sHyperlink.isEmpty())
+ m_pImpl->getFlyAttrList()->add(XML_href,
+ OUStringToOString(sHyperlink, RTL_TEXTENCODING_UTF8));
}
sax_fastparser::XFastAttributeListRef xFlyAttrList(m_pImpl->getFlyAttrList().get());
m_pImpl->getFlyAttrList().clear();
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 6313472bf728..cebf1ffcf430 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -109,7 +109,7 @@ static OString OutTBLBorderLine(RtfExport const& rExport, const editeng::SvxBord
{
case SvxBorderLineStyle::SOLID:
{
- if (DEF_LINE_WIDTH_0 == pLine->GetWidth())
+ if (SvxBorderLineWidth::Hairline == pLine->GetWidth())
aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRHAIR);
else
aRet.append(OOO_STRING_SVTOOLS_RTF_BRDRS);
diff --git a/sw/source/filter/ww8/wrtw8num.cxx b/sw/source/filter/ww8/wrtw8num.cxx
index d0514482e5e1..05e860caec74 100644
--- a/sw/source/filter/ww8/wrtw8num.cxx
+++ b/sw/source/filter/ww8/wrtw8num.cxx
@@ -61,6 +61,17 @@ SwNumRule* MSWordExportBase::DuplicateNumRuleImpl(const SwNumRule *pRule)
return pMyNumRule;
}
+sal_uInt16 MSWordExportBase::DuplicateNumRule(const SwNumRule* pRule, sal_uInt8 nLevel, sal_uInt16 nVal)
+{
+ SwNumRule* const pMyNumRule = DuplicateNumRuleImpl(pRule);
+
+ SwNumFormat aNumFormat(pMyNumRule->Get(nLevel));
+ aNumFormat.SetStart(nVal);
+ pMyNumRule->Set(nLevel, aNumFormat);
+
+ return GetNumberingId(*pMyNumRule);
+}
+
// multiple SwList can be based on the same SwNumRule; ensure one w:abstractNum
// per SwList
sal_uInt16 MSWordExportBase::DuplicateAbsNum(OUString const& rListId,
diff --git a/sw/source/filter/ww8/wrtw8sty.cxx b/sw/source/filter/ww8/wrtw8sty.cxx
index 8a315444a133..6228526a88ba 100644
--- a/sw/source/filter/ww8/wrtw8sty.cxx
+++ b/sw/source/filter/ww8/wrtw8sty.cxx
@@ -151,13 +151,13 @@ MSWordStyles::MSWordStyles( MSWordExportBase& rExport, bool bListStyles )
m_rExport.m_pDoc->GetFootnoteInfo().GetAnchorCharFormat( *m_rExport.m_pDoc );
m_rExport.m_pDoc->GetFootnoteInfo().GetCharFormat( *m_rExport.m_pDoc );
}
- sal_uInt16 nAlloc = WW8_RESERVED_SLOTS + m_rExport.m_pDoc->GetCharFormats()->size() - 1 +
+ sal_uInt32 nAlloc = WW8_RESERVED_SLOTS + m_rExport.m_pDoc->GetCharFormats()->size() - 1 +
m_rExport.m_pDoc->GetTextFormatColls()->size() - 1 +
(bListStyles ? m_rExport.m_pDoc->GetNumRuleTable().size() - 1 : 0);
+ nAlloc = std::min<sal_uInt32>(nAlloc, MSWORD_MAX_STYLES_LIMIT);
// somewhat generous ( free for up to 15 )
- m_pFormatA.reset( new SwFormat*[ nAlloc ] );
- memset( m_pFormatA.get(), 0, nAlloc * sizeof( SwFormat* ) );
+ m_aFormatA.resize(nAlloc, nullptr);
memset( m_aHeadingParagraphStyles, -1 , MAXLEVEL * sizeof( sal_uInt16));
BuildStylesTable();
@@ -173,7 +173,7 @@ sal_uInt16 MSWordStyles::GetSlot( const SwFormat* pFormat ) const
{
sal_uInt16 n;
for ( n = 0; n < m_nUsedSlots; n++ )
- if ( m_pFormatA[n] == pFormat )
+ if ( m_aFormatA[n] == pFormat )
return n;
return 0xfff; // 0xfff: WW: zero
}
@@ -282,19 +282,19 @@ void MSWordStyles::BuildStylesTable()
const SwCharFormats& rArr = *m_rExport.m_pDoc->GetCharFormats(); // first CharFormat
// the default character style ( 0 ) will not be outputted !
- for( size_t n = 1; n < rArr.size(); n++ )
+ for( size_t n = 1; n < rArr.size() && m_nUsedSlots < MSWORD_MAX_STYLES_LIMIT; n++ )
{
SwCharFormat* pFormat = rArr[n];
- m_pFormatA[ BuildGetSlot( *pFormat ) ] = pFormat;
+ m_aFormatA[ BuildGetSlot( *pFormat ) ] = pFormat;
}
const SwTextFormatColls& rArr2 = *m_rExport.m_pDoc->GetTextFormatColls(); // then TextFormatColls
// the default character style ( 0 ) will not be outputted !
- for( size_t n = 1; n < rArr2.size(); n++ )
+ for( size_t n = 1; n < rArr2.size() && m_nUsedSlots < MSWORD_MAX_STYLES_LIMIT; n++ )
{
SwTextFormatColl* pFormat = rArr2[n];
sal_uInt16 nId = BuildGetSlot( *pFormat ) ;
- m_pFormatA[ nId ] = pFormat;
+ m_aFormatA[ nId ] = pFormat;
if ( pFormat->IsAssignedToListLevelOfOutlineStyle() )
{
int nLvl = pFormat->GetAssignedOutlineStyleLevel() ;
@@ -307,7 +307,7 @@ void MSWordStyles::BuildStylesTable()
return;
const SwNumRuleTable& rNumRuleTable = m_rExport.m_pDoc->GetNumRuleTable();
- for (size_t i = 0; i < rNumRuleTable.size(); ++i)
+ for (size_t i = 0; i < rNumRuleTable.size() && m_nUsedSlots < MSWORD_MAX_STYLES_LIMIT; ++i)
{
const SwNumRule* pNumRule = rNumRuleTable[i];
if (pNumRule->IsAutoRule() || pNumRule->GetName().startsWith("WWNum"))
@@ -347,8 +347,8 @@ void MSWordStyles::BuildStyleIds()
for (sal_uInt16 n = 1; n < m_nUsedSlots; ++n)
{
OUString aName;
- if(m_pFormatA[n])
- aName = m_pFormatA[n]->GetName();
+ if (m_aFormatA[n])
+ aName = m_aFormatA[n]->GetName();
else if (m_aNumRules.find(n) != m_aNumRules.end())
aName = m_aNumRules[n]->GetName();
@@ -612,8 +612,8 @@ void MSWordStyles::OutputStyle( SwFormat* pFormat, sal_uInt16 nPos )
for ( int nSuffix = 0; ; ++nSuffix ) {
bool clash=false;
for ( sal_uInt16 n = 1; n < m_nUsedSlots; ++n )
- if ( m_pFormatA[n] &&
- m_pFormatA[n]->GetName().equalsIgnoreAsciiCase(aName) )
+ if ( m_aFormatA[n] &&
+ m_aFormatA[n]->GetName().equalsIgnoreAsciiCase(aName) )
{
clash = true;
break;
@@ -702,7 +702,7 @@ void MSWordStyles::OutputStylesTable()
if (m_aNumRules.find(n) != m_aNumRules.end())
OutputStyle(m_aNumRules[n], n);
else
- OutputStyle( m_pFormatA[n], n );
+ OutputStyle(m_aFormatA[n], n);
}
m_rExport.AttrOutput().EndStyles( m_nUsedSlots );
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index 8d4add7b34bf..86899e1dba88 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -3673,7 +3673,6 @@ MSWordExportBase::MSWordExportBase( SwDoc *pDocument, std::shared_ptr<SwUnoCurso
, m_nOrigRedlineFlags(RedlineFlags::NONE)
, m_bOrigShowChanges(true)
, m_pCurrentPageDesc(nullptr)
- , m_bPrevTextNodeIsEmpty(false)
, m_bFirstTOCNodeWithSection(false)
, m_pChpIter(nullptr)
, m_pAtn(nullptr)
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index 9356b87bd86f..0e1cfea0a51a 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -496,7 +496,6 @@ public:
std::vector<aBookmarkPair> m_aImplicitBookmarks;
ww8::Frames m_aFrames; // The floating frames in this document
const SwPageDesc *m_pCurrentPageDesc;
- bool m_bPrevTextNodeIsEmpty;
bool m_bFirstTOCNodeWithSection;
std::unique_ptr<WW8_WrPlcPn> m_pPapPlc;
std::unique_ptr<WW8_WrPlcPn> m_pChpPlc;
@@ -657,6 +656,7 @@ public:
/// List is set to restart at a particular value so for export make a
/// completely new list based on this one and export that instead,
/// which duplicates words behaviour in this respect.
+ sal_uInt16 DuplicateNumRule(const SwNumRule* pRule, sal_uInt8 nLevel, sal_uInt16 nVal);
SwNumRule * DuplicateNumRuleImpl(const SwNumRule *pRule);
/// check if a new abstractNum is needed for this list
@@ -758,7 +758,7 @@ public:
static sal_uLong GetSectionLineNo( const SfxItemSet* pSet, const SwNode& rNd );
/// Start new section.
- void OutputSectionBreaks( const SfxItemSet *pSet, const SwNode& rNd, bool isCellOpen = false, bool isTextNodeEmpty = false);
+ void OutputSectionBreaks( const SfxItemSet *pSet, const SwNode& rNd, bool isCellOpen = false );
/// Write section properties.
///
@@ -1576,7 +1576,7 @@ class MSWordStyles
{
MSWordExportBase& m_rExport;
sal_uInt16 m_aHeadingParagraphStyles[MAXLEVEL];
- std::unique_ptr<SwFormat*[]> m_pFormatA; ///< Slot <-> Character and paragraph style array (0 for list styles).
+ std::vector<SwFormat*> m_aFormatA; ///< Slot <-> Character and paragraph style array (0 for list styles).
sal_uInt16 m_nUsedSlots;
bool const m_bListStyles; ///< If list styles are requested to be exported as well.
std::map<sal_uInt16, const SwNumRule*> m_aNumRules; ///< Slot <-> List style map.
@@ -1627,7 +1627,7 @@ public:
/// Get styleId of the nId-th style (nId is its position in pFormatA).
OString const & GetStyleId(sal_uInt16 nId) const;
- const SwFormat* GetSwFormat(sal_uInt16 nId) const { return m_pFormatA[nId]; }
+ const SwFormat* GetSwFormat(sal_uInt16 nId) const { return m_aFormatA[nId]; }
/// Get numbering rule of the nId-th style
const SwNumRule* GetSwNumRule(sal_uInt16 nId) const;
sal_uInt16 GetHeadingParagraphStyleId(sal_uInt16 nLevel) const { return m_aHeadingParagraphStyles[ nLevel ]; }
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 0b2c6527c0ea..cfd58d9d643d 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -441,7 +441,7 @@ bool MSWordExportBase::SetCurrentPageDescFromNode(const SwNode &rNd)
* because that one only exits once for CHP and PAP and therefore end up in
* the wrong one.
*/
-void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode& rNd, bool isCellOpen, bool isTextNodeEmpty)
+void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode& rNd, bool isCellOpen )
{
if ( m_bStyDef || m_bOutKF || m_bInWriteEscher || m_bOutPageDescs )
return;
@@ -462,14 +462,10 @@ void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode
// Even if pAktPageDesc != pPageDesc ,it might be because of the different header & footer types.
if (m_pCurrentPageDesc != pPageDesc)
{
- if ( ( isCellOpen && ( m_pCurrentPageDesc->GetName() != pPageDesc->GetName() )) ||
- ( isTextNodeEmpty || m_bPrevTextNodeIsEmpty ))
+ if (isCellOpen && ( m_pCurrentPageDesc->GetName() != pPageDesc->GetName() ))
{
/* Do not output a section break in the following scenarios.
1) Table cell is open and page header types are different
- 2) PageBreak is present but text node has no string - it is an empty node.
- 3) If the previous node was an empty text node and current node is a non empty text node or vice versa.
- 4) If previous node and current node both are empty text nodes.
Converting a page break to section break would cause serious issues while importing
the RT files with different first page being set.
*/
@@ -572,8 +568,6 @@ void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode
{
bNewPageDesc |= SetCurrentPageDescFromNode( rNd );
}
- if( isTextNodeEmpty )
- bNewPageDesc = false;
}
if ( !bNewPageDesc )
AttrOutput().OutputItem( *pItem );
@@ -620,7 +614,6 @@ void MSWordExportBase::OutputSectionBreaks( const SfxItemSet *pSet, const SwNode
PrepareNewPageDesc( pSet, rNd, pPgDesc, m_pCurrentPageDesc );
}
m_bBreakBefore = false;
- m_bPrevTextNodeIsEmpty = isTextNodeEmpty ;
}
// #i76300#
@@ -3649,6 +3642,13 @@ void AttributeOutputBase::ParaNumRule( const SwNumRuleItem& rNumRule )
}
}
}
+ else if (pTextNd->IsListRestart())
+ {
+ sal_uInt16 nStartWith = static_cast<sal_uInt16>(pTextNd->GetActualListStartValue());
+ nNumId = GetExport().DuplicateNumRule(pRule, nLvl, nStartWith);
+ if (USHRT_MAX != nNumId)
+ ++nNumId;
+ }
}
else
{
@@ -4315,7 +4315,7 @@ WW8_BRCVer9 WW8Export::TranslateBorderLine(const SvxBorderLine& rLine,
{
case SvxBorderLineStyle::SOLID:
{
- if ( rLine.GetWidth( ) == DEF_LINE_WIDTH_0 )
+ if ( rLine.GetWidth( ) == SvxBorderLineWidth::Hairline )
brcType = 5;
else
brcType = 1;
diff --git a/sw/source/filter/ww8/ww8par.cxx b/sw/source/filter/ww8/ww8par.cxx
index f5bdacffe32d..41beb52670ff 100644
--- a/sw/source/filter/ww8/ww8par.cxx
+++ b/sw/source/filter/ww8/ww8par.cxx
@@ -1992,7 +1992,7 @@ void SwWW8ImplReader::ImportDopTypography(const WW8DopTypography &rTypo)
* Footnotes and Endnotes
*/
WW8ReaderSave::WW8ReaderSave(SwWW8ImplReader* pRdr ,WW8_CP nStartCp) :
- maTmpPos(*pRdr->m_pPaM->GetPoint()),
+ mxTmpPos(pRdr->m_rDoc.CreateUnoCursor(*pRdr->m_pPaM->GetPoint())),
mxOldStck(std::move(pRdr->m_xCtrlStck)),
mxOldAnchorStck(std::move(pRdr->m_xAnchorStck)),
mxOldRedlines(std::move(pRdr->m_xRedlineStack)),
@@ -2076,12 +2076,21 @@ void WW8ReaderSave::Restore( SwWW8ImplReader* pRdr )
pRdr->m_xRedlineStack->closeall(*pRdr->m_pPaM->GetPoint());
pRdr->m_aFrameRedlines.emplace(std::move(pRdr->m_xRedlineStack));
+
+ // ofz#37322 drop m_pLastAnchorPos during RedlineStack dtor and restore it afterwards to the same
+ // place, or somewhere close if that place got destroyed
+ std::shared_ptr<SwUnoCursor> xLastAnchorCursor(pRdr->m_pLastAnchorPos ? pRdr->m_rDoc.CreateUnoCursor(*pRdr->m_pLastAnchorPos) : nullptr);
+ pRdr->m_pLastAnchorPos.reset();
+
pRdr->m_xRedlineStack = std::move(mxOldRedlines);
+ if (xLastAnchorCursor)
+ pRdr->m_pLastAnchorPos.reset(new SwPosition(*xLastAnchorCursor->GetPoint()));
+
pRdr->DeleteAnchorStack();
pRdr->m_xAnchorStck = std::move(mxOldAnchorStck);
- *pRdr->m_pPaM->GetPoint() = maTmpPos;
+ *pRdr->m_pPaM->GetPoint() = GetStartPos();
if (mxOldPlcxMan != pRdr->m_xPlcxMan)
pRdr->m_xPlcxMan = mxOldPlcxMan;
diff --git a/sw/source/filter/ww8/ww8par.hxx b/sw/source/filter/ww8/ww8par.hxx
index 74953aa2016c..f98853d82295 100644
--- a/sw/source/filter/ww8/ww8par.hxx
+++ b/sw/source/filter/ww8/ww8par.hxx
@@ -589,7 +589,7 @@ class WW8ReaderSave
{
private:
WW8PLCFxSaveAll maPLCFxSave;
- SwPosition const maTmpPos;
+ std::shared_ptr<SwUnoCursor> mxTmpPos;
std::deque<bool> maOldApos;
std::deque<WW8FieldEntry> maOldFieldStack;
std::unique_ptr<SwWW8FltControlStack> mxOldStck;
@@ -617,7 +617,7 @@ private:
public:
WW8ReaderSave(SwWW8ImplReader* pRdr, WW8_CP nStart=-1);
void Restore(SwWW8ImplReader* pRdr);
- const SwPosition &GetStartPos() const { return maTmpPos; }
+ const SwPosition &GetStartPos() const { return *mxTmpPos->GetPoint(); }
};
enum class eF_ResT { OK, TEXT, TAGIGN, READ_FSPA };
@@ -922,6 +922,14 @@ public:
explicit wwExtraneousParas(SwDoc &rDoc) : m_rDoc(rDoc) {}
~wwExtraneousParas() { delete_all_from_doc(); }
void insert(SwTextNode *pTextNode) { m_aTextNodes.insert(pTextNode); }
+ void check_anchor_destination(SwTextNode *pTextNode)
+ {
+ auto it = m_aTextNodes.find(pTextNode);
+ if (it == m_aTextNodes.end())
+ return;
+ SAL_WARN("sw.ww8", "It is unexpected to anchor something in a para scheduled for removal");
+ m_aTextNodes.erase(it);
+ }
void delete_all_from_doc();
};
diff --git a/sw/source/filter/ww8/ww8par2.cxx b/sw/source/filter/ww8/ww8par2.cxx
index 6edc842e48ee..026b0ead213c 100644
--- a/sw/source/filter/ww8/ww8par2.cxx
+++ b/sw/source/filter/ww8/ww8par2.cxx
@@ -2749,8 +2749,17 @@ void WW8TabDesc::FinishSwTable()
{
m_pIo->m_xRedlineStack->closeall(*m_pIo->m_pPaM->GetPoint());
m_pIo->m_aFrameRedlines.emplace(std::move(m_pIo->m_xRedlineStack));
+
+ // ofz#38011 drop m_pLastAnchorPos during RedlineStack dtor and restore it afterwards to the same
+ // place, or somewhere close if that place got destroyed
+ std::shared_ptr<SwUnoCursor> xLastAnchorCursor(m_pIo->m_pLastAnchorPos ? m_pIo->m_rDoc.CreateUnoCursor(*m_pIo->m_pLastAnchorPos) : nullptr);
+ m_pIo->m_pLastAnchorPos.reset();
+
m_pIo->m_xRedlineStack = std::move(mxOldRedlineStack);
+ if (xLastAnchorCursor)
+ m_pIo->m_pLastAnchorPos.reset(new SwPosition(*xLastAnchorCursor->GetPoint()));
+
WW8DupProperties aDup(m_pIo->m_rDoc,m_pIo->m_xCtrlStck.get());
m_pIo->m_xCtrlStck->SetAttr( *m_pIo->m_pPaM->GetPoint(), 0, false);
diff --git a/sw/source/filter/ww8/ww8par6.cxx b/sw/source/filter/ww8/ww8par6.cxx
index 1e68d7a592b4..ca2ddc28fd1f 100644
--- a/sw/source/filter/ww8/ww8par6.cxx
+++ b/sw/source/filter/ww8/ww8par6.cxx
@@ -2451,6 +2451,9 @@ bool SwWW8ImplReader::StartApo(const ApoTestResults &rApo, const WW8_TablePos *p
}
else
{
+ // ofz#34749 we shouldn't anchor anything into an 'extra' paragraph scheduled for
+ // removal at end of import, but check if that scenario is happening
+ m_aExtraneousParas.check_anchor_destination(m_pPaM->GetNode().GetTextNode());
m_xSFlyPara->pFlyFormat = m_rDoc.MakeFlySection(WW8SwFlyPara::eAnchor,
m_pPaM->GetPoint(), &aFlySet);
OSL_ENSURE(m_xSFlyPara->pFlyFormat->GetAnchor().GetAnchorId() ==
diff --git a/sw/source/filter/xml/XMLRedlineImportHelper.cxx b/sw/source/filter/xml/XMLRedlineImportHelper.cxx
index bfd4e488fcb8..0a0c75bc9816 100644
--- a/sw/source/filter/xml/XMLRedlineImportHelper.cxx
+++ b/sw/source/filter/xml/XMLRedlineImportHelper.cxx
@@ -33,6 +33,9 @@
#include <IDocumentStylePoolAccess.hxx>
#include <tools/datetime.hxx>
#include <poolfmt.hxx>
+#include <fmtanchr.hxx>
+#include <ftnidx.hxx>
+#include <txtftn.hxx>
#include <unoredline.hxx>
#include <DocumentRedlineManager.hxx>
#include "xmlimp.hxx"
@@ -571,6 +574,73 @@ inline bool XMLRedlineImportHelper::IsReady(const RedlineInfo* pRedline)
!pRedline->bNeedsAdjustment );
}
+/// recursively check if rPos or its anchor (if in fly or footnote) is in redline section
+static auto RecursiveContains(SwStartNode const& rRedlineSection, SwNode const& rPos) -> bool
+{
+ if (rRedlineSection.GetIndex() <= rPos.GetIndex()
+ && rPos.GetIndex() <= rRedlineSection.EndOfSectionIndex())
+ {
+ return true;
+ }
+ // loop to iterate "up" in the node tree and find an anchored XText
+ for (SwStartNode const* pStartNode = rPos.StartOfSectionNode();
+ pStartNode != nullptr && pStartNode->GetIndex() != 0;
+ pStartNode = pStartNode->StartOfSectionNode())
+ {
+ switch (pStartNode->GetStartNodeType())
+ {
+ case SwNormalStartNode:
+ case SwTableBoxStartNode:
+ continue;
+ break;
+ case SwFlyStartNode:
+ {
+ SwFrameFormat const*const pFormat(pStartNode->GetFlyFormat());
+ assert(pFormat);
+ SwFormatAnchor const& rAnchor(pFormat->GetAnchor());
+ if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE)
+ {
+ return false;
+ }
+ else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_FLY)
+ { // anchor is on a start node, avoid skipping it:
+ pStartNode = rAnchor.GetContentAnchor()->nNode.GetNode().GetStartNode();
+ assert(pStartNode);
+ // pass the next node to recursive call - it will call
+ // call StartOfSectionNode on it and go back to pStartNode
+ SwNodeIndex const next(*pStartNode, +1);
+ return RecursiveContains(rRedlineSection, next.GetNode());
+ }
+ else
+ {
+ return RecursiveContains(rRedlineSection, rAnchor.GetContentAnchor()->nNode.GetNode());
+ }
+ }
+ break;
+ case SwFootnoteStartNode:
+ { // sigh ... need to search
+ for (SwTextFootnote const*const pFootnote : rRedlineSection.GetDoc()->GetFootnoteIdxs())
+ {
+ if (pStartNode == pFootnote->GetStartNode()->GetNode().GetStartNode())
+ {
+ return RecursiveContains(rRedlineSection, pFootnote->GetTextNode());
+ }
+ }
+ assert(false);
+ }
+ break;
+ case SwHeaderStartNode:
+ case SwFooterStartNode:
+ return false; // headers aren't anchored
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ return false;
+}
+
void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo)
{
OSL_ENSURE(nullptr != pRedlineInfo, "need redline info");
@@ -649,6 +719,17 @@ void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo)
}
}
}
+ else if (pRedlineInfo->pContentIndex != nullptr
+ // should be enough to check 1 position of aPaM bc CheckNodesRange() above
+ && RecursiveContains(*pRedlineInfo->pContentIndex->GetNode().GetStartNode(), aPaM.GetPoint()->nNode.GetNode()))
+ {
+ SAL_WARN("sw.xml", "Recursive change tracking, removing");
+ // reuse aPaM to remove it from nodes that will be deleted
+ *aPaM.GetPoint() = SwPosition(pRedlineInfo->pContentIndex->GetNode());
+ aPaM.SetMark();
+ *aPaM.GetMark() = SwPosition(*pRedlineInfo->pContentIndex->GetNode().EndOfSectionNode());
+ pDoc->getIDocumentContentOperations().DeleteRange(aPaM);
+ }
else
{
// regular file loading: insert redline
diff --git a/sw/source/filter/xml/xmlexp.hxx b/sw/source/filter/xml/xmlexp.hxx
index 22e6a42368a7..a5abc5baf15f 100644
--- a/sw/source/filter/xml/xmlexp.hxx
+++ b/sw/source/filter/xml/xmlexp.hxx
@@ -23,6 +23,8 @@
#include <xmloff/xmlexp.hxx>
#include "xmlitmap.hxx"
#include <xmloff/xmltoken.hxx>
+
+#include <optional>
#include <vector>
class SwDoc;
@@ -73,7 +75,8 @@ class SwXMLExport : public SvXMLExport
SwXMLTableInfo_Impl& rTableInfo,
bool bTop=false );
- void ExportFormat( const SwFormat& rFormat, enum ::xmloff::token::XMLTokenEnum eClass );
+ void ExportFormat(const SwFormat& rFormat, enum ::xmloff::token::XMLTokenEnum eClass,
+ ::std::optional<OUString> const oStyleName);
void ExportTableFormat( const SwFrameFormat& rFormat, sal_uInt32 nAbsWidth );
void ExportTableColumnStyle( const SwXMLTableColumn_Impl& rCol );
diff --git a/sw/source/filter/xml/xmlfmte.cxx b/sw/source/filter/xml/xmlfmte.cxx
index 209cdd5a3904..b7aa337eede3 100644
--- a/sw/source/filter/xml/xmlfmte.cxx
+++ b/sw/source/filter/xml/xmlfmte.cxx
@@ -46,7 +46,8 @@ using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::lang;
using namespace ::xmloff::token;
-void SwXMLExport::ExportFormat( const SwFormat& rFormat, enum XMLTokenEnum eFamily )
+void SwXMLExport::ExportFormat(const SwFormat& rFormat, enum XMLTokenEnum eFamily,
+ ::std::optional<OUString> const oStyleName)
{
// <style:style ...>
CheckAttrList();
@@ -57,11 +58,14 @@ void SwXMLExport::ExportFormat( const SwFormat& rFormat, enum XMLTokenEnum eFami
return;
OSL_ENSURE( eFamily != XML_TOKEN_INVALID, "family must be specified" );
// style:name="..."
+ assert(oStyleName || (eFamily != XML_TABLE_ROW && eFamily != XML_TABLE_CELL));
bool bEncoded = false;
- AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, EncodeStyleName(
- rFormat.GetName(), &bEncoded ) );
+ OUString const name(oStyleName ? *oStyleName : rFormat.GetName());
+ AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, EncodeStyleName(name, &bEncoded));
if( bEncoded )
- AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, rFormat.GetName() );
+ {
+ AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, name);
+ }
if( eFamily != XML_TOKEN_INVALID )
AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, eFamily );
diff --git a/sw/source/filter/xml/xmliteme.cxx b/sw/source/filter/xml/xmliteme.cxx
index b307a5c10872..8972bd14a51e 100644
--- a/sw/source/filter/xml/xmliteme.cxx
+++ b/sw/source/filter/xml/xmliteme.cxx
@@ -219,7 +219,7 @@ void SwXMLExport::ExportTableFormat( const SwFrameFormat& rFormat, sal_uInt32 nA
{
static_cast<SwXMLTableItemMapper_Impl *>(m_pTableItemMapper.get())
->SetAbsWidth( nAbsWidth );
- ExportFormat( rFormat, XML_TABLE );
+ ExportFormat(rFormat, XML_TABLE, {});
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmlithlp.cxx b/sw/source/filter/xml/xmlithlp.cxx
index 6dc8f3830e77..f3d8df67e1e6 100644
--- a/sw/source/filter/xml/xmlithlp.cxx
+++ b/sw/source/filter/xml/xmlithlp.cxx
@@ -73,11 +73,10 @@ const struct SvXMLEnumMapEntry<sal_uInt16> psXML_NamedBorderWidths[] =
};
// mapping tables to map external xml input to internal box line widths
-const sal_uInt16 aBorderWidths[] =
-{
- DEF_LINE_WIDTH_0,
- DEF_LINE_WIDTH_5,
- DEF_LINE_WIDTH_1,
+const sal_uInt16 aBorderWidths[] = {
+ SvxBorderLineWidth::Hairline,
+ SvxBorderLineWidth::VeryThin,
+ SvxBorderLineWidth::Thin
};
bool sw_frmitems_parseXMLBorder( const OUString& rValue,
diff --git a/sw/source/filter/xml/xmltble.cxx b/sw/source/filter/xml/xmltble.cxx
index 6a4fa1c9902b..d840509ecdc0 100644
--- a/sw/source/filter/xml/xmltble.cxx
+++ b/sw/source/filter/xml/xmltble.cxx
@@ -179,13 +179,18 @@ class SwXMLTableFrameFormatsSort_Impl
{
private:
SwXMLFrameFormats_Impl aFormatList;
+ SwXMLTextParagraphExport::FormatMap & m_rFormatMap;
+
public:
- bool AddRow( SwFrameFormat& rFrameFormat, const OUString& rNamePrefix, sal_uInt32 nLine );
- bool AddCell( SwFrameFormat& rFrameFormat, const OUString& rNamePrefix,
+ SwXMLTableFrameFormatsSort_Impl(SwXMLTextParagraphExport::FormatMap & rFormatMap)
+ : m_rFormatMap(rFormatMap)
+ {}
+ ::std::optional<OUString> AddRow(SwFrameFormat& rFrameFormat, const OUString& rNamePrefix, sal_uInt32 nLine );
+ ::std::optional<OUString> AddCell(SwFrameFormat& rFrameFormat, const OUString& rNamePrefix,
sal_uInt32 nCol, sal_uInt32 nRow, bool bTop );
};
-bool SwXMLTableFrameFormatsSort_Impl::AddRow( SwFrameFormat& rFrameFormat,
+::std::optional<OUString> SwXMLTableFrameFormatsSort_Impl::AddRow(SwFrameFormat& rFrameFormat,
const OUString& rNamePrefix,
sal_uInt32 nLine )
{
@@ -206,10 +211,12 @@ bool SwXMLTableFrameFormatsSort_Impl::AddRow( SwFrameFormat& rFrameFormat,
// empty styles have not to be exported
if( !pFrameSize && !pBrush && !pRowSplit )
- return false;
+ {
+ m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>()); // empty just to enable assert
+ return {};
+ }
// order is: -/brush, size/-, size/brush
- bool bInsert = true;
SwXMLFrameFormats_Impl::iterator i;
for( i = aFormatList.begin(); i < aFormatList.end(); ++i )
{
@@ -272,19 +279,19 @@ bool SwXMLTableFrameFormatsSort_Impl::AddRow( SwFrameFormat& rFrameFormat,
continue;
// found!
- rFrameFormat.SetName( pTestFormat->GetName() );
- bInsert = false;
- break;
+ auto const oName(m_rFormatMap.find(pTestFormat)->second);
+ assert(oName);
+ m_rFormatMap.emplace(&rFrameFormat, oName);
+ return {};
}
- if( bInsert )
{
- rFrameFormat.SetName( rNamePrefix + "." + OUString::number(nLine+1) );
+ OUString const name(rNamePrefix + "." + OUString::number(nLine+1));
+ m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>(name));
if ( i != aFormatList.end() ) ++i;
aFormatList.insert( i, &rFrameFormat );
+ return ::std::optional<OUString>(name);
}
-
- return bInsert;
}
static OUString lcl_xmltble_appendBoxPrefix(const OUString& rNamePrefix,
@@ -301,7 +308,7 @@ static OUString lcl_xmltble_appendBoxPrefix(const OUString& rNamePrefix,
+ "." + OUString::number(nRow + 1);
}
-bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat& rFrameFormat,
+::std::optional<OUString> SwXMLTableFrameFormatsSort_Impl::AddCell(SwFrameFormat& rFrameFormat,
const OUString& rNamePrefix,
sal_uInt32 nCol, sal_uInt32 nRow, bool bTop )
{
@@ -336,7 +343,10 @@ bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat& rFrameFormat,
// empty styles have not to be exported
if( !pVertOrient && !pBrush && !pBox && !pNumFormat && !pFrameDir && !pAttCnt )
- return false;
+ {
+ m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>()); // empty just to enable assert
+ return {};
+ }
// order is: -/-/-/num,
// -/-/box/-, -/-/box/num,
@@ -344,7 +354,6 @@ bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat& rFrameFormat,
// vert/-/-/-, vert/-/-/num, vert/-/box/-, ver/-/box/num,
// vert/brush/-/-, vert/brush/-/num, vert/brush/box/-,
// vert/brush/box/num
- bool bInsert = true;
SwXMLFrameFormats_Impl::iterator i;
for( i = aFormatList.begin(); i < aFormatList.end(); ++i )
{
@@ -462,19 +471,19 @@ bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat& rFrameFormat,
continue;
// found!
- rFrameFormat.SetName( pTestFormat->GetName() );
- bInsert = false;
- break;
+ auto const oName(m_rFormatMap.find(pTestFormat)->second);
+ assert(oName);
+ m_rFormatMap.emplace(&rFrameFormat, oName);
+ return {};
}
- if( bInsert )
{
- rFrameFormat.SetName( lcl_xmltble_appendBoxPrefix( rNamePrefix, nCol, nRow, bTop ) );
+ OUString const name(lcl_xmltble_appendBoxPrefix(rNamePrefix, nCol, nRow, bTop));
+ m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>(name));
if ( i != aFormatList.end() ) ++i;
aFormatList.insert( i, &rFrameFormat );
+ return ::std::optional<OUString>(name);
}
-
- return bInsert;
}
class SwXMLTableInfo_Impl
@@ -483,10 +492,21 @@ class SwXMLTableInfo_Impl
Reference<XTextSection> m_xBaseSection;
bool m_bBaseSectionValid;
sal_uInt32 const m_nPrefix;
+ SwXMLTextParagraphExport::FormatMap const& m_rLineFormats;
+ SwXMLTextParagraphExport::FormatMap const& m_rBoxFormats;
public:
- inline SwXMLTableInfo_Impl( const SwTable *pTable, sal_uInt16 nPrefix );
+ inline SwXMLTableInfo_Impl( const SwTable *pTable, sal_uInt16 nPrefix,
+ SwXMLTextParagraphExport::FormatMap const& rLineFormats,
+ SwXMLTextParagraphExport::FormatMap const& rBoxFormats)
+ : m_pTable(pTable)
+ , m_bBaseSectionValid(false)
+ , m_nPrefix(nPrefix)
+ , m_rLineFormats(rLineFormats)
+ , m_rBoxFormats(rBoxFormats)
+ {
+ }
const SwTable *GetTable() const { return m_pTable; }
const SwFrameFormat *GetTableFormat() const { return m_pTable->GetFrameFormat(); }
@@ -496,15 +516,10 @@ public:
inline void SetBaseSection( const Reference < XTextSection >& rBase );
/// The namespace (table or loext) that should be used for the elements.
sal_uInt16 GetPrefix() const { return m_nPrefix; }
+ SwXMLTextParagraphExport::FormatMap const& GetLineFormats() const { return m_rLineFormats; }
+ SwXMLTextParagraphExport::FormatMap const& GetBoxFormats() const { return m_rBoxFormats; }
};
-inline SwXMLTableInfo_Impl::SwXMLTableInfo_Impl(const SwTable *pTable, sal_uInt16 nPrefix) :
- m_pTable(pTable),
- m_bBaseSectionValid(false),
- m_nPrefix(nPrefix)
-{
-}
-
inline void SwXMLTableInfo_Impl::SetBaseSection(
const Reference < XTextSection >& rBaseSection )
{
@@ -638,8 +653,10 @@ void SwXMLExport::ExportTableLinesAutoStyles( const SwTableLines& rLines,
SwTableLine *pLine = rLines[nLine];
SwFrameFormat *pFrameFormat = pLine->GetFrameFormat();
- if( rExpRows.AddRow( *pFrameFormat, rNamePrefix, nLine ) )
- ExportFormat( *pFrameFormat, XML_TABLE_ROW );
+ if (auto oNew = rExpRows.AddRow(*pFrameFormat, rNamePrefix, nLine))
+ {
+ ExportFormat(*pFrameFormat, XML_TABLE_ROW, oNew);
+ }
const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
const size_t nBoxes = rBoxes.size();
@@ -666,9 +683,11 @@ void SwXMLExport::ExportTableLinesAutoStyles( const SwTableLines& rLines,
if( pBoxSttNd )
{
SwFrameFormat *pFrameFormat2 = pBox->GetFrameFormat();
- if( rExpCells.AddCell( *pFrameFormat2, rNamePrefix, nOldCol, nLine,
+ if (auto oNew = rExpCells.AddCell(*pFrameFormat2, rNamePrefix, nOldCol, nLine,
bTop) )
- ExportFormat( *pFrameFormat2, XML_TABLE_CELL );
+ {
+ ExportFormat(*pFrameFormat2, XML_TABLE_CELL, oNew);
+ }
Reference < XCell > xCell = SwXCell::CreateXCell(
const_cast<SwFrameFormat *>(rTableInfo.GetTableFormat()),
@@ -714,8 +733,13 @@ void SwXMLExport::ExportTableLinesAutoStyles( const SwTableLines& rLines,
}
}
-void SwXMLExport::ExportTableAutoStyles( const SwTableNode& rTableNd )
+void SwXMLExport::ExportTableAutoStyles(const SwTableNode& rTableNd)
{
+ auto & rFormats(static_cast<SwXMLTextParagraphExport *>(GetTextParagraphExport().get())->GetTableFormats());
+ auto const it(rFormats.find(&rTableNd));
+ assert(it != rFormats.end());
+ SwXMLTextParagraphExport::FormatMap & rRowFormats(it->second.first);
+ SwXMLTextParagraphExport::FormatMap & rBoxFormats(it->second.second);
const SwTable& rTable = rTableNd.GetTable();
const SwFrameFormat *pTableFormat = rTable.GetFrameFormat();
@@ -743,9 +767,9 @@ void SwXMLExport::ExportTableAutoStyles( const SwTableNode& rTableNd )
ExportTableFormat( *pTableFormat, nAbsWidth );
SwXMLTableColumnsSortByWidth_Impl aExpCols;
- SwXMLTableFrameFormatsSort_Impl aExpRows;
- SwXMLTableFrameFormatsSort_Impl aExpCells;
- SwXMLTableInfo_Impl aTableInfo( &rTable, XML_NAMESPACE_TABLE );
+ SwXMLTableFrameFormatsSort_Impl aExpRows(rRowFormats);
+ SwXMLTableFrameFormatsSort_Impl aExpCells(rBoxFormats);
+ SwXMLTableInfo_Impl aTableInfo(&rTable, XML_NAMESPACE_TABLE, rRowFormats, rBoxFormats);
ExportTableLinesAutoStyles( rTable.GetTabLines(), nAbsWidth, nBaseWidth,
pTableFormat->GetName(), aExpCols, aExpRows, aExpCells,
aTableInfo, true);
@@ -763,10 +787,12 @@ void SwXMLExport::ExportTableBox( const SwTableBox& rBox,
const SwFrameFormat *pFrameFormat = rBox.GetFrameFormat();
if( pFrameFormat )
{
- const OUString& sName = pFrameFormat->GetName();
- if( !sName.isEmpty() )
+ auto const it(rTableInfo.GetBoxFormats().find(pFrameFormat));
+ assert(it != rTableInfo.GetBoxFormats().end());
+ if (it->second)
{
- AddAttribute( XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(sName) );
+ assert(!it->second->isEmpty());
+ AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(*it->second));
}
}
}
@@ -896,10 +922,12 @@ void SwXMLExport::ExportTableLine( const SwTableLine& rLine,
const SwFrameFormat *pFrameFormat = rLine.GetFrameFormat();
if( pFrameFormat )
{
- const OUString& sName = pFrameFormat->GetName();
- if( !sName.isEmpty() )
+ auto const it(rTableInfo.GetLineFormats().find(pFrameFormat));
+ assert(it != rTableInfo.GetLineFormats().end());
+ if (it->second)
{
- AddAttribute( XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(sName) );
+ assert(!it->second->isEmpty());
+ AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(*it->second));
}
}
@@ -1051,29 +1079,6 @@ void SwXMLExport::ExportTableLines( const SwTableLines& rLines,
delete pLines;
}
-static void lcl_xmltble_ClearName_Line( SwTableLine* pLine );
-
-static void lcl_xmltble_ClearName_Box( SwTableBox* pBox )
-{
- if( !pBox->GetSttNd() )
- {
- for( SwTableLine* pLine : pBox->GetTabLines() )
- lcl_xmltble_ClearName_Line( pLine );
- }
- else
- {
- SwFrameFormat *pFrameFormat = pBox->GetFrameFormat();
- if( pFrameFormat && !pFrameFormat->GetName().isEmpty() )
- pFrameFormat->SetName( OUString() );
- }
-}
-
-void lcl_xmltble_ClearName_Line( SwTableLine* pLine )
-{
- for( SwTableBox* pBox : pLine->GetTabBoxes() )
- lcl_xmltble_ClearName_Box( pBox );
-}
-
void SwXMLExport::ExportTable( const SwTableNode& rTableNd )
{
const SwTable& rTable = rTableNd.GetTable();
@@ -1132,15 +1137,16 @@ void SwXMLExport::ExportTable( const SwTableNode& rTableNd )
XML_DDE_SOURCE, true, false);
}
- SwXMLTableInfo_Impl aTableInfo( &rTable, nPrefix );
+ auto const& rFormats(static_cast<SwXMLTextParagraphExport const*>(GetTextParagraphExport().get())->GetTableFormats());
+ auto const it(rFormats.find(&rTableNd));
+ assert(it != rFormats.end());
+ SwXMLTableInfo_Impl aTableInfo(&rTable, nPrefix, it->second.first, it->second.second);
ExportTableLines( rTable.GetTabLines(), aTableInfo, rTable.GetRowsToRepeat() );
-
- for( SwTableLine *pLine : const_cast<SwTable &>(rTable).GetTabLines() )
- lcl_xmltble_ClearName_Line( pLine );
}
}
void SwXMLTextParagraphExport::exportTableAutoStyles() {
+ // note: maTableNodes is used here only to keep the iteration order as before
for (const auto* pTableNode : maTableNodes)
{
static_cast<SwXMLExport&>(GetExport()).ExportTableAutoStyles(*pTableNode);
@@ -1187,6 +1193,7 @@ void SwXMLTextParagraphExport::exportTable(
&& (bExportStyles || !pFormat->GetDoc()->IsInHeaderFooter(aIdx)))
{
maTableNodes.push_back(pTableNd);
+ m_TableFormats.emplace(pTableNd, ::std::make_pair(SwXMLTextParagraphExport::FormatMap(), SwXMLTextParagraphExport::FormatMap()));
// Collect all tables inside cells of this table, too
const auto aCellNames = pXTable->getCellNames();
for (const OUString& rCellName : aCellNames)
diff --git a/sw/source/filter/xml/xmltexte.hxx b/sw/source/filter/xml/xmltexte.hxx
index 4432e4ce0166..78e0271384c3 100644
--- a/sw/source/filter/xml/xmltexte.hxx
+++ b/sw/source/filter/xml/xmltexte.hxx
@@ -23,6 +23,9 @@
#include <xmloff/txtparae.hxx>
#include <tools/globname.hxx>
+#include <optional>
+#include <unordered_map>
+
#define XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE "vnd.sun.star.GraphicObject:"
class SwXMLExport;
@@ -41,6 +44,10 @@ class SwXMLTextParagraphExport : public XMLTextParagraphExport
// Collected autostyles for use in exportTextAutoStyles
std::vector<const SwTableNode*> maTableNodes;
+public:
+ typedef ::std::unordered_map<SwFrameFormat const*, ::std::optional<OUString>> FormatMap;
+private:
+ ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, FormatMap>> m_TableFormats;
static SwNoTextNode *GetNoTextNode(
const css::uno::Reference < css::beans::XPropertySet >& rPropSet );
@@ -63,6 +70,11 @@ public:
SwXMLExport& rExp,
SvXMLAutoStylePoolP& rAutoStylePool );
virtual ~SwXMLTextParagraphExport() override;
+
+ ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, FormatMap>> const&
+ GetTableFormats() const { return m_TableFormats; }
+ ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, FormatMap>> &
+ GetTableFormats() { return m_TableFormats; }
};
#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLTEXTE_HXX
diff --git a/sw/source/filter/xml/xmltexti.cxx b/sw/source/filter/xml/xmltexti.cxx
index 788bec5c2d47..caf300f239c6 100644
--- a/sw/source/filter/xml/xmltexti.cxx
+++ b/sw/source/filter/xml/xmltexti.cxx
@@ -853,9 +853,14 @@ uno::Reference< XPropertySet > SwXMLTextImportHelper::createAndInsertFloatingFra
uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY );
if ( xSet.is() )
{
+ OUString sHRef = URIHelper::SmartRel2Abs(
+ INetURLObject( GetXMLImport().GetBaseURL() ), rHRef );
+
+ if (INetURLObject(sHRef).IsExoticProtocol())
+ GetXMLImport().NotifyMacroEventRead();
+
xSet->setPropertyValue("FrameURL",
- makeAny( URIHelper::SmartRel2Abs(
- INetURLObject( GetXMLImport().GetBaseURL() ), rHRef ) ) );
+ makeAny( sHRef ) );
xSet->setPropertyValue("FrameName",
makeAny( rName ) );
diff --git a/sw/source/ui/dbui/dbinsdlg.cxx b/sw/source/ui/dbui/dbinsdlg.cxx
index 4ead5f41f49b..64fd72b9a253 100644
--- a/sw/source/ui/dbui/dbinsdlg.cxx
+++ b/sw/source/ui/dbui/dbinsdlg.cxx
@@ -1290,7 +1290,7 @@ void SwInsertDBColAutoPilot::DataToDoc( const Sequence<Any>& rSelection,
}
pField->SetInitialized();
- rSh.Insert( *pField );
+ rSh.InsertField2( *pField );
}
break;
@@ -1354,7 +1354,7 @@ void SwInsertDBColAutoPilot::DataToDoc( const Sequence<Any>& rSelection,
break;
if( m_xRbAsField->get_active() )
- rSh.Insert( aNxtDBField );
+ rSh.InsertField2( aNxtDBField );
if( !rSh.IsSttPara() )
rSh.SwEditShell::SplitNode();
diff --git a/sw/source/ui/fldui/flddb.cxx b/sw/source/ui/fldui/flddb.cxx
index 01b9065cd36e..937c2b265c71 100644
--- a/sw/source/ui/fldui/flddb.cxx
+++ b/sw/source/ui/fldui/flddb.cxx
@@ -299,12 +299,18 @@ void SwFieldDBPage::TypeHdl(const weld::TreeView* pBox)
OUString sColumnName;
if (nTypeId == SwFieldTypesEnum::Database)
{
- aData = static_cast<SwDBField*>(GetCurField())->GetDBData();
- sColumnName = static_cast<SwDBFieldType*>(GetCurField()->GetTyp())->GetColumnName();
+ if (auto const*const pField = dynamic_cast<SwDBField*>(GetCurField()))
+ {
+ aData = pField->GetDBData();
+ sColumnName = static_cast<SwDBFieldType*>(GetCurField()->GetTyp())->GetColumnName();
+ }
}
else
{
- aData = static_cast<SwDBNameInfField*>(GetCurField())->GetDBData(pSh->GetDoc());
+ if (auto *const pField = dynamic_cast<SwDBNameInfField*>(GetCurField()))
+ {
+ aData = pField->GetDBData(pSh->GetDoc());
+ }
}
m_xDatabaseTLB->Select(aData.sDataSource, aData.sCommand, sColumnName);
}
diff --git a/sw/source/ui/fldui/flddinf.cxx b/sw/source/ui/fldui/flddinf.cxx
index 92d263a6efd1..4fe4d8b41aaa 100644
--- a/sw/source/ui/fldui/flddinf.cxx
+++ b/sw/source/ui/fldui/flddinf.cxx
@@ -99,10 +99,13 @@ void SwFieldDokInfPage::Reset(const SfxItemSet* )
if (IsFieldEdit())
{
const SwField* pCurField = GetCurField();
- nSubType = static_cast<const SwDocInfoField*>(pCurField)->GetSubType() & 0xff;
+ nSubType = pCurField->GetSubType() & 0xff;
if( nSubType == DI_CUSTOM )
{
- m_sOldCustomFieldName = static_cast<const SwDocInfoField*>(pCurField)->GetName();
+ if (auto const pField = dynamic_cast<SwDocInfoField const*>(pCurField))
+ {
+ m_sOldCustomFieldName = pField->GetName();
+ }
}
m_xFormatLB->SetAutomaticLanguage(pCurField->IsAutomaticLanguage());
SwWrtShell *pSh = GetWrtShell();
@@ -311,12 +314,17 @@ IMPL_LINK_NOARG(SwFieldDokInfPage, SubTypeHdl, weld::TreeView&, void)
bEnable = true;
}
- sal_uInt32 nFormat = IsFieldEdit() ? static_cast<SwDocInfoField*>(GetCurField())->GetFormat() : 0;
+ sal_uInt32 nFormat = 0;
- sal_uInt16 nOldSubType = IsFieldEdit() ? (static_cast<SwDocInfoField*>(GetCurField())->GetSubType() & 0xff00) : 0;
+ sal_uInt16 nOldSubType = 0;
if (IsFieldEdit())
{
+ if (auto const pField = dynamic_cast<SwDocInfoField const*>(GetCurField()))
+ {
+ nFormat = pField->GetFormat();
+ nOldSubType = pField->GetSubType() & 0xff00;
+ }
nPos = m_xSelectionLB->get_selected_index();
if (nPos != -1)
{
@@ -367,10 +375,14 @@ sal_Int32 SwFieldDokInfPage::FillSelectionLB(sal_uInt16 nSubType)
sal_uInt16 nSize = 0;
sal_Int32 nSelPos = -1;
- sal_uInt16 nExtSubType = IsFieldEdit() ? (static_cast<SwDocInfoField*>(GetCurField())->GetSubType() & 0xff00) : 0;
+ sal_uInt16 nExtSubType = 0;
if (IsFieldEdit())
{
+ if (auto const pField = dynamic_cast<SwDocInfoField const*>(GetCurField()))
+ {
+ nExtSubType = pField->GetSubType() & 0xff00;
+ }
m_xFixedCB->set_active((nExtSubType & DI_SUB_FIXED) != 0);
nExtSubType = ((nExtSubType & ~DI_SUB_FIXED) >> 8) - 1;
}
diff --git a/sw/source/ui/fldui/fldref.cxx b/sw/source/ui/fldui/fldref.cxx
index 95935b115177..d13ed61cd550 100644
--- a/sw/source/ui/fldui/fldref.cxx
+++ b/sw/source/ui/fldui/fldref.cxx
@@ -330,9 +330,15 @@ IMPL_LINK_NOARG(SwFieldRefPage, TypeHdl, weld::TreeView&, void)
break;
case REF_SEQUENCEFLD:
- sName = static_cast<SwGetRefField*>(GetCurField())->GetSetRefName();
+ {
+ SwGetRefField const*const pRefField(dynamic_cast<SwGetRefField*>(GetCurField()));
+ if (pRefField)
+ {
+ sName = pRefField->GetSetRefName();
+ }
nFlag = REFFLDFLAG;
break;
+ }
}
if (m_xTypeLB->find_text(sName) == -1) // reference to deleted mark
@@ -468,7 +474,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
SwWrtShell *pSh = GetWrtShell();
if(!pSh)
pSh = ::GetActiveWrtShell();
- SwGetRefField* pRefField = static_cast<SwGetRefField*>(GetCurField());
+ SwGetRefField const*const pRefField(dynamic_cast<SwGetRefField*>(GetCurField()));
const sal_uInt16 nTypeId = m_xTypeLB->get_id(GetTypeSel()).toUInt32();
OUString sOldSel;
@@ -479,7 +485,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
if (nSelectionSel != -1)
sOldSel = m_xSelectionLB->get_text(nSelectionSel);
}
- if (IsFieldEdit() && sOldSel.isEmpty())
+ if (IsFieldEdit() && pRefField && sOldSel.isEmpty())
sOldSel = OUString::number( pRefField->GetSeqNo() + 1 );
m_xSelectionLB->freeze();
@@ -528,7 +534,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
}
}
}
- if (IsFieldEdit())
+ if (IsFieldEdit() && pRefField)
sOldSel = pRefField->GetSetRefName();
}
else if (nTypeId == REFFLDFLAG_FOOTNOTE)
@@ -543,7 +549,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
{
m_xSelectionLB->append_text( aArr[ n ].sDlgEntry );
}
- if (IsFieldEdit() && pRefField->GetSeqNo() == aArr[ n ].nSeqNo)
+ if (IsFieldEdit() && pRefField && pRefField->GetSeqNo() == aArr[ n ].nSeqNo)
sOldSel = aArr[n].sDlgEntry;
}
}
@@ -559,7 +565,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
{
m_xSelectionLB->append_text( aArr[ n ].sDlgEntry );
}
- if (IsFieldEdit() && pRefField->GetSeqNo() == aArr[ n ].nSeqNo)
+ if (IsFieldEdit() && pRefField && pRefField->GetSeqNo() == aArr[ n ].nSeqNo)
sOldSel = aArr[n].sDlgEntry;
}
}
@@ -583,9 +589,9 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
OUString sId(OUString::number(nOutlIdx));
m_xSelectionToolTipLB->append(sId,
pIDoc->getOutlineText(nOutlIdx, pSh->GetLayout(), true, true, false));
- if ( ( IsFieldEdit() &&
- pRefField->GetReferencedTextNode() == maOutlineNodes[nOutlIdx] ) ||
- mpSavedSelectedTextNode == maOutlineNodes[nOutlIdx] )
+ if ((IsFieldEdit() && pRefField
+ && pRefField->GetReferencedTextNode() == maOutlineNodes[nOutlIdx])
+ || mpSavedSelectedTextNode == maOutlineNodes[nOutlIdx])
{
m_sSelectionToolTipLBId = sId;
sOldSel.clear();
@@ -618,9 +624,9 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
OUString sId(OUString::number(nNumItemIdx));
m_xSelectionToolTipLB->append(sId,
pIDoc->getListItemText(*maNumItems[nNumItemIdx], *pSh->GetLayout()));
- if ( ( IsFieldEdit() &&
- pRefField->GetReferencedTextNode() == maNumItems[nNumItemIdx]->GetTextNode() ) ||
- mpSavedSelectedTextNode == maNumItems[nNumItemIdx]->GetTextNode() )
+ if ((IsFieldEdit() && pRefField
+ && pRefField->GetReferencedTextNode() == maNumItems[nNumItemIdx]->GetTextNode())
+ || mpSavedSelectedTextNode == maNumItems[nNumItemIdx]->GetTextNode())
{
m_sSelectionToolTipLBId = sId;
sOldSel.clear();
@@ -655,12 +661,12 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
{
m_xSelectionLB->append_text( aArr[ n ].sDlgEntry );
}
- if (IsFieldEdit() && sOldSel.isEmpty() &&
+ if (IsFieldEdit() && pRefField && sOldSel.isEmpty() &&
aArr[ n ].nSeqNo == pRefField->GetSeqNo())
sOldSel = aArr[ n ].sDlgEntry;
}
- if (IsFieldEdit() && sOldSel.isEmpty())
+ if (IsFieldEdit() && pRefField && sOldSel.isEmpty())
sOldSel = OUString::number( pRefField->GetSeqNo() + 1);
}
}
@@ -678,7 +684,7 @@ void SwFieldRefPage::UpdateSubType(const OUString& filterString)
}
}
- if (IsFieldEdit())
+ if (IsFieldEdit() && pRefField)
sOldSel = pRefField->GetSetRefName();
}
@@ -950,7 +956,7 @@ bool SwFieldRefPage::FillItemSet(SfxItemSet* )
}
}
- SwGetRefField* pRefField = static_cast<SwGetRefField*>(GetCurField());
+ SwGetRefField const*const pRefField(dynamic_cast<SwGetRefField*>(GetCurField()));
if (REFFLDFLAG & nTypeId)
{
@@ -980,10 +986,10 @@ bool SwFieldRefPage::FillItemSet(SfxItemSet* )
{
aVal = OUString::number( aArr[nPos].nSeqNo );
- if (IsFieldEdit() && aArr[nPos].nSeqNo == pRefField->GetSeqNo())
+ if (IsFieldEdit() && pRefField && aArr[nPos].nSeqNo == pRefField->GetSeqNo())
bModified = true; // can happen with fields of which the references were deleted
}
- else if (IsFieldEdit())
+ else if (IsFieldEdit() && pRefField)
aVal = OUString::number( pRefField->GetSeqNo() );
}
else if (REFFLDFLAG_ENDNOTE == nTypeId) // endnotes
@@ -1001,10 +1007,10 @@ bool SwFieldRefPage::FillItemSet(SfxItemSet* )
{
aVal = OUString::number( aArr[nPos].nSeqNo );
- if (IsFieldEdit() && aArr[nPos].nSeqNo == pRefField->GetSeqNo())
+ if (IsFieldEdit() && pRefField && aArr[nPos].nSeqNo == pRefField->GetSeqNo())
bModified = true; // can happen with fields of which the reference was deleted
}
- else if (IsFieldEdit())
+ else if (IsFieldEdit() && pRefField)
aVal = OUString::number( pRefField->GetSeqNo() );
}
// #i83479#
@@ -1069,10 +1075,10 @@ bool SwFieldRefPage::FillItemSet(SfxItemSet* )
{
aVal = OUString::number( aArr[nPos].nSeqNo );
- if (IsFieldEdit() && aArr[nPos].nSeqNo == pRefField->GetSeqNo())
+ if (IsFieldEdit() && pRefField && aArr[nPos].nSeqNo == pRefField->GetSeqNo())
bModified = true; // can happen with fields of which the reference was deleted
}
- else if (IsFieldEdit())
+ else if (IsFieldEdit() && pRefField)
aVal = OUString::number( pRefField->GetSeqNo() );
}
}
diff --git a/sw/source/ui/fldui/fldtdlg.cxx b/sw/source/ui/fldui/fldtdlg.cxx
index 8c1bb998fb85..084c4d66c8c7 100644
--- a/sw/source/ui/fldui/fldtdlg.cxx
+++ b/sw/source/ui/fldui/fldtdlg.cxx
@@ -110,9 +110,16 @@ void SwFieldDlg::Close()
{
if (m_bClosing)
return;
- m_pBindings->GetDispatcher()->
+ const SfxPoolItem* pResult = m_pBindings->GetDispatcher()->
Execute(m_bDataBaseMode ? FN_INSERT_FIELD_DATA_ONLY : FN_INSERT_FIELD,
SfxCallMode::SYNCHRON|SfxCallMode::RECORD);
+ if (!pResult)
+ {
+ // If Execute action did fail for whatever reason, this means that request
+ // to close did fail or wasn't delivered to SwTextShell::ExecField().
+ // Just explicitly close dialog in this case.
+ SfxTabDialogController::EndDialog();
+ }
}
void SwFieldDlg::Initialize(SfxChildWinInfo const *pInfo)
@@ -179,8 +186,9 @@ void SwFieldDlg::ReInitDlg()
if(!pActiveView)
return;
const SwWrtShell& rSh = pActiveView->GetWrtShell();
- GetOKButton().set_sensitive(!rSh.IsReadOnlyAvailable() ||
- !rSh.HasReadonlySel());
+ GetOKButton().set_sensitive(( !rSh.IsReadOnlyAvailable()
+ || !rSh.HasReadonlySel())
+ && !SwCursorShell::PosInsideInputField(*rSh.GetCursor()->GetPoint()));
ReInitTabPage("document");
ReInitTabPage("variables");
@@ -212,8 +220,10 @@ void SwFieldDlg::Activate()
{
bool bHtmlMode = (::GetHtmlMode(static_cast<SwDocShell*>(SfxObjectShell::Current())) & HTMLMODE_ON) != 0;
const SwWrtShell& rSh = pView->GetWrtShell();
- GetOKButton().set_sensitive(!rSh.IsReadOnlyAvailable() ||
- !rSh.HasReadonlySel());
+ GetOKButton().set_sensitive(( !rSh.IsReadOnlyAvailable()
+ || !rSh.HasReadonlySel())
+ && !SwCursorShell::PosInsideInputField(*rSh.GetCursor()->GetPoint()));
+
ReInitTabPage("variables", true);
@@ -233,9 +243,12 @@ void SwFieldDlg::EnableInsert(bool bEnable)
OSL_ENSURE(pView, "no view found");
if( !pView ||
(pView->GetWrtShell().IsReadOnlyAvailable() &&
- pView->GetWrtShell().HasReadonlySel()) )
+ pView->GetWrtShell().HasReadonlySel())
+ || SwCursorShell::PosInsideInputField(*pView->GetWrtShell().GetCursor()->GetPoint()))
+ {
bEnable = false;
}
+ }
GetOKButton().set_sensitive(bEnable);
}
diff --git a/sw/source/ui/misc/bookmark.cxx b/sw/source/ui/misc/bookmark.cxx
index 7267f5a059f4..649c1e806e79 100644
--- a/sw/source/ui/misc/bookmark.cxx
+++ b/sw/source/ui/misc/bookmark.cxx
@@ -103,7 +103,7 @@ IMPL_LINK_NOARG(SwInsertBookmarkDlg, DeleteHdl, weld::Button&, void)
sw::mark::IMark* pBookmark = reinterpret_cast<sw::mark::IMark*>(m_xBookmarksBox->get_id(rEntry).toInt64());
OUString sRemoved = pBookmark->GetName();
IDocumentMarkAccess* const pMarkAccess = rSh.getIDocumentMarkAccess();
- pMarkAccess->deleteMark(pMarkAccess->findMark(sRemoved));
+ pMarkAccess->deleteMark(pMarkAccess->findMark(sRemoved), false);
SfxRequest aReq(rSh.GetView().GetViewFrame(), FN_DELETE_BOOKMARK);
aReq.AppendItem(SfxStringItem(FN_DELETE_BOOKMARK, sRemoved));
aReq.Done();
@@ -440,10 +440,10 @@ void BookmarkTable::InsertBookmark(sw::mark::IMark* pMark)
else if (bPulling && !bPulledAll)
sBookmarkNodeText = "..." + sBookmarkNodeText;
+ const OUString& sHideCondition = pBookmark->GetHideCondition();
OUString sHidden = SwResId(STR_BOOKMARK_NO);
- if (pBookmark->IsHidden())
+ if (pBookmark->IsHidden() || !sHideCondition.isEmpty())
sHidden = SwResId(STR_BOOKMARK_YES);
- const OUString& sHideCondition = pBookmark->GetHideCondition();
OUString sPageNum = OUString::number(SwPaM(pMark->GetMarkStart()).GetPageNum());
int nRow = m_xControl->n_children();
m_xControl->append(OUString::number(reinterpret_cast<sal_Int64>(pMark)), sPageNum);
diff --git a/sw/source/uibase/config/StoredChapterNumbering.cxx b/sw/source/uibase/config/StoredChapterNumbering.cxx
index 5c94fc56110b..eea0c260bbf5 100644
--- a/sw/source/uibase/config/StoredChapterNumbering.cxx
+++ b/sw/source/uibase/config/StoredChapterNumbering.cxx
@@ -152,7 +152,7 @@ public:
SwXNumberingRules::SetPropertiesToNumFormat(
aNumberFormat,
charStyleName,
- nullptr, nullptr, nullptr, nullptr,
+ nullptr, nullptr, nullptr, nullptr, nullptr,
props);
SwNumRulesWithName *const pRules(GetOrCreateRules());
pRules->SetNumFormat(nIndex, aNumberFormat, charStyleName);
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index f6e5990b1b3d..244e95de182c 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -2580,7 +2580,7 @@ bool SwTransferable::PasteDDE( TransferableDataHelper& rData,
{
// insert
SwDDEField aSwDDEField( pDDETyp );
- rWrtShell.Insert( aSwDDEField );
+ rWrtShell.InsertField2( aSwDDEField );
}
} while( false );
@@ -3950,7 +3950,7 @@ bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt,
if ( bTableSel )
{
/* delete table contents not cells */
- rSrcSh.Delete();
+ rSrcSh.Delete(false);
}
else
{
@@ -4217,7 +4217,7 @@ bool SwTransferDdeLink::WriteData( SvStream& rStrm )
// remove mark
rServerObject.SetNoServer(); // this removes the connection between SwServerObject and mark
// N.B. ppMark was not loaded from file and cannot have xml:id
- pMarkAccess->deleteMark(ppMark);
+ pMarkAccess->deleteMark(ppMark, false);
// recreate as Bookmark
::sw::mark::IMark* const pNewMark = pMarkAccess->makeMark(
@@ -4252,7 +4252,7 @@ void SwTransferDdeLink::Disconnect( bool bRemoveDataAdvise )
bool bIsModified = pDoc->getIDocumentState().IsModified();
IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
- pMarkAccess->deleteMark(pMarkAccess->findMark(sName));
+ pMarkAccess->deleteMark(pMarkAccess->findMark(sName), false);
if( !bIsModified )
pDoc->getIDocumentState().ResetModified();
diff --git a/sw/source/uibase/docvw/OverlayRanges.hxx b/sw/source/uibase/docvw/OverlayRanges.hxx
index 7482deef8f97..8deecac241fd 100644
--- a/sw/source/uibase/docvw/OverlayRanges.hxx
+++ b/sw/source/uibase/docvw/OverlayRanges.hxx
@@ -23,7 +23,9 @@
#include <svx/sdr/overlay/overlayobject.hxx>
#include <basegfx/range/b2drange.hxx>
+#include <memory>
#include <vector>
+#include <memory>
class SwView;
diff --git a/sw/source/uibase/docvw/ShadowOverlayObject.hxx b/sw/source/uibase/docvw/ShadowOverlayObject.hxx
index ec2c7eaf44c1..506b801d0991 100644
--- a/sw/source/uibase/docvw/ShadowOverlayObject.hxx
+++ b/sw/source/uibase/docvw/ShadowOverlayObject.hxx
@@ -20,8 +20,14 @@
#ifndef INCLUDED_SW_SOURCE_UIBASE_DOCVW_SHADOWOVERLAYOBJECT_HXX
#define INCLUDED_SW_SOURCE_UIBASE_DOCVW_SHADOWOVERLAYOBJECT_HXX
+#include <sal/config.h>
+
+#include <memory>
+
#include <svx/sdr/overlay/overlayobject.hxx>
+#include <memory>
+
class SwView;
namespace sw { namespace sidebarwindows {
diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx
index 80c00954fa0e..c6e5cbda9cbf 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -163,6 +163,9 @@
#include <sfx2/event.hxx>
#include <memory>
+#include "../../core/crsr/callnk.hxx"
+
+
using namespace sw::mark;
using namespace ::com::sun::star;
@@ -3698,7 +3701,7 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
// select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
// and CH_TXT_ATR_INPUTFIELDEND
rSh.SttSelect();
- rSh.SelectText( aFieldAtPos.pFndTextAttr->GetStart() + 1,
+ rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
*(aFieldAtPos.pFndTextAttr->End()) - 1 );
}
// don't reset here any longer so that, in case through MouseMove
@@ -3728,8 +3731,8 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
// select content of Input Field, but exclude CH_TXT_ATR_INPUTFIELDSTART
// and CH_TXT_ATR_INPUTFIELDEND
rSh.SttSelect();
- rSh.SelectText( aFieldAtPos.pFndTextAttr->GetStart() + 1,
- *(aFieldAtPos.pFndTextAttr->End()) - 1 );
+ rSh.SelectTextModel( aFieldAtPos.pFndTextAttr->GetStart() + 1,
+ *(aFieldAtPos.pFndTextAttr->End()) - 1 );
}
}
@@ -6285,8 +6288,7 @@ OUString SwEditWin::GetSurroundingText() const
rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR );
else if( !rSh.HasSelection() )
{
- SwPosition *pPos = rSh.GetCursor()->GetPoint();
- const sal_Int32 nPos = pPos->nContent.GetIndex();
+ rSh.Push();
// get the sentence around the cursor
rSh.HideCursor();
@@ -6295,8 +6297,7 @@ OUString SwEditWin::GetSurroundingText() const
rSh.GoEndSentence();
rSh.GetSelectedText( sReturn, ParaBreakType::ToOnlyCR );
- pPos->nContent = nPos;
- rSh.ClearMark();
+ rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
rSh.HideCursor();
}
@@ -6316,18 +6317,20 @@ Selection SwEditWin::GetSurroundingTextSelection() const
{
// Return the position of the visible cursor in the sentence
// around the visible cursor.
- SwPosition *pPos = rSh.GetCursor()->GetPoint();
- const sal_Int32 nPos = pPos->nContent.GetIndex();
+ TextFrameIndex const nPos(rSh.GetCursorPointAsViewIndex());
+
+ // store shell state *before* Push
+ ::std::unique_ptr<SwCallLink> pLink(::std::make_unique<SwCallLink>(rSh));
+ rSh.Push();
rSh.HideCursor();
rSh.GoStartSentence();
- const sal_Int32 nStartPos = rSh.GetCursor()->GetPoint()->nContent.GetIndex();
+ TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
- pPos->nContent = nPos;
- rSh.ClearMark();
+ rSh.Pop(SwCursorShell::PopMode::DeleteCurrent, ::std::move(pLink));
rSh.ShowCursor();
- return Selection( nPos - nStartPos, nPos - nStartPos );
+ return Selection(sal_Int32(nPos - nStartPos), sal_Int32(nPos - nStartPos));
}
}
diff --git a/sw/source/uibase/fldui/fldmgr.cxx b/sw/source/uibase/fldui/fldmgr.cxx
index 871cb366df1c..6bc001c99e0e 100644
--- a/sw/source/uibase/fldui/fldmgr.cxx
+++ b/sw/source/uibase/fldui/fldmgr.cxx
@@ -1494,40 +1494,49 @@ bool SwFieldMgr::InsertField(
// insert
pCurShell->StartAllAction();
- pCurShell->Insert(*pField, rData.m_pAnnotationRange.get());
+ bool const isSuccess = pCurShell->InsertField2(*pField, rData.m_pAnnotationRange.get());
- if (SwFieldTypesEnum::Input == rData.m_nTypeId)
+ if (isSuccess)
{
- pCurShell->Push();
+ if (SwFieldTypesEnum::Input == rData.m_nTypeId)
+ {
+ pCurShell->Push();
- // start dialog, not before the field is inserted tdf#99529
- pCurShell->Left(CRSR_SKIP_CHARS, false,
- (INP_VAR == (nSubType & 0xff) || pCurShell->GetViewOptions()->IsFieldName()) ? 1 : 2,
- false);
- pCurShell->StartInputFieldDlg(pField.get(), false, true, rData.m_pParent);
+ // start dialog, not before the field is inserted tdf#99529
+ pCurShell->Left(CRSR_SKIP_CHARS, false,
+ (INP_VAR == (nSubType & 0xff) || pCurShell->GetViewOptions()->IsFieldName()) ? 1 : 2,
+ false);
+ pCurShell->StartInputFieldDlg(pField.get(), false, true, rData.m_pParent);
- pCurShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
- }
+ pCurShell->Pop(SwCursorShell::PopMode::DeleteCurrent);
+ }
- if(bExp && m_bEvalExp)
- pCurShell->UpdateExpFields(true);
+ if (bExp && m_bEvalExp)
+ {
+ pCurShell->UpdateExpFields(true);
+ }
- if(bTable)
- {
- pCurShell->Left(CRSR_SKIP_CHARS, false, 1, false );
- pCurShell->UpdateOneField(*pField);
- pCurShell->Right(CRSR_SKIP_CHARS, false, 1, false );
+ if (bTable)
+ {
+ pCurShell->Left(CRSR_SKIP_CHARS, false, 1, false );
+ pCurShell->UpdateOneField(*pField);
+ pCurShell->Right(CRSR_SKIP_CHARS, false, 1, false );
+ }
+ else if (bPageVar)
+ {
+ static_cast<SwRefPageGetFieldType*>(pCurShell->GetFieldType(0, SwFieldIds::RefPageGet))->UpdateFields();
+ }
+ else if (SwFieldTypesEnum::GetRef == rData.m_nTypeId)
+ {
+ pField->GetTyp()->ModifyNotification( nullptr, nullptr );
+ }
}
- else if( bPageVar )
- static_cast<SwRefPageGetFieldType*>(pCurShell->GetFieldType( 0, SwFieldIds::RefPageGet ))->UpdateFields();
- else if( SwFieldTypesEnum::GetRef == rData.m_nTypeId )
- pField->GetTyp()->ModifyNotification( nullptr, nullptr );
// delete temporary field
pField.reset();
pCurShell->EndAllAction();
- return true;
+ return isSuccess;
}
// fields update
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index 6ec17d5b0e78..a61b049f5002 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -140,6 +140,7 @@ public:
// is there a text- or frameselection?
bool HasSelection() const { return SwCursorShell::HasSelection() ||
IsMultiSelection() || IsSelFrameMode() || IsObjSelected(); }
+ bool Pop(SwCursorShell::PopMode, ::std::unique_ptr<SwCallLink> const pLink);
bool Pop(SwCursorShell::PopMode = SwCursorShell::PopMode::DeleteStack);
void EnterStdMode();
@@ -279,7 +280,7 @@ typedef bool (SwWrtShell:: *FNSimpleMove)();
bool DelLeft();
// also deletes the frame or sets the cursor in the frame when bDelFrame == false
- bool DelRight();
+ bool DelRight(bool isReplaceHeuristic = false);
void DelToEndOfPara();
void DelToStartOfPara();
bool DelToEndOfSentence();
@@ -300,7 +301,7 @@ typedef bool (SwWrtShell:: *FNSimpleMove)();
int IntelligentCut(SelectionType nSelectionType, bool bCut = true);
// edit
- void Insert(SwField const &, SwPaM* pAnnotationRange = nullptr);
+ bool InsertField2(SwField const &, SwPaM* pAnnotationRange = nullptr);
void Insert(const OUString &);
// graphic
void Insert( const OUString &rPath, const OUString &rFilter,
diff --git a/sw/source/uibase/lingu/hhcwrp.cxx b/sw/source/uibase/lingu/hhcwrp.cxx
index 52ee334ec21d..55f09447c623 100644
--- a/sw/source/uibase/lingu/hhcwrp.cxx
+++ b/sw/source/uibase/lingu/hhcwrp.cxx
@@ -326,7 +326,7 @@ void SwHHCWrapper::ChangeText_impl( const OUString &rNewText, bool bKeepAttribut
// restore those for the new text
m_rWrtShell.GetCurAttr( aItemSet );
- m_rWrtShell.Delete();
+ m_rWrtShell.Delete(true);
m_rWrtShell.Insert( rNewText );
// select new inserted text (currently the Point is right after the new text)
@@ -346,7 +346,7 @@ void SwHHCWrapper::ChangeText_impl( const OUString &rNewText, bool bKeepAttribut
}
else
{
- m_rWrtShell.Delete();
+ m_rWrtShell.Delete(true);
m_rWrtShell.Insert( rNewText );
}
}
diff --git a/sw/source/uibase/ribbar/inputwin.cxx b/sw/source/uibase/ribbar/inputwin.cxx
index 1c278137cb16..fdab2b6ec5de 100644
--- a/sw/source/uibase/ribbar/inputwin.cxx
+++ b/sw/source/uibase/ribbar/inputwin.cxx
@@ -245,7 +245,7 @@ void SwInputWindow::ShowWin()
if( pWrtShell->SwCursorShell::HasSelection() )
{
pWrtShell->StartUndo( SwUndoId::DELETE );
- pWrtShell->Delete();
+ pWrtShell->Delete(false);
if( SwUndoId::EMPTY != pWrtShell->EndUndo( SwUndoId::DELETE ))
{
m_bCallUndo = true;
@@ -451,7 +451,7 @@ void SwInputWindow::DelBoxContent()
pWrtShell->MoveSection( GoCurrSection, fnSectionStart );
pWrtShell->SetMark();
pWrtShell->MoveSection( GoCurrSection, fnSectionEnd );
- pWrtShell->SwEditShell::Delete();
+ pWrtShell->SwEditShell::Delete(false);
pWrtShell->EndAllAction();
}
}
diff --git a/sw/source/uibase/shells/drwbassh.cxx b/sw/source/uibase/shells/drwbassh.cxx
index 12d87bab691b..6f73e76ec91c 100644
--- a/sw/source/uibase/shells/drwbassh.cxx
+++ b/sw/source/uibase/shells/drwbassh.cxx
@@ -30,6 +30,7 @@
#include <svx/swframevalidation.hxx>
#include <svx/anchorid.hxx>
#include <sfx2/htmlmode.hxx>
+#include <svx/hlnkitem.hxx>
#include <drawdoc.hxx>
#include <uitool.hxx>
#include <fmtornt.hxx>
@@ -54,16 +55,23 @@
#include <swslots.hxx>
#include <svx/svxdlg.hxx>
#include <svx/dialogs.hrc>
+#include <vcl/unohelp2.hxx>
#include <swabstdlg.hxx>
#include <swundo.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
#include <com/sun/star/text/HoriOrientation.hpp>
#include <com/sun/star/text/VertOrientation.hpp>
#include <com/sun/star/text/RelOrientation.hpp>
+#include <com/sun/star/uno/Reference.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <memory>
#include <fmtfollowtextflow.hxx>
using namespace ::com::sun::star;
+using namespace css::beans;
+using namespace css::drawing;
+using namespace css::uno;
SFX_IMPL_SUPERCLASS_INTERFACE(SwDrawBaseShell, SwBaseShell)
@@ -603,6 +611,52 @@ void SwDrawBaseShell::Execute(SfxRequest const &rReq)
break;
}
+ case SID_OPEN_HYPERLINK:
+ {
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ LoadURL(GetShell(), pObj->getHyperlink(), LoadUrlFlags::NewView,
+ /*rTargetFrameName=*/OUString());
+ break;
+ }
+
+ case SID_EDIT_HYPERLINK:
+ case SID_HYPERLINK_DIALOG:
+ {
+ GetView().GetViewFrame()->SetChildWindow(SID_HYPERLINK_DIALOG, true);
+ break;
+ }
+
+ case SID_HYPERLINK_SETLINK:
+ {
+ if(pItem)
+ {
+ const SvxHyperlinkItem& rHLinkItem = *static_cast<const SvxHyperlinkItem *>(pItem);
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ pObj->setHyperlink(rHLinkItem.GetURL());
+ }
+ break;
+ }
+
+ case SID_REMOVE_HYPERLINK:
+ {
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ pObj->setHyperlink(OUString());
+ break;
+ }
+
+ case SID_COPY_HYPERLINK_LOCATION:
+ {
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ uno::Reference<datatransfer::clipboard::XClipboard> xClipboard
+ = GetView().GetEditWin().GetClipboard();
+ vcl::unohelper::TextDataObject::CopyStringTo(pObj->getHyperlink(), xClipboard);
+ break;
+ }
+
default:
OSL_ENSURE(false, "wrong Dispatcher");
return;
@@ -736,6 +790,62 @@ void SwDrawBaseShell::GetState(SfxItemSet& rSet)
}
}
break;
+
+ case SID_OPEN_HYPERLINK:
+ case SID_EDIT_HYPERLINK:
+ case SID_HYPERLINK_DIALOG:
+ case SID_REMOVE_HYPERLINK:
+ case SID_COPY_HYPERLINK_LOCATION:
+ {
+ if (pSdrView->GetMarkedObjectCount() != 1)
+ {
+ rSet.DisableItem(nWhich);
+ break;
+ }
+
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ sal_uInt16 nObjType = pObj->GetObjIdentifier();
+
+ // Only enable hyperlink for the following types
+ switch (nObjType)
+ {
+ case OBJ_PATHFILL:
+ case OBJ_SECT:
+ case OBJ_LINE:
+ case OBJ_CUSTOMSHAPE:
+ case OBJ_TEXT:
+ case OBJ_RECT:
+ case OBJ_CAPTION:
+ case OBJ_POLY:
+ case OBJ_PLIN:
+ case OBJ_MEASURE:
+ case OBJ_EDGE:
+ break;
+ default:
+ rSet.DisableItem(nWhich);
+ break;
+ }
+
+ if (nWhich == SID_OPEN_HYPERLINK || nWhich == SID_REMOVE_HYPERLINK
+ || nWhich == SID_EDIT_HYPERLINK || nWhich == SID_COPY_HYPERLINK_LOCATION)
+ {
+ if (pObj->getHyperlink().isEmpty())
+ rSet.DisableItem(nWhich);
+ }
+ }
+ break;
+
+ case SID_HYPERLINK_GETLINK:
+ {
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ OUString sHyperLink = pObj->getHyperlink();
+ SvxHyperlinkItem aHLinkItem;
+ aHLinkItem.SetURL(sHyperLink);
+ rSet.Put(aHLinkItem);
+ }
+ break;
}
nWhich = aIter.NextWhich();
}
diff --git a/sw/source/uibase/shells/drwtxtex.cxx b/sw/source/uibase/shells/drwtxtex.cxx
index 60bdf16380be..0e3ba07c3973 100644
--- a/sw/source/uibase/shells/drwtxtex.cxx
+++ b/sw/source/uibase/shells/drwtxtex.cxx
@@ -545,12 +545,8 @@ void SwDrawTextShell::Execute( SfxRequest &rReq )
const SvxFieldData* pField = pOLV->GetFieldAtCursor();
if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
{
- SfxStringItem aUrl(SID_FILE_NAME, pURLField->GetURL());
- SfxStringItem aTarget(SID_TARGETNAME, pURLField->GetTargetFrame());
- SfxBoolItem aNewView(SID_OPEN_NEW_VIEW, false);
- SfxBoolItem aBrowsing(SID_BROWSE, true);
- GetView().GetViewFrame()->GetDispatcher()->ExecuteList(
- SID_OPENDOC, SfxCallMode::SYNCHRON, { &aUrl, &aTarget, &aNewView, &aBrowsing });
+ ::LoadURL(GetShell(), pURLField->GetURL(), LoadUrlFlags::NONE,
+ pURLField->GetTargetFrame());
}
}
break;
diff --git a/sw/source/uibase/shells/frmsh.cxx b/sw/source/uibase/shells/frmsh.cxx
index 32036351a5ee..ba6e91f12ec1 100644
--- a/sw/source/uibase/shells/frmsh.cxx
+++ b/sw/source/uibase/shells/frmsh.cxx
@@ -1123,7 +1123,7 @@ void SwFrameShell::ExecFrameStyle(SfxRequest const & rReq)
{
aBorderLine.SetBorderLineStyle(
SvxBorderLineStyle::SOLID);
- aBorderLine.SetWidth( DEF_LINE_WIDTH_0 );
+ aBorderLine.SetWidth( SvxBorderLineWidth::Hairline );
}
//Set distance only if the request is received from the controller.
diff --git a/sw/source/uibase/shells/tabsh.cxx b/sw/source/uibase/shells/tabsh.cxx
index 073fe280c924..da77b89e4189 100644
--- a/sw/source/uibase/shells/tabsh.cxx
+++ b/sw/source/uibase/shells/tabsh.cxx
@@ -530,7 +530,7 @@ void SwTableShell::Execute(SfxRequest &rReq)
if(aBorderLine.GetOutWidth() == 0)
{
aBorderLine.SetBorderLineStyle(SvxBorderLineStyle::SOLID);
- aBorderLine.SetWidth( DEF_LINE_WIDTH_5 );
+ aBorderLine.SetWidth( SvxBorderLineWidth::VeryThin );
}
if( aBox->GetTop() != nullptr )
diff --git a/sw/source/uibase/shells/textfld.cxx b/sw/source/uibase/shells/textfld.cxx
index 3d6a2edee1f2..61f4b8e86f26 100644
--- a/sw/source/uibase/shells/textfld.cxx
+++ b/sw/source/uibase/shells/textfld.cxx
@@ -196,10 +196,10 @@ void SwTextShell::ExecField(SfxRequest &rReq)
rSh.ClearMark();
if (!rSh.IsMultiSelection()
&& (nullptr != dynamic_cast<const SwTextInputField*>(
- SwCursorShell::GetTextFieldAtCursor(rSh.GetCursor(), true))))
+ SwCursorShell::GetTextFieldAtCursor(rSh.GetCursor(), ::sw::GetTextAttrMode::Default))))
{
rSh.SttSelect();
- rSh.SelectText(
+ rSh.SelectTextModel(
SwCursorShell::StartOfInputFieldAtPos( *(rSh.GetCursor()->Start()) ) + 1,
SwCursorShell::EndOfInputFieldAtPos( *(rSh.GetCursor()->Start()) ) - 1 );
}
diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx
index 3907f2611fac..ef5b86f6f199 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -708,7 +708,7 @@ void SwTextShell::Execute(SfxRequest &rReq)
if ( pItem )
{
IDocumentMarkAccess* const pMarkAccess = rWrtSh.getIDocumentMarkAccess();
- pMarkAccess->deleteMark( pMarkAccess->findMark(static_cast<const SfxStringItem*>(pItem)->GetValue()) );
+ pMarkAccess->deleteMark(pMarkAccess->findMark(static_cast<const SfxStringItem*>(pItem)->GetValue()), false);
}
break;
}
diff --git a/sw/source/uibase/uitest/uiobject.cxx b/sw/source/uibase/uitest/uiobject.cxx
index ecdfd68ad6a8..f44f2b5a70fb 100644
--- a/sw/source/uibase/uitest/uiobject.cxx
+++ b/sw/source/uibase/uitest/uiobject.cxx
@@ -13,6 +13,7 @@
#include <view.hxx>
#include <wrtsh.hxx>
#include <navipi.hxx>
+#include <ndtxt.hxx>
#include <sfx2/sidebar/Sidebar.hxx>
#include <sfx2/viewfrm.hxx>
@@ -89,14 +90,30 @@ void SwEditWinUIObject::execute(const OUString& rAction,
{
auto itr = rParameters.find("START_POS");
OUString aStartPos = itr->second;
- sal_Int32 nStartPos = aStartPos.toInt32();
+ TextFrameIndex const nStartPos(aStartPos.toInt32());
itr = rParameters.find("END_POS");
assert(itr != rParameters.end());
OUString aEndPos = itr->second;
- sal_Int32 nEndPos = aEndPos.toInt32();
-
- getWrtShell(mxEditWin).SelectText(nStartPos, nEndPos);
+ TextFrameIndex const nEndPos(aEndPos.toInt32());
+
+ auto & shell = getWrtShell(mxEditWin);
+ if (shell.GetCursor_()->GetPoint()->nNode.GetNode().GetTextNode())
+ {
+ shell.Push();
+ shell.MovePara(GoCurrPara, fnParaEnd);
+ TextFrameIndex const len(shell.GetCursorPointAsViewIndex());
+ shell.Pop(SwCursorShell::PopMode::DeleteCurrent);
+ SAL_WARN_IF(
+ sal_Int32(nStartPos) < 0 || nStartPos > len || sal_Int32(nEndPos) < 0 || nEndPos > len, "sw.ui",
+ "SELECT START/END_POS " << sal_Int32(nStartPos) << ".." << sal_Int32(nEndPos) << " outside 0.." << sal_Int32(len));
+ shell.SelectTextView(
+ std::clamp(nStartPos, TextFrameIndex(0), len), std::clamp(nEndPos, TextFrameIndex(0), len));
+ }
+ else
+ {
+ SAL_WARN("sw.ui", "SELECT without SwTextNode");
+ }
}
}
else if (rAction == "SIDEBAR")
diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx
index 85e6d4559608..ad6a69df6c01 100644
--- a/sw/source/uibase/utlui/content.cxx
+++ b/sw/source/uibase/utlui/content.cxx
@@ -3532,7 +3532,7 @@ void SwContentTree::EditEntry(SvTreeListEntry const * pEntry, EditEntryMode nMod
if(nMode == EditEntryMode::DELETE)
{
IDocumentMarkAccess* const pMarkAccess = m_pActiveShell->getIDocumentMarkAccess();
- pMarkAccess->deleteMark( pMarkAccess->findMark(pCnt->GetName()) );
+ pMarkAccess->deleteMark(pMarkAccess->findMark(pCnt->GetName()), false);
}
else if(nMode == EditEntryMode::RENAME)
{
diff --git a/sw/source/uibase/utlui/navipi.cxx b/sw/source/uibase/utlui/navipi.cxx
index e016ab69910f..29bdd3938cde 100644
--- a/sw/source/uibase/utlui/navipi.cxx
+++ b/sw/source/uibase/utlui/navipi.cxx
@@ -512,7 +512,7 @@ void SwNavigationPI::MakeMark()
// nAutoMarkIdx rotates through the available MarkNames
// this assumes that IDocumentMarkAccess generates Names in ascending order
if(vNavMarkNames.size() == MAX_MARKS)
- pMarkAccess->deleteMark(pMarkAccess->findMark(vNavMarkNames[m_nAutoMarkIdx]));
+ pMarkAccess->deleteMark(pMarkAccess->findMark(vNavMarkNames[m_nAutoMarkIdx]), false);
rSh.SetBookmark(vcl::KeyCode(), OUString(), IDocumentMarkAccess::MarkType::NAVIGATOR_REMINDER);
SwView::SetActMark( m_nAutoMarkIdx );
diff --git a/sw/source/uibase/wrtsh/delete.cxx b/sw/source/uibase/wrtsh/delete.cxx
index 4a2420ad7b84..8b5cd59bfa0c 100644
--- a/sw/source/uibase/wrtsh/delete.cxx
+++ b/sw/source/uibase/wrtsh/delete.cxx
@@ -104,7 +104,7 @@ void SwWrtShell::DelLine()
SetMark();
SwCursorShell::RightMargin();
- bool bRet = Delete();
+ bool bRet = Delete(false);
Pop(SwCursorShell::PopMode::DeleteCurrent);
if( bRet )
UpdateAttr();
@@ -114,7 +114,7 @@ void SwWrtShell::DelToStartOfLine()
{
OpenMark();
SwCursorShell::LeftMargin();
- bool bRet = Delete();
+ bool bRet = Delete(false);
CloseMark( bRet );
}
@@ -122,7 +122,7 @@ void SwWrtShell::DelToEndOfLine()
{
OpenMark();
SwCursorShell::RightMargin();
- bool bRet = Delete();
+ bool bRet = Delete(false);
CloseMark( bRet );
}
@@ -164,7 +164,7 @@ bool SwWrtShell::DelLeft()
{
SwActContext aActContext(this);
ResetCursorStack();
- Delete();
+ Delete(false);
UpdateAttr();
}
if( IsBlockMode() )
@@ -275,14 +275,14 @@ bool SwWrtShell::DelLeft()
}
}
}
- bool bRet = Delete();
+ bool bRet = Delete(true);
if( !bRet && bSwap )
SwCursorShell::SwapPam();
CloseMark( bRet );
return bRet;
}
-bool SwWrtShell::DelRight()
+bool SwWrtShell::DelRight(bool const isReplaceHeuristic)
{
// Will be or'ed, if a tableselection exists;
// will here be implemented on SelectionType::Table
@@ -309,7 +309,7 @@ bool SwWrtShell::DelRight()
{
SwActContext aActContext(this);
ResetCursorStack();
- Delete();
+ Delete(isReplaceHeuristic);
UpdateAttr();
}
if( IsBlockMode() )
@@ -392,7 +392,7 @@ bool SwWrtShell::DelRight()
OpenMark();
SwCursorShell::Right(1, CRSR_SKIP_CELLS);
- bRet = Delete();
+ bRet = Delete(true);
CloseMark( bRet );
break;
@@ -434,7 +434,7 @@ bool SwWrtShell::DelRight()
if (pTextNode)
{
const SwTextField* pField(
- pTextNode->GetFieldTextAttrAt(pAnchor->nContent.GetIndex(), true));
+ pTextNode->GetFieldTextAttrAt(pAnchor->nContent.GetIndex(), ::sw::GetTextAttrMode::Default));
if (pField
&& dynamic_cast<const SwPostItField*>(pField->GetFormatField().GetField()))
{
@@ -498,7 +498,7 @@ void SwWrtShell::DelToEndOfPara()
Pop(SwCursorShell::PopMode::DeleteCurrent);
return;
}
- bool bRet = Delete();
+ bool bRet = Delete(false);
Pop(SwCursorShell::PopMode::DeleteCurrent);
if( bRet )
UpdateAttr();
@@ -515,7 +515,7 @@ void SwWrtShell::DelToStartOfPara()
Pop(SwCursorShell::PopMode::DeleteCurrent);
return;
}
- bool bRet = Delete();
+ bool bRet = Delete(false);
Pop(SwCursorShell::PopMode::DeleteCurrent);
if( bRet )
UpdateAttr();
@@ -530,7 +530,7 @@ void SwWrtShell::DelToStartOfSentence()
if(IsStartOfDoc())
return;
OpenMark();
- bool bRet = BwdSentence_() && Delete();
+ bool bRet = BwdSentence_() && Delete(false);
CloseMark( bRet );
}
@@ -562,7 +562,7 @@ bool SwWrtShell::DelToEndOfSentence()
}
else
{
- bRet = FwdSentence_() && Delete();
+ bRet = FwdSentence_() && Delete(false);
}
CloseMark( bRet );
return bRet;
@@ -583,7 +583,7 @@ void SwWrtShell::DelNxtWord()
else
EndWrd();
- bool bRet = Delete();
+ bool bRet = Delete(false);
if( bRet )
UpdateAttr();
else
@@ -607,7 +607,7 @@ void SwWrtShell::DelPrvWord()
else
SttWrd();
}
- bool bRet = Delete();
+ bool bRet = Delete(false);
if( bRet )
UpdateAttr();
else
diff --git a/sw/source/uibase/wrtsh/select.cxx b/sw/source/uibase/wrtsh/select.cxx
index 90664ae098f5..322199a2b1d5 100644
--- a/sw/source/uibase/wrtsh/select.cxx
+++ b/sw/source/uibase/wrtsh/select.cxx
@@ -914,7 +914,7 @@ int SwWrtShell::IntelligentCut(SelectionType nSelection, bool bCut)
ClearMark();
SetMark();
SwCursorShell::Left(1,CRSR_SKIP_CHARS);
- SwFEShell::Delete();
+ SwFEShell::Delete(true);
Pop(SwCursorShell::PopMode::DeleteCurrent);
}
}
@@ -928,7 +928,7 @@ int SwWrtShell::IntelligentCut(SelectionType nSelection, bool bCut)
ClearMark();
SetMark();
SwCursorShell::Right(1,CRSR_SKIP_CHARS);
- SwFEShell::Delete();
+ SwFEShell::Delete(true);
Pop(SwCursorShell::PopMode::DeleteCurrent);
}
}
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx
index 0840ed3cd407..c240c630df3a 100644
--- a/sw/source/uibase/wrtsh/wrtsh1.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -118,6 +118,9 @@
#include <comphelper/lok.hxx>
#include <memory>
+#include "../../core/crsr/callnk.hxx"
+
+
using namespace sw::mark;
using namespace com::sun::star;
namespace {
@@ -244,7 +247,8 @@ void SwWrtShell::Insert( const OUString &rStr )
StartUndo(SwUndoId::REPLACE, &aRewriter);
bStarted = true;
Push();
- bDeleted = DelRight();
+ // let's interpret a selection within the same node as "replace"
+ bDeleted = DelRight(GetCursor()->GetPoint()->nNode == GetCursor()->GetMark()->nNode);
Pop(SwCursorShell::PopMode::DeleteCurrent); // Restore selection (if tracking changes)
NormalizePam(false); // tdf#127635 put point at the end of deletion
ClearMark();
@@ -1667,7 +1671,7 @@ void SwWrtShell::AutoCorrect( SvxAutoCorrect& rACorr, sal_Unicode cChar )
StartUndo( SwUndoId::REPLACE, &aRewriter );
bStarted = true;
- DelRight();
+ DelRight(true);
}
SwEditShell::AutoCorrect( rACorr, IsInsMode(), cChar );
@@ -1729,7 +1733,13 @@ SwWrtShell::~SwWrtShell()
bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete)
{
- bool bRet = SwCursorShell::Pop(eDelete);
+ ::std::unique_ptr<SwCallLink> pLink(::std::make_unique<SwCallLink>(*this));
+ return Pop(eDelete, ::std::move(pLink));
+}
+
+bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete, ::std::unique_ptr<SwCallLink> pLink)
+{
+ bool bRet = SwCursorShell::Pop(eDelete, ::std::move(pLink));
if( bRet && IsSelection() )
{
m_fnSetCursor = &SwWrtShell::SetCursorKillSel;
diff --git a/sw/source/uibase/wrtsh/wrtsh2.cxx b/sw/source/uibase/wrtsh/wrtsh2.cxx
index 82d7c27cb0c6..459abd7f8b33 100644
--- a/sw/source/uibase/wrtsh/wrtsh2.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh2.cxx
@@ -68,11 +68,11 @@
#include <sfx2/event.hxx>
#include <sal/log.hxx>
-void SwWrtShell::Insert(SwField const& rField, SwPaM* pAnnotationRange)
+bool SwWrtShell::InsertField2(SwField const& rField, SwPaM* pAnnotationRange)
{
ResetCursorStack();
if(!CanInsert())
- return;
+ return false;
StartAllAction();
SwRewriter aRewriter;
@@ -120,7 +120,7 @@ void SwWrtShell::Insert(SwField const& rField, SwPaM* pAnnotationRange)
}
}
- SwEditShell::Insert2(rField, bDeleted);
+ bool const isSuccess = SwEditShell::InsertField(rField, bDeleted);
if ( pAnnotationTextRange )
{
@@ -145,6 +145,8 @@ void SwWrtShell::Insert(SwField const& rField, SwPaM* pAnnotationRange)
EndUndo();
EndAllAction();
+
+ return isSuccess;
}
// Start the field update
@@ -488,30 +490,24 @@ bool SwWrtShell::ClickToINetGrf( const Point& rDocPt, LoadUrlFlags nFilter )
return bRet;
}
-void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
- const OUString& rTargetFrameName )
+static void LoadURL(SwView& rView, const OUString& rURL, LoadUrlFlags nFilter,
+ const OUString& rTargetFrameName)
{
- OSL_ENSURE( !rURL.isEmpty(), "what should be loaded here?" );
- if( rURL.isEmpty() )
- return ;
+ SwDocShell* pDShell = rView.GetDocShell();
+ OSL_ENSURE( pDShell, "No DocShell?!");
+ SfxViewFrame& rViewFrame = *rView.GetViewFrame();
- // The shell could be 0 also!!!!!
- if ( dynamic_cast<const SwCursorShell*>( &rVSh) == nullptr )
+ if (!SfxObjectShell::AllowedLinkProtocolFromDocument(rURL, pDShell, rView.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("#"))
{
- rVSh.GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, rURL.toUtf8().getStr());
+ rView.libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, rURL.toUtf8().getStr());
return;
}
- //A CursorShell is always a WrtShell
- SwWrtShell &rSh = static_cast<SwWrtShell&>(rVSh);
-
- SwDocShell* pDShell = rSh.GetView().GetDocShell();
- OSL_ENSURE( pDShell, "No DocShell?!");
OUString sTargetFrame(rTargetFrameName);
if (sTargetFrame.isEmpty() && pDShell)
{
@@ -526,8 +522,7 @@ void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
OUString sReferer;
if( pDShell && pDShell->GetMedium() )
sReferer = pDShell->GetMedium()->GetName();
- SfxViewFrame* pViewFrame = rSh.GetView().GetViewFrame();
- SfxFrameItem aView( SID_DOCFRAME, pViewFrame );
+ SfxFrameItem aView( SID_DOCFRAME, &rViewFrame );
SfxStringItem aName( SID_FILE_NAME, rURL );
SfxStringItem aTargetFrameName( SID_TARGETNAME, sTargetFrame );
SfxStringItem aReferer( SID_REFERER, sReferer );
@@ -548,10 +543,27 @@ void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
nullptr
};
- pViewFrame->GetDispatcher()->GetBindings()->Execute( SID_OPENDOC, aArr,
+ rViewFrame.GetDispatcher()->GetBindings()->Execute( SID_OPENDOC, aArr,
SfxCallMode::ASYNCHRON|SfxCallMode::RECORD );
}
+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 ( dynamic_cast<const SwCursorShell*>( &rVSh) == nullptr )
+ return;
+
+ //A CursorShell is always a WrtShell
+ SwWrtShell &rSh = static_cast<SwWrtShell&>(rVSh);
+
+ ::LoadURL(rSh.GetView(), rURL, nFilter, rTargetFrameName);
+}
+
void SwWrtShell::NavigatorPaste( const NaviContentBookmark& rBkmk,
const sal_uInt16 nAction )
{