sw/CppunitTest_sw_swdoc_test.mk | 1 sw/inc/modeltoviewhelper.hxx | 37 ++++++++- sw/qa/core/swdoc-test.cxx | 111 +++++++++++++++++++++++++++ sw/source/core/text/porlay.cxx | 10 ++ sw/source/core/txtnode/ndtxt.cxx | 152 +++++++++++++++++++++++++++++--------- sw/source/core/txtnode/txtedt.cxx | 11 -- 6 files changed, 274 insertions(+), 48 deletions(-)
New commits: commit 92236c0fc4c8704a72f20a3c2e6f22df3c5ae333 Author: Caolán McNamara <caol...@redhat.com> Date: Fri Aug 3 10:54:11 2012 +0100 Related: fdo#46757 unsafe to pass expanded text to masking So, use improved ModelToViewHelper to remove the hidden text right from the start, which drops the need to mask out the hidden text and we can remove the nNumOfMaskedChars hack Change-Id: I3bd90598e496d4e82cd9cef4c8f9e61c180cb945 diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index 64e67b8..d03304a 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -1371,7 +1371,7 @@ sal_uInt16 SwScriptInfo::MaskHiddenRanges( const SwTxtNode& rNode, XubString& rT const xub_StrLen nStt, const xub_StrLen nEnd, const xub_Unicode cChar ) { - SAL_WARN_IF( rNode.GetTxt().Len() != rText.Len(), "sw.core", "MaskHiddenRanges, string len mismatch" ); + assert(rNode.GetTxt().Len() == rText.Len()); PositionList aList; xub_StrLen nHiddenStart; @@ -2194,6 +2194,9 @@ SwTwips SwTxtFrm::HangingMargin() const void SwScriptInfo::selectHiddenTextProperty(const SwTxtNode& rNode, MultiSelection &rHiddenMulti) { + assert((!rNode.GetTxt().Len() && rHiddenMulti.GetTotalRange().Len() == 1) || + (rNode.GetTxt().Len() == rHiddenMulti.GetTotalRange().Len())); + const SfxPoolItem* pItem = 0; if( SFX_ITEM_SET == rNode.GetSwAttrSet().GetItemState( RES_CHRATR_HIDDEN, sal_True, &pItem ) && ((SvxCharHiddenItem*)pItem)->GetValue() ) @@ -2228,6 +2231,9 @@ void SwScriptInfo::selectHiddenTextProperty(const SwTxtNode& rNode, MultiSelecti void SwScriptInfo::selectRedLineDeleted(const SwTxtNode& rNode, MultiSelection &rHiddenMulti, bool bSelect) { + assert((!rNode.GetTxt().Len() && rHiddenMulti.GetTotalRange().Len() == 1) || + (rNode.GetTxt().Len() == rHiddenMulti.GetTotalRange().Len())); + const IDocumentRedlineAccess& rIDRA = *rNode.getIDocumentRedlineAccess(); if ( IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineMode() ) ) { @@ -2243,6 +2249,8 @@ void SwScriptInfo::selectRedLineDeleted(const SwTxtNode& rNode, MultiSelection & xub_StrLen nRedlStart; xub_StrLen nRedlnEnd; pRed->CalcStartEnd( rNode.GetIndex(), nRedlStart, nRedlnEnd ); + //clip it if the redline extends past the end of the nodes text + nRedlnEnd = std::min(nRedlnEnd, rNode.GetTxt().Len()); if ( nRedlnEnd > nRedlStart ) { Range aTmp( nRedlStart, nRedlnEnd - 1 ); diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx index daeda95..66650ba 100644 --- a/sw/source/core/txtnode/txtedt.cxx +++ b/sw/source/core/txtnode/txtedt.cxx @@ -1860,8 +1860,8 @@ void SwTxtNode::CountWords( SwDocStat& rStat, return; } - // expand text into aConversionMap for scanner - const ModelToViewHelper aConversionMap(*this); + // ConversionMap to expand fields, remove invisible and redline deleted text for scanner + const ModelToViewHelper aConversionMap(*this, EXPANDFIELDS | HIDEINVISIBLE | HIDEREDLINED); rtl::OUString aExpandText = aConversionMap.getViewText(); // map start and end points onto the ConversionMap @@ -1874,12 +1874,6 @@ void SwTxtNode::CountWords( SwDocStat& rStat, return; } - // make a copy of the expanded text for masking redlined/hidden text with ' ' - String textCopy = aExpandText; - const xub_Unicode cChar(' '); - const sal_uInt16 nNumOfMaskedChars = lcl_MaskRedlinesAndHiddenText( *this, textCopy, nExpandBegin, nExpandEnd, cChar, false ); - aExpandText = textCopy; - //do the count // all counts exclude hidden paras and hidden+redlined within para // definition of space/white chars in SwScanner (and BreakIter!) @@ -1914,7 +1908,6 @@ void SwTxtNode::CountWords( SwDocStat& rStat, } nTmpChars = pBreakIt->getGraphemeCount(aExpandText, nExpandBegin, nExpandEnd); - nTmpChars -= nNumOfMaskedChars; // no nTmpCharsExcludingSpaces adjust needed neither for blanked out MaskedChars // nor for mid-word selection - set scanner bClip = true at creation commit 27c2fe405ca55a2630176a657fb4895c5e31fcea Author: Caolán McNamara <caol...@redhat.com> Date: Thu Aug 2 17:01:19 2012 +0100 Related: fdo#46757 extend ModelToViewHelper for more cases beef up ModelToViewHelper to be able to optionally expand fields, collapse hidden text and collapse/expand redline deleted text Change-Id: I6d4d0969102ad9699f7fafe091b2eff6a5707bc4 diff --git a/sw/CppunitTest_sw_swdoc_test.mk b/sw/CppunitTest_sw_swdoc_test.mk index 94ebab3..b3ab7d7 100644 --- a/sw/CppunitTest_sw_swdoc_test.mk +++ b/sw/CppunitTest_sw_swdoc_test.mk @@ -77,6 +77,7 @@ $(eval $(call gb_CppunitTest_use_externals,sw_swdoc_test,\ $(eval $(call gb_CppunitTest_set_include,sw_swdoc_test,\ -I$(SRCDIR)/sw/source/ui/inc \ + -I$(SRCDIR)/sw/source/core/inc \ -I$(SRCDIR)/sw/inc \ $$(INCLUDE) \ )) diff --git a/sw/inc/modeltoviewhelper.hxx b/sw/inc/modeltoviewhelper.hxx index c7a80c5..835044d 100644 --- a/sw/inc/modeltoviewhelper.hxx +++ b/sw/inc/modeltoviewhelper.hxx @@ -34,7 +34,38 @@ class SwTxtNode; to expand the fields to get the string as it appears in the view. Two helper functions are provided to convert model positions to view positions and vice versa. + + CH_TXTATR_BREAKWORD -> SwTxtNode will have field attributes associated with these + . . + . . + . . + AAAAA BBBBB # CCCCC # DDDDD + | | | | + | | | | + | --------- + | | . + | | . + | | .......... bounds of a hidden text character attribute + ------ + . + . + .............. a range of text defined in redline region as deleted + + 0000: pass through gives: AAAAA BBBBB # CCCCC # DDDDD + 0001: only expanding fields gives: AAAAA BBBBB foo CCCCC foo DDDDD + 0010: only hiding hiddens gives: AAAAA CCCCC # DDDDD + 0100: only hiding redlines gives: AAAABB # CCCCC # DDDDD + 0011: expanding fields + hiding hiddens gives: AAAAA CCCC foo DDDDD + 0101: expanding fields + hiding redlines gives: AAAA B foo CCCCC foo DDDDD + 0110: hiding hiddens + hiding redlines gives: AAAACCCC # DDDDD + 0111: expanding fields + hiding hiddens + hiding redlines gives: AAAABB foo CCCCC foo DDDDD */ + +#define PASSTHROUGH 0x0000 +#define EXPANDFIELDS 0x0001 +#define HIDEINVISIBLE 0x0002 +#define HIDEREDLINED 0x0004 + class ModelToViewHelper { /** For each field in the model string, there is an entry in the conversion @@ -67,8 +98,10 @@ public: ModelPosition() : mnPos(0), mnSubPos(0), mbIsField(false) {} }; - ModelToViewHelper(const SwTxtNode &rNode); - ModelToViewHelper() {} //pass through filter, view == model + ModelToViewHelper(const SwTxtNode &rNode, int eMode = EXPANDFIELDS); + ModelToViewHelper() //pass through filter, view == model + { + } /** Converts a model position into a view position diff --git a/sw/qa/core/swdoc-test.cxx b/sw/qa/core/swdoc-test.cxx index 3e26b1f..a5df143 100644 --- a/sw/qa/core/swdoc-test.cxx +++ b/sw/qa/core/swdoc-test.cxx @@ -38,6 +38,7 @@ #include <unotools/tempfile.hxx> #include <editeng/langitem.hxx> +#include <editeng/charhiddenitem.hxx> #include <sfx2/app.hxx> #include <sfx2/docfilt.hxx> @@ -63,6 +64,8 @@ #include "fmtfld.hxx" #include "redline.hxx" #include "docary.hxx" +#include "modeltoviewhelper.hxx" +#include "scriptinfo.hxx" SO2_DECL_REF(SwDocShell) SO2_IMPL_REF(SwDocShell) @@ -81,6 +84,7 @@ public: void testPageDescName(); void testFileNameFields(); void testDocStat(); + void testModelToViewHelper(); void testSwScanner(); void testUserPerceivedCharCount(); void testGraphicAnchorDeletion(); @@ -90,6 +94,7 @@ public: CPPUNIT_TEST(testPageDescName); CPPUNIT_TEST(testFileNameFields); CPPUNIT_TEST(testDocStat); + CPPUNIT_TEST(testModelToViewHelper); CPPUNIT_TEST(testSwScanner); CPPUNIT_TEST(testUserPerceivedCharCount); CPPUNIT_TEST(testGraphicAnchorDeletion); @@ -222,6 +227,112 @@ void SwDocTest::testUserPerceivedCharCount() CPPUNIT_ASSERT_MESSAGE("Surrogate Pair should be counted as single character", nCount == 1); } +void SwDocTest::testModelToViewHelper() +{ + SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1); + SwPaM aPaM(aIdx); + + { + SwFmtFtn aFtn; + aFtn.SetNumStr(rtl::OUString("foo")); + + m_pDoc->AppendTxtNode(*aPaM.GetPoint()); + m_pDoc->InsertString(aPaM, rtl::OUString("AAAAA BBBBB ")); + SwTxtNode* pTxtNode = aPaM.GetNode()->GetTxtNode(); + xub_StrLen nPos = aPaM.GetPoint()->nContent.GetIndex(); + pTxtNode->InsertItem(aFtn, nPos, nPos); + m_pDoc->InsertString(aPaM, rtl::OUString(" CCCCC ")); + nPos = aPaM.GetPoint()->nContent.GetIndex(); + pTxtNode->InsertItem(aFtn, nPos, nPos); + m_pDoc->InsertString(aPaM, rtl::OUString(" DDDDD")); + CPPUNIT_ASSERT(pTxtNode->GetTxt().Len() == (4*5) + 5 + 2); + + //set start of selection to first B + aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 6); + aPaM.SetMark(); + //set end of selection to last C + aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 14); + //set character attribute hidden on range + SvxCharHiddenItem aHidden(true, RES_CHRATR_HIDDEN); + m_pDoc->InsertPoolItem(aPaM, aHidden, 0 ); + + //turn on red-lining and show changes + m_pDoc->SetRedlineMode(nsRedlineMode_t::REDLINE_ON | nsRedlineMode_t::REDLINE_SHOW_DELETE|nsRedlineMode_t::REDLINE_SHOW_INSERT); + CPPUNIT_ASSERT_MESSAGE("redlining should be on", m_pDoc->IsRedlineOn()); + CPPUNIT_ASSERT_MESSAGE("redlines should be visible", IDocumentRedlineAccess::IsShowChanges(m_pDoc->GetRedlineMode())); + + //set start of selection to last A + aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 4); + aPaM.SetMark(); + //set end of selection to second last B + aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 9); + m_pDoc->DeleteAndJoin(aPaM); //redline-aware deletion api + + { + ModelToViewHelper aModelToViewHelper(*pTxtNode, PASSTHROUGH); + rtl::OUString sViewText = aModelToViewHelper.getViewText(); + rtl::OUString sModelText = pTxtNode->GetTxt(); + CPPUNIT_ASSERT(sViewText == sModelText); + } + + { + ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS); + rtl::OUString sViewText = aModelToViewHelper.getViewText(); + CPPUNIT_ASSERT(sViewText == "AAAAA BBBBB foo CCCCC foo DDDDD"); + } + + { + ModelToViewHelper aModelToViewHelper(*pTxtNode, HIDEINVISIBLE); + rtl::OUString sViewText = aModelToViewHelper.getViewText(); + rtl::OUStringBuffer aBuffer; + aBuffer.append("AAAAA CCCCC "); + aBuffer.append(CH_TXTATR_BREAKWORD); + aBuffer.append(" DDDDD"); + CPPUNIT_ASSERT(sViewText == aBuffer.makeStringAndClear()); + } + + { + ModelToViewHelper aModelToViewHelper(*pTxtNode, HIDEREDLINED); + rtl::OUString sViewText = aModelToViewHelper.getViewText(); + rtl::OUStringBuffer aBuffer; + aBuffer.append("AAAABB "); + aBuffer.append(CH_TXTATR_BREAKWORD); + aBuffer.append(" CCCCC "); + aBuffer.append(CH_TXTATR_BREAKWORD); + aBuffer.append(" DDDDD"); + CPPUNIT_ASSERT(sViewText == aBuffer.makeStringAndClear()); + } + + { + ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS | HIDEINVISIBLE); + rtl::OUString sViewText = aModelToViewHelper.getViewText(); + CPPUNIT_ASSERT(sViewText == "AAAAA CCCCC foo DDDDD"); + } + + { + ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS | HIDEREDLINED); + rtl::OUString sViewText = aModelToViewHelper.getViewText(); + CPPUNIT_ASSERT(sViewText == "AAAABB foo CCCCC foo DDDDD"); + } + + { + ModelToViewHelper aModelToViewHelper(*pTxtNode, HIDEINVISIBLE | HIDEREDLINED); + rtl::OUString sViewText = aModelToViewHelper.getViewText(); + rtl::OUStringBuffer aBuffer; + aBuffer.append("AAAACCCCC "); + aBuffer.append(CH_TXTATR_BREAKWORD); + aBuffer.append(" DDDDD"); + CPPUNIT_ASSERT(sViewText == aBuffer.makeStringAndClear()); + } + + { + ModelToViewHelper aModelToViewHelper(*pTxtNode, EXPANDFIELDS | HIDEINVISIBLE | HIDEREDLINED); + rtl::OUString sViewText = aModelToViewHelper.getViewText(); + CPPUNIT_ASSERT(sViewText == "AAAACCCCC foo DDDDD"); + } + } +} + void SwDocTest::testSwScanner() { SwNodeIndex aIdx(m_pDoc->GetNodes().GetEndOfContent(), -1); diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index 90e9a2b..22ddb66 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -37,6 +37,7 @@ #include <editeng/tstpitem.hxx> #include <svl/urihelper.hxx> #include <svl/ctloptions.hxx> +#include <tools/multisel.hxx> #include <swmodule.hxx> #include <txtfld.hxx> #include <txtinet.hxx> @@ -3092,52 +3093,131 @@ sal_Bool SwTxtNode::GetExpandTxt( SwTxtNode& rDestNd, const SwIndex* pDestIdx, return sal_True; } -ModelToViewHelper::ModelToViewHelper(const SwTxtNode &rNode) +struct block +{ + sal_Int32 m_nStart; + sal_Int32 m_nLen; + bool m_bVisible; + std::vector<const SwTxtAttr*> m_aAttrs; + block(sal_Int32 nStart, sal_Int32 nLen, bool bVisible) + : m_nStart(nStart), m_nLen(nLen), m_bVisible(bVisible) + { + } +}; + +struct containsPos +{ + const sal_Int32 m_nPos; + containsPos(const sal_Int32 nPos) + : m_nPos(nPos) + { + } + bool operator() (const block& rIn) const + { + return m_nPos >= rIn.m_nStart && m_nPos < rIn.m_nStart + rIn.m_nLen; + } +}; + +ModelToViewHelper::ModelToViewHelper(const SwTxtNode &rNode, int eMode) { const rtl::OUString& rNodeText = rNode.GetTxt(); m_aRetText = rNodeText; - const SwpHints* pSwpHints2 = rNode.GetpSwpHints(); - xub_StrLen nPos = 0; + if (eMode == PASSTHROUGH) + return; + + Range aRange( 0, rNodeText.isEmpty() ? 0 : rNodeText.getLength() - 1); + MultiSelection aHiddenMulti(aRange); + + if (eMode & HIDEINVISIBLE) + SwScriptInfo::selectHiddenTextProperty(rNode, aHiddenMulti); - for ( sal_uInt16 i = 0; pSwpHints2 && i < pSwpHints2->Count(); ++i ) + if (eMode & HIDEREDLINED) + SwScriptInfo::selectRedLineDeleted(rNode, aHiddenMulti); + + std::vector<block> aBlocks; + + sal_Int32 nShownStart = 0; + for (size_t i = 0; i < aHiddenMulti.GetRangeCount(); ++i) { - const SwTxtAttr* pAttr = (*pSwpHints2)[i]; - bool bReplace = false; - xub_StrLen nFieldPos(STRING_NOTFOUND); - rtl::OUString aExpand; - switch (pAttr->Which()) + const Range& rRange = aHiddenMulti.GetRange(i); + sal_Int32 nHiddenStart = rRange.Min(); + sal_Int32 nHiddenEnd = rRange.Max() + 1; + sal_Int32 nHiddenLen = nHiddenEnd - nHiddenStart; + + sal_Int32 nShownEnd = nHiddenStart; + sal_Int32 nShownLen = nShownEnd - nShownStart; + + if (nShownLen) + aBlocks.push_back(block(nShownStart, nShownLen, true)); + + if (nHiddenLen) + aBlocks.push_back(block(nHiddenStart, nHiddenLen, false)); + + nShownStart = nHiddenEnd; + } + + sal_Int32 nTrailingShownLen = rNodeText.getLength() - nShownStart; + if (nTrailingShownLen) + aBlocks.push_back(block(nShownStart, nTrailingShownLen, true)); + + if (eMode & EXPANDFIELDS) + { + const SwpHints* pSwpHints2 = rNode.GetpSwpHints(); + for ( sal_uInt16 i = 0; pSwpHints2 && i < pSwpHints2->Count(); ++i ) { - case RES_TXTATR_FIELD: - bReplace = true; - aExpand = - static_cast<SwTxtFld const*>(pAttr)->GetFld().GetFld() - ->ExpandField(true); - nFieldPos = *pAttr->GetStart(); - break; - case RES_TXTATR_FTN: - { - bReplace = true; - const SwFmtFtn& rFtn = static_cast<SwTxtFtn const*>(pAttr)->GetFtn(); - const SwDoc *pDoc = rNode.GetDoc(); - aExpand = rFtn.GetViewNumStr(*pDoc); - nFieldPos = *pAttr->GetStart(); - } - break; - default: - if (pAttr->HasDummyChar()) - { - bReplace = true; - nFieldPos = *pAttr->GetStart(); - } - break; + const SwTxtAttr* pAttr = (*pSwpHints2)[i]; + if (pAttr->HasDummyChar()) + { + xub_StrLen nDummyCharPos = *pAttr->GetStart(); + if (aHiddenMulti.IsSelected(nDummyCharPos)) + continue; + std::vector<block>::iterator aFind = std::find_if(aBlocks.begin(), aBlocks.end(), containsPos(nDummyCharPos)); + aFind->m_aAttrs.push_back(pAttr); + } } + } + + sal_Int32 nOffset = 0; + for (std::vector<block>::iterator i = aBlocks.begin(); i != aBlocks.end(); ++i) + { + if (!i->m_bVisible) + { + const sal_Int32 nHiddenStart = i->m_nStart; + const sal_Int32 nHiddenLen = i->m_nLen; - if (bReplace) + m_aRetText = m_aRetText.replaceAt( nOffset + nHiddenStart, nHiddenLen, rtl::OUString() ); + m_aMap.push_back( ConversionMapEntry( nHiddenStart, nOffset + nHiddenStart ) ); + nOffset -= nHiddenLen; + } + else { - m_aRetText = m_aRetText.replaceAt( nPos + nFieldPos, 1, aExpand ); - m_aMap.push_back( ConversionMapEntry( nFieldPos, nPos + nFieldPos ) ); - nPos += ( aExpand.getLength() - 1 ); + for (std::vector<const SwTxtAttr*>::iterator j = i->m_aAttrs.begin(); j != i->m_aAttrs.end(); ++j) + { + const SwTxtAttr* pAttr = *j; + xub_StrLen nFieldPos = *pAttr->GetStart(); + rtl::OUString aExpand; + switch (pAttr->Which()) + { + case RES_TXTATR_FIELD: + aExpand = + static_cast<SwTxtFld const*>(pAttr)->GetFld().GetFld() + ->ExpandField(true); + break; + case RES_TXTATR_FTN: + { + const SwFmtFtn& rFtn = static_cast<SwTxtFtn const*>(pAttr)->GetFtn(); + const SwDoc *pDoc = rNode.GetDoc(); + aExpand = rFtn.GetViewNumStr(*pDoc); + } + break; + default: + break; + } + m_aRetText = m_aRetText.replaceAt( nOffset + nFieldPos, 1, aExpand ); + m_aMap.push_back( ConversionMapEntry( nFieldPos, nOffset + nFieldPos ) ); + nOffset += ( aExpand.getLength() - 1 ); + } } }
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits