summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Stahl <mstahl@redhat.com>2017-05-10 17:45:14 +0200
committerMichael Stahl <mstahl@redhat.com>2017-05-10 18:01:09 +0200
commit771d85baf18e5b503eb6248e1f41928b00265d8d (patch)
tree5ea7b0ca65fece457fe764d84ff4f575e425ce54
parentffe239962f195781c6b086c5a284aad333e3e12e (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.hxx6
-rw-r--r--sw/qa/extras/uiwriter/uiwriter.cxx121
-rw-r--r--sw/source/core/txtnode/thints.cxx8
-rw-r--r--sw/source/core/undo/undobj1.cxx2
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();