diff options
author | Michael Stahl <mstahl@redhat.com> | 2017-05-10 17:45:14 +0200 |
---|---|---|
committer | Michael Stahl <mstahl@redhat.com> | 2017-05-10 18:01:09 +0200 |
commit | 771d85baf18e5b503eb6248e1f41928b00265d8d (patch) | |
tree | 5ea7b0ca65fece457fe764d84ff4f575e425ce54 | |
parent | ffe239962f195781c6b086c5a284aad333e3e12e (diff) |
tdf#107512 sw: fix rollback of text attributes in SwUndoDelete
The problem is that in SwUndoDelete::UndoImpl(), first the formatting
attributes are restored via TmpRollback(), and then all footnote/fly
attributes are restored via Rollback(). This means that the SwHistory
doesn't actually store the original positions of the formatting hints;
ideally there wouldn't be 2 separate steps here, but that appears
difficult to change now given the plethora of calls to
DelContentIndex() ...
So work around the problem by adding a new SetAttrMode::NOHINTEXPAND
to prevent expanding the existing hints when the CH_TXTATR_BREAKWORD
are inserted from SwUndoDelLayFormat.
This fixes 2 problematic cases: at the start of the paragraph,
and if the hint ends at the position before the CH_TXTATR_BREAKWORD.
Let's hope this won't break anything anybody cares about.
Change-Id: I557c4c9136f4225ca502019730fb9f0a9c03d23b
-rw-r--r-- | sw/inc/swtypes.hxx | 6 | ||||
-rw-r--r-- | sw/qa/extras/uiwriter/uiwriter.cxx | 121 | ||||
-rw-r--r-- | sw/source/core/txtnode/thints.cxx | 8 | ||||
-rw-r--r-- | sw/source/core/undo/undobj1.cxx | 2 |
4 files changed, 131 insertions, 6 deletions
diff --git a/sw/inc/swtypes.hxx b/sw/inc/swtypes.hxx index 76ee8b94243a..2307091b98e4 100644 --- a/sw/inc/swtypes.hxx +++ b/sw/inc/swtypes.hxx @@ -170,11 +170,13 @@ enum class SetAttrMode /// Force hint expand (only matters for hints with CH_TXTATR). FORCEHINTEXPAND = 0x0040, /// The inserted item is a copy -- intended for use in ndtxt.cxx. - IS_COPY = 0x0080 + IS_COPY = 0x0080, + /// for Undo, translated to SwInsertFlags::NOHINTEXPAND + NOHINTEXPAND = 0x0100, }; namespace o3tl { - template<> struct typed_flags<SetAttrMode> : is_typed_flags<SetAttrMode, 0x0ff> {}; + template<> struct typed_flags<SetAttrMode> : is_typed_flags<SetAttrMode, 0x1ff> {}; } #define SW_ISPRINTABLE( c ) ( c >= ' ' && 127 != c ) diff --git a/sw/qa/extras/uiwriter/uiwriter.cxx b/sw/qa/extras/uiwriter/uiwriter.cxx index 4d58b7c242aa..6816d9f6c3db 100644 --- a/sw/qa/extras/uiwriter/uiwriter.cxx +++ b/sw/qa/extras/uiwriter/uiwriter.cxx @@ -186,6 +186,7 @@ public: void testTableBackgroundColor(); void testTdf88899(); void testTdf90362(); + void testUndoDelAsCharTdf107512(); void testUndoCharAttribute(); void testUndoDelAsChar(); void testTdf86639(); @@ -319,6 +320,7 @@ public: CPPUNIT_TEST(testTableBackgroundColor); CPPUNIT_TEST(testTdf88899); CPPUNIT_TEST(testTdf90362); + CPPUNIT_TEST(testUndoDelAsCharTdf107512); CPPUNIT_TEST(testUndoCharAttribute); CPPUNIT_TEST(testUndoDelAsChar); CPPUNIT_TEST(testTdf86639); @@ -3187,6 +3189,125 @@ void SwUiWriterTest::testTdf90362() comphelper::ConfigurationHelper::writeDirectKey(xComponentContext, "org.openoffice.Office.Writer/", "Cursor/Option", "IgnoreProtectedArea", css::uno::Any(false), comphelper::EConfigurationModes::Standard); } +void SwUiWriterTest::testUndoDelAsCharTdf107512() +{ + SwDoc * pDoc(createDoc()); + sw::UndoManager & rUndoManager(pDoc->GetUndoManager()); + IDocumentContentOperations & rIDCO(pDoc->getIDocumentContentOperations()); + SwCursorShell * pShell(pDoc->GetEditShell()); + SfxItemSet frameSet(pDoc->GetAttrPool(), RES_FRMATR_BEGIN, RES_FRMATR_END-1); + SfxItemSet grfSet(pDoc->GetAttrPool(), RES_GRFATR_BEGIN, RES_GRFATR_END-1); + rIDCO.InsertString(*pShell->GetCursor(), "foo"); + pShell->ClearMark(); + SwFormatAnchor anchor(RndStdIds::FLY_AS_CHAR); + frameSet.Put(anchor); + GraphicObject grf; + pShell->SttEndDoc(true); + CPPUNIT_ASSERT(rIDCO.InsertGraphicObject(*pShell->GetCursor(), grf, &frameSet, &grfSet, nullptr)); + pShell->SttEndDoc(false); + CPPUNIT_ASSERT(rIDCO.InsertGraphicObject(*pShell->GetCursor(), grf, &frameSet, &grfSet, nullptr)); + CPPUNIT_ASSERT_EQUAL(size_t(2), pDoc->GetFlyCount(FLYCNTTYPE_GRF)); + SvxCharHiddenItem hidden(true, RES_CHRATR_HIDDEN); + pShell->SelectText(1, 4); + rIDCO.InsertPoolItem(*pShell->GetCursor(), hidden); + // now we have "\1foo\1" with the "foo" hidden + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(4, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT_EQUAL(OUString(OUStringLiteral1(CH_TXTATR_BREAKWORD) + u"foo" + OUStringLiteral1(CH_TXTATR_BREAKWORD)), pShell->GetCursor()->GetNode().GetTextNode()->GetText()); + SfxPoolItem const* pItem; + SfxItemSet query(pDoc->GetAttrPool(), RES_CHRATR_HIDDEN, RES_CHRATR_HIDDEN); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 1, 4); + CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + CPPUNIT_ASSERT(static_cast<SvxCharHiddenItem const*>(pItem)->GetValue()); + query.ClearItem(RES_CHRATR_HIDDEN); + + // delete from the start + pShell->SelectText(0, 4); + rIDCO.DeleteAndJoin(*pShell->GetCursor()); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_GRF)); + CPPUNIT_ASSERT_EQUAL(1, pShell->GetCursor()->GetNode().GetTextNode()->Len()); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 0, 1); + CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + query.ClearItem(RES_CHRATR_HIDDEN); + rUndoManager.Undo(); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(4, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT_EQUAL(size_t(2), pDoc->GetFlyCount(FLYCNTTYPE_GRF)); + CPPUNIT_ASSERT_EQUAL(5, pShell->GetCursor()->GetNode().GetTextNode()->Len()); + CPPUNIT_ASSERT_EQUAL(OUString(OUStringLiteral1(CH_TXTATR_BREAKWORD) + u"foo" + OUStringLiteral1(CH_TXTATR_BREAKWORD)), pShell->GetCursor()->GetNode().GetTextNode()->GetText()); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 0, 1); + CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + query.ClearItem(RES_CHRATR_HIDDEN); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 1, 4); + CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + CPPUNIT_ASSERT(static_cast<SvxCharHiddenItem const*>(pItem)->GetValue()); + query.ClearItem(RES_CHRATR_HIDDEN); + rUndoManager.Redo(); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_GRF)); + CPPUNIT_ASSERT_EQUAL(1, pShell->GetCursor()->GetNode().GetTextNode()->Len()); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 0, 1); + CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + query.ClearItem(RES_CHRATR_HIDDEN); + rUndoManager.Undo(); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(4, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT_EQUAL(size_t(2), pDoc->GetFlyCount(FLYCNTTYPE_GRF)); + CPPUNIT_ASSERT_EQUAL(5, pShell->GetCursor()->GetNode().GetTextNode()->Len()); + CPPUNIT_ASSERT_EQUAL(OUString(OUStringLiteral1(CH_TXTATR_BREAKWORD) + u"foo" + OUStringLiteral1(CH_TXTATR_BREAKWORD)), pShell->GetCursor()->GetNode().GetTextNode()->GetText()); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 0, 1); + CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + query.ClearItem(RES_CHRATR_HIDDEN); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 1, 4); + CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + CPPUNIT_ASSERT(static_cast<SvxCharHiddenItem const*>(pItem)->GetValue()); + query.ClearItem(RES_CHRATR_HIDDEN); + + // delete from the end + pShell->SelectText(1, 5); + rIDCO.DeleteAndJoin(*pShell->GetCursor()); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_GRF)); + CPPUNIT_ASSERT_EQUAL(1, pShell->GetCursor()->GetNode().GetTextNode()->Len()); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 4, 5); + CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + query.ClearItem(RES_CHRATR_HIDDEN); + rUndoManager.Undo(); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(4, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT_EQUAL(size_t(2), pDoc->GetFlyCount(FLYCNTTYPE_GRF)); + CPPUNIT_ASSERT_EQUAL(5, pShell->GetCursor()->GetNode().GetTextNode()->Len()); + CPPUNIT_ASSERT_EQUAL(OUString(OUStringLiteral1(CH_TXTATR_BREAKWORD) + u"foo" + OUStringLiteral1(CH_TXTATR_BREAKWORD)), pShell->GetCursor()->GetNode().GetTextNode()->GetText()); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 4, 5); + CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + query.ClearItem(RES_CHRATR_HIDDEN); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 1, 4); + CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + CPPUNIT_ASSERT(static_cast<SvxCharHiddenItem const*>(pItem)->GetValue()); + query.ClearItem(RES_CHRATR_HIDDEN); + rUndoManager.Redo(); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_GRF)); + CPPUNIT_ASSERT_EQUAL(1, pShell->GetCursor()->GetNode().GetTextNode()->Len()); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 4, 5); + CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + query.ClearItem(RES_CHRATR_HIDDEN); + rUndoManager.Undo(); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(0, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT(pShell->GetCursor()->GetNode().GetTextNode()->GetTextAttrForCharAt(4, RES_TXTATR_FLYCNT)); + CPPUNIT_ASSERT_EQUAL(size_t(2), pDoc->GetFlyCount(FLYCNTTYPE_GRF)); + CPPUNIT_ASSERT_EQUAL(5, pShell->GetCursor()->GetNode().GetTextNode()->Len()); + CPPUNIT_ASSERT_EQUAL(OUString(OUStringLiteral1(CH_TXTATR_BREAKWORD) + u"foo" + OUStringLiteral1(CH_TXTATR_BREAKWORD)), pShell->GetCursor()->GetNode().GetTextNode()->GetText()); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 4, 5); + CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + query.ClearItem(RES_CHRATR_HIDDEN); + pShell->GetCursor()->GetNode().GetTextNode()->GetAttr(query, 1, 4); + CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, query.GetItemState(RES_CHRATR_HIDDEN, false, &pItem)); + CPPUNIT_ASSERT(static_cast<SvxCharHiddenItem const*>(pItem)->GetValue()); + query.ClearItem(RES_CHRATR_HIDDEN); +} + void SwUiWriterTest::testUndoCharAttribute() { // Create a new empty Writer document diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx index e5cb1022e812..2737ddad4e8b 100644 --- a/sw/source/core/txtnode/thints.cxx +++ b/sw/source/core/txtnode/thints.cxx @@ -1246,9 +1246,11 @@ bool SwTextNode::InsertHint( SwTextAttr * const pAttr, const SetAttrMode nMode ) // translate from SetAttrMode to InsertMode (for hints with CH_TXTATR) const SwInsertFlags nInsertFlags = - (nMode & SetAttrMode::FORCEHINTEXPAND) - ? (SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND) - : SwInsertFlags::EMPTYEXPAND; + (nMode & SetAttrMode::NOHINTEXPAND) + ? SwInsertFlags::NOHINTEXPAND + : (nMode & SetAttrMode::FORCEHINTEXPAND) + ? (SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND) + : SwInsertFlags::EMPTYEXPAND; // need this after TryInsertHint, when pAttr may be deleted const sal_Int32 nStart( pAttr->GetStart() ); diff --git a/sw/source/core/undo/undobj1.cxx b/sw/source/core/undo/undobj1.cxx index b5f27ce5b33f..2379b521afa6 100644 --- a/sw/source/core/undo/undobj1.cxx +++ b/sw/source/core/undo/undobj1.cxx @@ -104,7 +104,7 @@ void SwUndoFlyBase::InsFly(::sw::UndoRedoContext & rContext, bool bShowSelFrame) SwContentNode* pCNd = aAnchor.GetContentAnchor()->nNode.GetNode().GetContentNode(); OSL_ENSURE( pCNd->IsTextNode(), "no Text Node at position." ); SwFormatFlyCnt aFormat( pFrameFormat ); - pCNd->GetTextNode()->InsertItem( aFormat, nCntPos, nCntPos ); + pCNd->GetTextNode()->InsertItem(aFormat, nCntPos, nCntPos, SetAttrMode::NOHINTEXPAND); } pFrameFormat->MakeFrames(); |