sw/Library_sw.mk | 1 sw/inc/ToxTextGenerator.hxx | 59 ++++ sw/inc/tox.hxx | 5 sw/source/core/doc/doctxm.cxx | 362 +----------------------------- sw/source/core/tox/ToxTextGenerator.cxx | 379 ++++++++++++++++++++++++++++++++ sw/source/core/tox/tox.cxx | 6 6 files changed, 462 insertions(+), 350 deletions(-)
New commits: commit 4ed0c3dd4e71275b7018d86bc71f8a935219aeae Author: Tobias Lippert <d...@fastmail.fm> Date: Sun Jun 1 14:13:28 2014 +0200 Extract TOX text generation to its own source file The separate source file will make it easier to unit test the functionality Also: move some constants to tox.hxx to have them available in the new source file Conflicts: sw/source/core/doc/doctxm.cxx Change-Id: Ib0369cc4875043829f55d30a549997560a38cc35 Reviewed-on: https://gerrit.libreoffice.org/9607 Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk index d9eecf0..c9804a0 100644 --- a/sw/Library_sw.mk +++ b/sw/Library_sw.mk @@ -388,6 +388,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\ sw/source/core/tox/tox \ sw/source/core/tox/toxhlp \ sw/source/core/tox/txmsrt \ + sw/source/core/tox/ToxTextGenerator \ sw/source/core/txtnode/SwGrammarContact \ sw/source/core/txtnode/atrfld \ sw/source/core/txtnode/atrflyin \ diff --git a/sw/inc/ToxTextGenerator.hxx b/sw/inc/ToxTextGenerator.hxx new file mode 100644 index 0000000..6a5dbd9 --- /dev/null +++ b/sw/inc/ToxTextGenerator.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef SW_TOXTEXTGENERATOR_HXX_ +#define SW_TOXTEXTGENERATOR_HXX_ + +#include "sal/types.h" +#include "swdllapi.h" +#include <vector> + +class SwDoc; +class SwForm; +class SwPageDesc; +class SwTOXSortTabBase; + +namespace sw { + +class SW_DLLPUBLIC ToxTextGenerator +{ +public: + ToxTextGenerator(const SwForm& toxForm) + : mToxForm(toxForm) + {} + /** Generate the text for an entry of a table of X (X is, e.g., content). + * + * This method will process the entries in @p entries, starting at @p indexOfEntryToProcess and + * process @p numberOfEntriesToProcess entries. + */ + void + GenerateText(SwDoc *doc, const std::vector<SwTOXSortTabBase*>& entries, + sal_uInt16 indexOfEntryToProcess, sal_uInt16 numberOfEntriesToProcess, + sal_uInt32 _nTOXSectNdIdx, const SwPageDesc* _pDefaultPageDesc); + + +private: + const SwForm& mToxForm; +}; + +} + +#endif /* SW_TOXTEXTGENERATOR_HXX_ */ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/inc/tox.hxx b/sw/inc/tox.hxx index 86565af..375a27b 100644 --- a/sw/inc/tox.hxx +++ b/sw/inc/tox.hxx @@ -43,6 +43,11 @@ class SwDoc; class SwTOXMarks : public std::vector<SwTOXMark*> {}; // Entry of content index, alphabetical index or user defined index + +extern const sal_Unicode C_NUM_REPL; +extern const sal_Unicode C_END_PAGE_NUM; +extern const OUString S_PAGE_DELI; + class SW_DLLPUBLIC SwTOXMark : public SfxPoolItem , public SwModify diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx index bf5081f..6ea9279 100644 --- a/sw/source/core/doc/doctxm.cxx +++ b/sw/source/core/doc/doctxm.cxx @@ -64,28 +64,12 @@ #include <editsh.hxx> #include <scriptinfo.hxx> #include <switerator.hxx> +#include <ToxTextGenerator.hxx> using namespace ::com::sun::star; -const sal_Unicode cNumRepl = '@'; -const sal_Unicode cEndPageNum = '~'; -const sal_Char sPageDeli[] = ", "; - TYPEINIT2( SwTOXBaseSection, SwTOXBase, SwSection ); // for RTTI -struct LinkStruct -{ - SwFmtINetFmt aINetFmt; - sal_Int32 nStartTextPos, nEndTextPos; - - LinkStruct( const OUString& rURL, sal_Int32 nStart, sal_Int32 nEnd ) - : aINetFmt( rURL, OUString()), - nStartTextPos( nStart), - nEndTextPos(nEnd) {} -}; - -typedef std::vector<LinkStruct*> LinkStructArr; - sal_uInt16 SwDoc::GetTOIKeys( SwTOIKeyType eTyp, std::vector<OUString>& rArr ) const { rArr.clear(); @@ -990,7 +974,9 @@ void SwTOXBaseSection::Update(const SfxItemSet* pAttr, } // pass node index of table-of-content section and default page description // to method <GenerateText(..)>. - GenerateText( nCnt, nRange, pSectNd->GetIndex(), pDefaultPageDesc ); + ::SetProgressState( 0, pDoc->GetDocShell() ); + sw::ToxTextGenerator ttgn(GetTOXForm()); + ttgn.GenerateText((SwDoc*) GetFmt()->GetDoc(), aSortArr, nCnt, nRange, pSectNd->GetIndex(), pDefaultPageDesc); nCnt += nRange - 1; } @@ -1534,330 +1520,6 @@ void SwTOXBaseSection::UpdateTable( const SwTxtNode* pOwnChapterNode ) } } -/// Generate String according to the Form and remove the -/// special characters 0-31 and 255. -static OUString lcl_GetNumString( const SwTOXSortTabBase& rBase, bool bUsePrefix, sal_uInt8 nLevel ) -{ - OUString sRet; - - if( !rBase.pTxtMark && !rBase.aTOXSources.empty() ) - { // only if it's not a Mark - const SwTxtNode* pNd = rBase.aTOXSources[0].pNd->GetTxtNode(); - if( pNd ) - { - const SwNumRule* pRule = pNd->GetNumRule(); - - if( pRule && pNd->GetActualListLevel() < MAXLEVEL ) - sRet = pNd->GetNumString(bUsePrefix, nLevel); - } - } - return sRet; -} - -/// Generate String with newlines changed to spaces, consecutive spaces changed -/// to a single space, and trailing space removed. -OUString lcl_RemoveLineBreaks(const OUString &rRet) -{ - if (rRet.isEmpty()) - return rRet; - sal_Int32 nOffset = 0; - OUStringBuffer sRet(rRet.replace('\n', ' ')); - for (sal_Int32 i = 1; i < sRet.getLength(); ++i) - { - if ( sRet[i - 1] == ' ' && sRet[i] == ' ' ) - { - nOffset += 1; - } - else - { - sRet[i - nOffset] = sRet[i]; - } - } - if (sRet[sRet.getLength() - 1] == ' ') - { - nOffset += 1; - } - return sRet.copy(0, sRet.getLength() - nOffset).toString(); -} - -// Add parameter <_TOXSectNdIdx> and <_pDefaultPageDesc> in order to control, -// which page description is used, no appropriate one is found. -void SwTOXBaseSection::GenerateText( sal_uInt16 nArrayIdx, - sal_uInt16 nCount, - const sal_uInt32 _nTOXSectNdIdx, - const SwPageDesc* _pDefaultPageDesc ) -{ - LinkStructArr aLinkArr; - SwDoc* pDoc = (SwDoc*)GetFmt()->GetDoc(); - ::SetProgressState( 0, pDoc->GetDocShell() ); - - // pTOXNd is only set at the first mark - SwTxtNode* pTOXNd = (SwTxtNode*)aSortArr[nArrayIdx]->pTOXNd; - // FIXME this operates directly on the node text - OUString & rTxt = const_cast<OUString&>(pTOXNd->GetTxt()); - rTxt = ""; - for(sal_uInt16 nIndex = nArrayIdx; nIndex < nArrayIdx + nCount; nIndex++) - { - if(nIndex > nArrayIdx) - rTxt += ", "; // comma separation - // Initialize String with the Pattern from the form - const SwTOXSortTabBase& rBase = *aSortArr[nIndex]; - sal_uInt16 nLvl = rBase.GetLevel(); - OSL_ENSURE( nLvl < GetTOXForm().GetFormMax(), "invalid FORM_LEVEL"); - - SvxTabStopItem aTStops( 0, 0, SVX_TAB_ADJUST_DEFAULT, RES_PARATR_TABSTOP ); - sal_Int32 nLinkStartPosition = -1; - OUString sLinkCharacterStyle; // default to "Default" character style - which is none - OUString sURL; - // create an enumerator - // #i21237# - SwFormTokens aPattern = GetTOXForm().GetPattern(nLvl); - SwFormTokens::iterator aIt = aPattern.begin(); - // remove text from node - while(aIt != aPattern.end()) // #i21237# - { - SwFormToken aToken = *aIt; // #i21237# - sal_Int32 nStartCharStyle = rTxt.getLength(); - switch( aToken.eTokenType ) - { - case TOKEN_ENTRY_NO: - // for TOC numbering - rTxt += lcl_GetNumString( rBase, aToken.nChapterFormat == CF_NUMBER, static_cast<sal_uInt8>(aToken.nOutlineLevel - 1) ) ; - break; - - case TOKEN_ENTRY_TEXT: - { - SwIndex aIdx( pTOXNd, std::min(pTOXNd->GetTxt().getLength(),rTxt.getLength()) ); - rBase.FillText( *pTOXNd, aIdx ); - rTxt = lcl_RemoveLineBreaks(rTxt); - } - break; - - case TOKEN_ENTRY: - { - // for TOC numbering - rTxt += lcl_GetNumString( rBase, true, MAXLEVEL ); - - SwIndex aIdx( pTOXNd, rTxt.getLength() ); - rBase.FillText( *pTOXNd, aIdx ); - rTxt = lcl_RemoveLineBreaks(rTxt); - } - break; - - case TOKEN_TAB_STOP: - if (aToken.bWithTab) // #i21237# - rTxt += "\t"; - - if(SVX_TAB_ADJUST_END > aToken.eTabAlign) - { - const SvxLRSpaceItem& rLR = - (SvxLRSpaceItem&)pTOXNd-> - SwCntntNode::GetAttr( RES_LR_SPACE, true ); - - long nTabPosition = aToken.nTabStopPosition; - if( !GetTOXForm().IsRelTabPos() && rLR.GetTxtLeft() ) - nTabPosition -= rLR.GetTxtLeft(); - aTStops.Insert( SvxTabStop( nTabPosition, - aToken.eTabAlign, - cDfltDecimalChar, - aToken.cTabFillChar )); - } - else - { - const SwPageDesc* pPageDesc = ((SwFmtPageDesc&)pTOXNd-> - SwCntntNode::GetAttr( RES_PAGEDESC )).GetPageDesc(); - - bool bCallFindRect = true; - long nRightMargin; - if( pPageDesc ) - { - const SwFrm* pFrm = pTOXNd->getLayoutFrm( pDoc->GetCurrentLayout(), 0, 0, true ); - if( !pFrm || 0 == ( pFrm = pFrm->FindPageFrm() ) || - pPageDesc != ((SwPageFrm*)pFrm)->GetPageDesc() ) - // we have to go via the PageDesc here - bCallFindRect = false; - } - - SwRect aNdRect; - if( bCallFindRect ) - aNdRect = pTOXNd->FindLayoutRect( true ); - - if( aNdRect.IsEmpty() ) - { - // Nothing helped so far, so we go via the PageDesc - sal_uInt32 nPgDescNdIdx = pTOXNd->GetIndex() + 1; - sal_uInt32* pPgDescNdIdx = &nPgDescNdIdx; - pPageDesc = pTOXNd->FindPageDesc( false, pPgDescNdIdx ); - if ( !pPageDesc || - *pPgDescNdIdx < _nTOXSectNdIdx ) - { - // Use default page description, if none is found - // or the found one is given by a Node before the - // table-of-content section. - pPageDesc = _pDefaultPageDesc; - } - - const SwFrmFmt& rPgDscFmt = pPageDesc->GetMaster(); - nRightMargin = rPgDscFmt.GetFrmSize().GetWidth() - - rPgDscFmt.GetLRSpace().GetLeft() - - rPgDscFmt.GetLRSpace().GetRight(); - } - else - nRightMargin = aNdRect.Width(); - //#i24363# tab stops relative to indent - if( pDoc->GetDocumentSettingManager().get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT) ) - { - // left margin of paragraph style - const SvxLRSpaceItem& rLRSpace = pTOXNd->GetTxtColl()->GetLRSpace(); - nRightMargin -= rLRSpace.GetLeft(); - nRightMargin -= rLRSpace.GetTxtFirstLineOfst(); - } - - aTStops.Insert( SvxTabStop( nRightMargin, SVX_TAB_ADJUST_RIGHT, - cDfltDecimalChar, - aToken.cTabFillChar )); - } - break; - - case TOKEN_TEXT: - rTxt += aToken.sText; - break; - - case TOKEN_PAGE_NUMS: - // Place holder for the PageNumber; we only respect the first one - { - // The count of similar entries gives the PagerNumber pattern - size_t nSize = rBase.aTOXSources.size(); - if (nSize > 0) - { - OUString aInsStr = OUString(cNumRepl); - for (size_t i = 1; i < nSize; ++i) - { - aInsStr += sPageDeli; - aInsStr += OUString(cNumRepl); - } - aInsStr += OUString(cEndPageNum); - rTxt += aInsStr; - } - } - break; - - case TOKEN_CHAPTER_INFO: - { - // A bit tricky: Find a random Frame - const SwTOXSource* pTOXSource = 0; - if (!rBase.aTOXSources.empty()) - pTOXSource = &rBase.aTOXSources[0]; - - // #i53420# - if ( pTOXSource && pTOXSource->pNd && - pTOXSource->pNd->IsCntntNode() ) - { - const SwCntntFrm* pFrm = pTOXSource->pNd->getLayoutFrm( pDoc->GetCurrentLayout() ); - if( pFrm ) - { - SwChapterFieldType aFldTyp; - SwChapterField aFld( &aFldTyp, aToken.nChapterFormat ); - aFld.SetLevel( static_cast<sal_uInt8>(aToken.nOutlineLevel - 1) ); - // #i53420# - aFld.ChangeExpansion( pFrm, - dynamic_cast<const SwCntntNode*>(pTOXSource->pNd), - true ); - //---> #i89791# - // continue to support CF_NUMBER - // and CF_NUM_TITLE in order to handle ODF 1.0/1.1 - // written by OOo 3.x in the same way as OOo 2.x - // would handle them. - if ( CF_NUM_NOPREPST_TITLE == aToken.nChapterFormat || - CF_NUMBER == aToken.nChapterFormat ) - rTxt += aFld.GetNumber(); // get the string number without pre/postfix - else if ( CF_NUMBER_NOPREPST == aToken.nChapterFormat || - CF_NUM_TITLE == aToken.nChapterFormat ) - { - rTxt += aFld.GetNumber(); - rTxt += " "; - rTxt += aFld.GetTitle(); - } - else if(CF_TITLE == aToken.nChapterFormat) - rTxt += aFld.GetTitle(); - } - } - } - break; - - case TOKEN_LINK_START: - nLinkStartPosition = rTxt.getLength(); - sLinkCharacterStyle = aToken.sCharStyleName; - break; - - case TOKEN_LINK_END: - //TODO: only paired start/end tokens are valid - if (nLinkStartPosition != -1) - { - SwIndex aIdx( pTOXNd, nLinkStartPosition ); - // pTOXNd->Erase( aIdx, SwForm::nFormLinkSttLen ); - sal_Int32 nEnd = rTxt.getLength(); - - if( sURL.isEmpty() ) - { - sURL = rBase.GetURL(); - if( sURL.isEmpty() ) - break; - } - LinkStruct* pNewLink = new LinkStruct(sURL, nLinkStartPosition, - nEnd); - const sal_uInt16 nPoolId = - sLinkCharacterStyle.isEmpty() - ? USHRT_MAX - : SwStyleNameMapper::GetPoolIdFromUIName( sLinkCharacterStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT ); - pNewLink->aINetFmt.SetVisitedFmtAndId( sLinkCharacterStyle, nPoolId ); - pNewLink->aINetFmt.SetINetFmtAndId( sLinkCharacterStyle, nPoolId ); - aLinkArr.push_back(pNewLink); - nLinkStartPosition = -1; - sLinkCharacterStyle = ""; - } - break; - - case TOKEN_AUTHORITY: - { - ToxAuthorityField eField = (ToxAuthorityField)aToken.nAuthorityField; - SwIndex aIdx( pTOXNd, rTxt.getLength() ); - rBase.FillText( *pTOXNd, aIdx, static_cast<sal_uInt16>(eField) ); - } - break; - case TOKEN_END: break; - } - - if ( !aToken.sCharStyleName.isEmpty() ) - { - SwCharFmt* pCharFmt; - if( USHRT_MAX != aToken.nPoolId ) - pCharFmt = pDoc->GetCharFmtFromPool( aToken.nPoolId ); - else - pCharFmt = pDoc->FindCharFmtByName( aToken.sCharStyleName); - - if (pCharFmt) - { - SwFmtCharFmt aFmt( pCharFmt ); - pTOXNd->InsertItem( aFmt, nStartCharStyle, - rTxt.getLength(), nsSetAttrMode::SETATTR_DONTEXPAND ); - } - } - - ++aIt; // #i21237# - } - - pTOXNd->SetAttr( aTStops ); - } - - for(LinkStructArr::const_iterator i = aLinkArr.begin(); i != aLinkArr.end(); ++i) - { - pTOXNd->InsertItem((*i)->aINetFmt, (*i)->nStartTextPos, - (*i)->nEndTextPos); - delete (*i); - } -} - /// Calculate PageNumber and insert after formatting void SwTOXBaseSection::UpdatePageNum() { @@ -1990,11 +1652,11 @@ void SwTOXBaseSection::_UpdatePageNum( SwTxtNode* pNd, // collect starts end ends of main entry character style boost::scoped_ptr< std::vector<sal_uInt16> > xCharStyleIdx(pMainEntryNums ? new std::vector<sal_uInt16> : 0); - OUString sSrchStr = OUStringBuffer().append(cNumRepl). - append(sPageDeli).append(cNumRepl).makeStringAndClear(); + OUString sSrchStr = OUStringBuffer().append(C_NUM_REPL). + append(S_PAGE_DELI).append(C_NUM_REPL).makeStringAndClear(); sal_Int32 nStartPos = pNd->GetTxt().indexOf(sSrchStr); - sSrchStr = OUStringBuffer().append(cNumRepl). - append(cEndPageNum).makeStringAndClear(); + sSrchStr = OUStringBuffer().append(C_NUM_REPL). + append(C_END_PAGE_NUM).makeStringAndClear(); sal_Int32 nEndPos = pNd->GetTxt().indexOf(sSrchStr); sal_uInt16 i; @@ -2061,7 +1723,7 @@ void SwTOXBaseSection::_UpdatePageNum( SwTxtNode* pNd, if(nCount >= 2 ) aNumStr += "-"; else if(nCount == 1 ) - aNumStr += sPageDeli; + aNumStr += S_PAGE_DELI; //#58127# If nCount == 0, then the only PageNumber is already in aNumStr! if(nCount) aNumStr += aType.GetNumStr( nBeg + nCount ); @@ -2069,7 +1731,7 @@ void SwTOXBaseSection::_UpdatePageNum( SwTxtNode* pNd, // Create new String nBeg = rNums[i]; - aNumStr += sPageDeli; + aNumStr += S_PAGE_DELI; //the change of the character style must apply after sPageDeli is appended if (xCharStyleIdx && bMainEntryChanges) { @@ -2084,7 +1746,7 @@ void SwTOXBaseSection::_UpdatePageNum( SwTxtNode* pNd, { // Insert all Numbers aNumStr += aType.GetNumStr( sal_uInt16(rNums[i]) ); if(i != (rNums.size()-1)) - aNumStr += sPageDeli; + aNumStr += S_PAGE_DELI; } } // Flush when ending and the following old values @@ -2100,7 +1762,7 @@ void SwTOXBaseSection::_UpdatePageNum( SwTxtNode* pNd, if(nCount >= 2) aNumStr += "-"; else if(nCount == 1) - aNumStr += sPageDeli; + aNumStr += S_PAGE_DELI; //#58127# If nCount == 0, then the only PageNumber is already in aNumStr! if(nCount) aNumStr += SvxNumberType( rDescs[i-1]->GetNumType() ).GetNumStr( nBeg+nCount ); diff --git a/sw/source/core/tox/ToxTextGenerator.cxx b/sw/source/core/tox/ToxTextGenerator.cxx new file mode 100644 index 0000000..54d7b6a --- /dev/null +++ b/sw/source/core/tox/ToxTextGenerator.cxx @@ -0,0 +1,379 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ToxTextGenerator.hxx> + +#include "chpfld.hxx" +#include "cntfrm.hxx" +#include "pagefrm.hxx" +#include "fchrfmt.hxx" +#include "doc.hxx" +#include "fmtinfmt.hxx" +#include "ndtxt.hxx" +#include "pagedesc.hxx" +#include "tox.hxx" +#include "txmsrt.hxx" +#include "fmtfsize.hxx" +#include "fmtpdsc.hxx" +#include "DocumentSettingManager.hxx" +#include "SwStyleNameMapper.hxx" + +#include "editeng/tstpitem.hxx" +#include "editeng/lrspitem.hxx" +#include "rtl/ustring.hxx" + +struct LinkStruct +{ + SwFmtINetFmt aINetFmt; + sal_Int32 nStartTextPos, nEndTextPos; + + LinkStruct( const OUString& rURL, sal_Int32 nStart, sal_Int32 nEnd ) + : aINetFmt( rURL, OUString()), + nStartTextPos( nStart), + nEndTextPos(nEnd) {} +}; + +/// Generate String with newlines changed to spaces, consecutive spaces changed +/// to a single space, and trailing space removed. +OUString lcl_RemoveLineBreaks(const OUString &rRet) +{ + if (rRet.isEmpty()) + return rRet; + sal_Int32 nOffset = 0; + OUStringBuffer sRet(rRet.replace('\n', ' ')); + for (sal_Int32 i = 1; i < sRet.getLength(); ++i) + { + if ( sRet[i - 1] == ' ' && sRet[i] == ' ' ) + { + nOffset += 1; + } + else + { + sRet[i - nOffset] = sRet[i]; + } + } + if (sRet[sRet.getLength() - 1] == ' ') + { + nOffset += 1; + } + return sRet.copy(0, sRet.getLength() - nOffset).toString(); +} + +/// Generate String according to the Form and remove the +/// special characters 0-31 and 255. +static OUString lcl_GetNumString( const SwTOXSortTabBase& rBase, bool bUsePrefix, sal_uInt8 nLevel ) +{ + OUString sRet; + + if( !rBase.pTxtMark && !rBase.aTOXSources.empty() ) + { // only if it's not a Mark + const SwTxtNode* pNd = rBase.aTOXSources[0].pNd->GetTxtNode(); + if( pNd ) + { + const SwNumRule* pRule = pNd->GetNumRule(); + + if( pRule && pNd->GetActualListLevel() < MAXLEVEL ) + sRet = pNd->GetNumString(bUsePrefix, nLevel); + } + } + return sRet; +} + +typedef std::vector<LinkStruct*> LinkStructArr; + +namespace sw { + +// Add parameter <_TOXSectNdIdx> and <_pDefaultPageDesc> in order to control, +// which page description is used, no appropriate one is found. +void ToxTextGenerator::GenerateText(SwDoc* pDoc, const std::vector<SwTOXSortTabBase*> &entries, + sal_uInt16 indexOfEntryToProcess, sal_uInt16 numberOfEntriesToProcess, sal_uInt32 _nTOXSectNdIdx, + const SwPageDesc* _pDefaultPageDesc) +{ + LinkStructArr aLinkArr; + + // pTOXNd is only set at the first mark + SwTxtNode* pTOXNd = (SwTxtNode*)entries.at(indexOfEntryToProcess)->pTOXNd; + // FIXME this operates directly on the node text + OUString & rTxt = const_cast<OUString&>(pTOXNd->GetTxt()); + rTxt = ""; + for(sal_uInt16 nIndex = indexOfEntryToProcess; nIndex < indexOfEntryToProcess + numberOfEntriesToProcess; nIndex++) + { + if(nIndex > indexOfEntryToProcess) + rTxt += ", "; // comma separation + // Initialize String with the Pattern from the form + const SwTOXSortTabBase& rBase = *entries.at(nIndex); + sal_uInt16 nLvl = rBase.GetLevel(); + OSL_ENSURE( nLvl < mToxForm.GetFormMax(), "invalid FORM_LEVEL"); + + SvxTabStopItem aTStops( 0, 0, SVX_TAB_ADJUST_DEFAULT, RES_PARATR_TABSTOP ); + sal_Int32 nLinkStartPosition = -1; + OUString sLinkCharacterStyle; // default to "Default" character style - which is none + OUString sURL; + // create an enumerator + // #i21237# + SwFormTokens aPattern = mToxForm.GetPattern(nLvl); + SwFormTokens::iterator aIt = aPattern.begin(); + // remove text from node + while(aIt != aPattern.end()) // #i21237# + { + SwFormToken aToken = *aIt; // #i21237# + sal_Int32 nStartCharStyle = rTxt.getLength(); + switch( aToken.eTokenType ) + { + case TOKEN_ENTRY_NO: + // for TOC numbering + rTxt += lcl_GetNumString( rBase, aToken.nChapterFormat == CF_NUMBER, static_cast<sal_uInt8>(aToken.nOutlineLevel - 1) ) ; + break; + + case TOKEN_ENTRY_TEXT: + { + SwIndex aIdx( pTOXNd, std::min(pTOXNd->GetTxt().getLength(),rTxt.getLength()) ); + rBase.FillText( *pTOXNd, aIdx ); + rTxt = lcl_RemoveLineBreaks(rTxt); + } + break; + + case TOKEN_ENTRY: + { + // for TOC numbering + rTxt += lcl_GetNumString( rBase, true, MAXLEVEL ); + + SwIndex aIdx( pTOXNd, rTxt.getLength() ); + rBase.FillText( *pTOXNd, aIdx ); + rTxt = lcl_RemoveLineBreaks(rTxt); + } + break; + + case TOKEN_TAB_STOP: + if (aToken.bWithTab) // #i21237# + rTxt += "\t"; + + if(SVX_TAB_ADJUST_END > aToken.eTabAlign) + { + const SvxLRSpaceItem& rLR = + (SvxLRSpaceItem&)pTOXNd-> + SwCntntNode::GetAttr( RES_LR_SPACE, true ); + + long nTabPosition = aToken.nTabStopPosition; + if( !mToxForm.IsRelTabPos() && rLR.GetTxtLeft() ) + nTabPosition -= rLR.GetTxtLeft(); + aTStops.Insert( SvxTabStop( nTabPosition, + aToken.eTabAlign, + cDfltDecimalChar, + aToken.cTabFillChar )); + } + else + { + const SwPageDesc* pPageDesc = ((SwFmtPageDesc&)pTOXNd-> + SwCntntNode::GetAttr( RES_PAGEDESC )).GetPageDesc(); + + bool bCallFindRect = true; + long nRightMargin; + if( pPageDesc ) + { + const SwFrm* pFrm = pTOXNd->getLayoutFrm( pDoc->GetCurrentLayout(), 0, 0, true ); + if( !pFrm || 0 == ( pFrm = pFrm->FindPageFrm() ) || + pPageDesc != ((SwPageFrm*)pFrm)->GetPageDesc() ) + // we have to go via the PageDesc here + bCallFindRect = false; + } + + SwRect aNdRect; + if( bCallFindRect ) + aNdRect = pTOXNd->FindLayoutRect( true ); + + if( aNdRect.IsEmpty() ) + { + // Nothing helped so far, so we go via the PageDesc + sal_uInt32 nPgDescNdIdx = pTOXNd->GetIndex() + 1; + sal_uInt32* pPgDescNdIdx = &nPgDescNdIdx; + pPageDesc = pTOXNd->FindPageDesc( false, pPgDescNdIdx ); + if ( !pPageDesc || + *pPgDescNdIdx < _nTOXSectNdIdx ) + { + // Use default page description, if none is found + // or the found one is given by a Node before the + // table-of-content section. + pPageDesc = _pDefaultPageDesc; + } + + const SwFrmFmt& rPgDscFmt = pPageDesc->GetMaster(); + nRightMargin = rPgDscFmt.GetFrmSize().GetWidth() - + rPgDscFmt.GetLRSpace().GetLeft() - + rPgDscFmt.GetLRSpace().GetRight(); + } + else + nRightMargin = aNdRect.Width(); + //#i24363# tab stops relative to indent + if( pDoc->GetDocumentSettingManager().get(IDocumentSettingAccess::TABS_RELATIVE_TO_INDENT) ) + { + // left margin of paragraph style + const SvxLRSpaceItem& rLRSpace = pTOXNd->GetTxtColl()->GetLRSpace(); + nRightMargin -= rLRSpace.GetLeft(); + nRightMargin -= rLRSpace.GetTxtFirstLineOfst(); + } + + aTStops.Insert( SvxTabStop( nRightMargin, SVX_TAB_ADJUST_RIGHT, + cDfltDecimalChar, + aToken.cTabFillChar )); + } + break; + + case TOKEN_TEXT: + rTxt += aToken.sText; + break; + + case TOKEN_PAGE_NUMS: + // Place holder for the PageNumber; we only respect the first one + { + // The count of similar entries gives the PagerNumber pattern + size_t nSize = rBase.aTOXSources.size(); + if (nSize > 0) + { + OUString aInsStr = OUString(C_NUM_REPL); + for (size_t i = 1; i < nSize; ++i) + { + aInsStr += S_PAGE_DELI; + aInsStr += OUString(C_NUM_REPL); + } + aInsStr += OUString(C_END_PAGE_NUM); + rTxt += aInsStr; + } + } + break; + + case TOKEN_CHAPTER_INFO: + { + // A bit tricky: Find a random Frame + const SwTOXSource* pTOXSource = 0; + if (!rBase.aTOXSources.empty()) + pTOXSource = &rBase.aTOXSources[0]; + + // #i53420# + if ( pTOXSource && pTOXSource->pNd && + pTOXSource->pNd->IsCntntNode() ) + { + const SwCntntFrm* pFrm = pTOXSource->pNd->getLayoutFrm( pDoc->GetCurrentLayout() ); + if( pFrm ) + { + SwChapterFieldType aFldTyp; + SwChapterField aFld( &aFldTyp, aToken.nChapterFormat ); + aFld.SetLevel( static_cast<sal_uInt8>(aToken.nOutlineLevel - 1) ); + // #i53420# + aFld.ChangeExpansion( pFrm, + dynamic_cast<const SwCntntNode*>(pTOXSource->pNd), + true ); + //---> #i89791# + // continue to support CF_NUMBER + // and CF_NUM_TITLE in order to handle ODF 1.0/1.1 + // written by OOo 3.x in the same way as OOo 2.x + // would handle them. + if ( CF_NUM_NOPREPST_TITLE == aToken.nChapterFormat || + CF_NUMBER == aToken.nChapterFormat ) + rTxt += aFld.GetNumber(); // get the string number without pre/postfix + else if ( CF_NUMBER_NOPREPST == aToken.nChapterFormat || + CF_NUM_TITLE == aToken.nChapterFormat ) + { + rTxt += aFld.GetNumber(); + rTxt += " "; + rTxt += aFld.GetTitle(); + } + else if(CF_TITLE == aToken.nChapterFormat) + rTxt += aFld.GetTitle(); + } + } + } + break; + + case TOKEN_LINK_START: + nLinkStartPosition = rTxt.getLength(); + sLinkCharacterStyle = aToken.sCharStyleName; + break; + + case TOKEN_LINK_END: + //TODO: only paired start/end tokens are valid + if (nLinkStartPosition != -1) + { + SwIndex aIdx( pTOXNd, nLinkStartPosition ); + // pTOXNd->Erase( aIdx, SwForm::nFormLinkSttLen ); + sal_Int32 nEnd = rTxt.getLength(); + + if( sURL.isEmpty() ) + { + sURL = rBase.GetURL(); + if( sURL.isEmpty() ) + break; + } + LinkStruct* pNewLink = new LinkStruct(sURL, nLinkStartPosition, + nEnd); + const sal_uInt16 nPoolId = + sLinkCharacterStyle.isEmpty() + ? USHRT_MAX + : SwStyleNameMapper::GetPoolIdFromUIName( sLinkCharacterStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT ); + pNewLink->aINetFmt.SetVisitedFmtAndId( sLinkCharacterStyle, nPoolId ); + pNewLink->aINetFmt.SetINetFmtAndId( sLinkCharacterStyle, nPoolId ); + aLinkArr.push_back(pNewLink); + nLinkStartPosition = -1; + sLinkCharacterStyle = ""; + } + break; + + case TOKEN_AUTHORITY: + { + ToxAuthorityField eField = (ToxAuthorityField)aToken.nAuthorityField; + SwIndex aIdx( pTOXNd, rTxt.getLength() ); + rBase.FillText( *pTOXNd, aIdx, static_cast<sal_uInt16>(eField) ); + } + break; + case TOKEN_END: break; + } + + if ( !aToken.sCharStyleName.isEmpty() ) + { + SwCharFmt* pCharFmt; + if( USHRT_MAX != aToken.nPoolId ) + pCharFmt = pDoc->GetCharFmtFromPool( aToken.nPoolId ); + else + pCharFmt = pDoc->FindCharFmtByName( aToken.sCharStyleName); + + if (pCharFmt) + { + SwFmtCharFmt aFmt( pCharFmt ); + pTOXNd->InsertItem( aFmt, nStartCharStyle, + rTxt.getLength(), nsSetAttrMode::SETATTR_DONTEXPAND ); + } + } + + ++aIt; // #i21237# + } + + pTOXNd->SetAttr( aTStops ); + } + + for(LinkStructArr::const_iterator i = aLinkArr.begin(); i != aLinkArr.end(); ++i) + { + pTOXNd->InsertItem((*i)->aINetFmt, (*i)->nStartTextPos, + (*i)->nEndTextPos); + delete (*i); + } +} + +} // end namespace sw + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/tox/tox.cxx b/sw/source/core/tox/tox.cxx index b683ada..819b94f 100644 --- a/sw/source/core/tox/tox.cxx +++ b/sw/source/core/tox/tox.cxx @@ -41,6 +41,12 @@ using namespace std; + +const sal_Unicode C_NUM_REPL = '@'; +const sal_Unicode C_END_PAGE_NUM = '~'; +const OUString S_PAGE_DELI(", "); + + namespace {
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits