tdf#50447 sw: track changes of character formatting

Only range of the formatting change was tracked,
but not the original direct character formatting of the text.
Now rejection of the tracked change of a text portion
resets the original direct formatting.

Note: nor ODT or DOCX export hasn't been supported, yet.

See also commit 5322663f8234836a6a4aaaed025c158fd7e8b67a
"tdf#126206 DOCX: add rejection of character formatting changes".

Change-Id: I6e94a797605187cff232c3d7dd505c769b70601b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120466
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx
index 0af2e61..429501d 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -2803,6 +2803,50 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf126206)
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf50447)
{
    SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf126206.docx");

    SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell();

    // bold text
    auto xText = getParagraph(1)->getText();
    CPPUNIT_ASSERT(xText.is());
    {
        auto xCursor(xText->createTextCursorByRange(getRun(getParagraph(1), 1)));
        CPPUNIT_ASSERT(xCursor.is());
        CPPUNIT_ASSERT_EQUAL(OUString("Lorem "), xCursor->getString());
        CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xCursor, "CharWeight"));
    }

    // remove bold formatting with change tracking
    pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 6, /*bBasicCall=*/false);
    dispatchCommand(mxComponent, ".uno:Bold", {});

    xText = getParagraph(1)->getText();
    CPPUNIT_ASSERT(xText.is());
    {
        auto xCursor(xText->createTextCursorByRange(getRun(getParagraph(1), 2)));
        CPPUNIT_ASSERT(xCursor.is());
        CPPUNIT_ASSERT_EQUAL(OUString("Lorem "), xCursor->getString());
        CPPUNIT_ASSERT_EQUAL(awt::FontWeight::NORMAL, getProperty<float>(xCursor, "CharWeight"));
    }

    // reject tracked changes
    dispatchCommand(mxComponent, ".uno:RejectAllTrackedChanges", {});

    // bold text again
    xText = getParagraph(1)->getText();
    CPPUNIT_ASSERT(xText.is());
    {
        auto xCursor(xText->createTextCursorByRange(getRun(getParagraph(1), 1)));
        CPPUNIT_ASSERT(xCursor.is());
        CPPUNIT_ASSERT_EQUAL(OUString("Lorem "), xCursor->getString());
        // This was NORMAL
        CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xCursor, "CharWeight"));
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf101873)
{
    SwDoc* pDoc = createSwDoc();
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 29a2ce5..a07360a 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1644,11 +1644,16 @@ namespace //local functions originally from docfmt.cxx
            return bRet;
        }

        SwRangeRedline * pRedline = nullptr;
        if( rDoc.getIDocumentRedlineAccess().IsRedlineOn() && pCharSet && pCharSet->Count() )
        {
            if( pUndo )
                pUndo->SaveRedlineData( rRg, false );
            rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline( RedlineType::Format, rRg ), true);

            pRedline = new SwRangeRedline( RedlineType::Format, rRg );
            auto const result(rDoc.getIDocumentRedlineAccess().AppendRedline( pRedline, true));
            if (IDocumentRedlineAccess::AppendResult::IGNORED == result)
                pRedline = nullptr;
        }

        /* now if range */
@@ -1670,6 +1675,32 @@ namespace //local functions originally from docfmt.cxx
                if( pNode->IsTextNode() && pCharSet && pCharSet->Count() )
                {
                    SwRegHistory history( pNode, *pNode, pHistory );

                    // store original text attributes to reject formatting change
                    if (pRedline)
                    {
                        // Apply the first character's attributes to the ReplaceText
                        SfxItemSet aSet( rDoc.GetAttrPool(),
                                    svl::Items<RES_CHRATR_BEGIN,     RES_TXTATR_WITHEND_END - 1,
                                    RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1> );
                        pNode->GetTextNode()->GetParaAttr( aSet, pStt->nContent.GetIndex() + 1, aCntEnd.GetIndex() );

                        aSet.ClearItem( RES_TXTATR_REFMARK );
                        aSet.ClearItem( RES_TXTATR_TOXMARK );
                        aSet.ClearItem( RES_TXTATR_CJK_RUBY );
                        aSet.ClearItem( RES_TXTATR_INETFMT );
                        aSet.ClearItem( RES_TXTATR_META );
                        aSet.ClearItem( RES_TXTATR_METAFIELD );

                        auto pExtra = new SwRedlineExtraData_FormatColl( "", USHRT_MAX, &aSet );
                        if ( pExtra )
                        {
                            std::unique_ptr<SwRedlineExtraData_FormatColl> xRedlineExtraData;
                            xRedlineExtraData.reset(pExtra);
                            pRedline->SetExtraData( xRedlineExtraData.get() );
                        }
                    }

                    bRet = history.InsertItems(*pCharSet,
                            pStt->nContent.GetIndex(), aCntEnd.GetIndex(), nFlags, /*ppNewTextAttr*/nullptr)
                        || bRet;