2014-06-01 14:13:28 +02:00
|
|
|
/* -*- 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"
|
2014-06-01 14:15:35 +02:00
|
|
|
#include "ToxWhitespaceStripper.hxx"
|
2014-06-01 14:13:28 +02:00
|
|
|
|
|
|
|
#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 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()) );
|
2014-06-01 14:15:35 +02:00
|
|
|
ToxWhitespaceStripper stripper(rBase.GetTxt().sText);
|
|
|
|
pTOXNd->InsertText(stripper.GetStrippedString(), aIdx);
|
2014-06-01 14:13:28 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TOKEN_ENTRY:
|
|
|
|
{
|
|
|
|
// for TOC numbering
|
|
|
|
rTxt += lcl_GetNumString( rBase, true, MAXLEVEL );
|
|
|
|
SwIndex aIdx( pTOXNd, rTxt.getLength() );
|
2014-06-01 14:15:35 +02:00
|
|
|
ToxWhitespaceStripper stripper(rBase.GetTxt().sText);
|
|
|
|
pTOXNd->InsertText(stripper.GetStrippedString(), aIdx);
|
2014-06-01 14:13:28 +02:00
|
|
|
}
|
|
|
|
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: */
|