973 lines
30 KiB
C++
973 lines
30 KiB
C++
/* -*- 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 <calbck.hxx>
|
|
#include <doc.hxx>
|
|
#include <docary.hxx>
|
|
#include <editeng/tstpitem.hxx>
|
|
#include <hintids.hxx>
|
|
#include <hints.hxx>
|
|
#include <ndtxt.hxx>
|
|
#include <paratr.hxx>
|
|
#include <rootfrm.hxx>
|
|
#include <scriptinfo.hxx>
|
|
#include <strings.hrc>
|
|
#include <swtypes.hxx>
|
|
#include <tox.hxx>
|
|
#include <txtfrm.hxx>
|
|
#include <txttxmrk.hxx>
|
|
#include <unoidx.hxx>
|
|
|
|
#include <optional>
|
|
#include <sal/log.hxx>
|
|
#include <o3tl/string_view.hxx>
|
|
#include <osl/diagnose.h>
|
|
|
|
#include <algorithm>
|
|
#include <string_view>
|
|
#include <utility>
|
|
|
|
|
|
const sal_Unicode C_NUM_REPL = '@';
|
|
const sal_Unicode C_END_PAGE_NUM = '~';
|
|
|
|
namespace
|
|
{
|
|
void lcl_FillAuthPattern(SwFormTokens &rAuthTokens, sal_uInt16 nTypeId)
|
|
{
|
|
rAuthTokens.reserve(9); // Worst case: Start+Sep1+Auth+3*(Sep2+Auth)
|
|
|
|
SwFormToken aStartToken( TOKEN_AUTHORITY );
|
|
aStartToken.nAuthorityField = AUTH_FIELD_IDENTIFIER;
|
|
rAuthTokens.push_back( aStartToken );
|
|
SwFormToken aSeparatorToken( TOKEN_TEXT );
|
|
aSeparatorToken.sText = ": ";
|
|
rAuthTokens.push_back( aSeparatorToken );
|
|
|
|
--nTypeId; // compensate +1 offset introduced by caller
|
|
|
|
SwFormToken aTextToken( TOKEN_TEXT );
|
|
aTextToken.sText = ", ";
|
|
|
|
const ToxAuthorityField nVals[4] = {
|
|
AUTH_FIELD_AUTHOR,
|
|
AUTH_FIELD_TITLE,
|
|
AUTH_FIELD_YEAR,
|
|
nTypeId == AUTH_TYPE_WWW ? AUTH_FIELD_URL : AUTH_FIELD_END
|
|
};
|
|
|
|
for(size_t i = 0; i < SAL_N_ELEMENTS(nVals); ++i)
|
|
{
|
|
if(nVals[i] == AUTH_FIELD_END)
|
|
break;
|
|
if( i > 0 )
|
|
rAuthTokens.push_back( aTextToken );
|
|
|
|
// -> #i21237#
|
|
SwFormToken aToken(TOKEN_AUTHORITY);
|
|
|
|
aToken.nAuthorityField = nVals[i];
|
|
rAuthTokens.push_back(aToken);
|
|
// <- #i21237#
|
|
}
|
|
}
|
|
}
|
|
|
|
/// pool default constructor
|
|
SwTOXMark::SwTOXMark()
|
|
: SfxPoolItem(RES_TXTATR_TOXMARK)
|
|
, m_pType(nullptr)
|
|
, m_pTextAttr(nullptr)
|
|
, m_nLevel(0)
|
|
, m_bAutoGenerated(false)
|
|
, m_bMainEntry(false)
|
|
{
|
|
setNonShareable();
|
|
}
|
|
|
|
SwTOXMark::SwTOXMark(const SwTOXType* pType)
|
|
: SfxPoolItem(RES_TXTATR_TOXMARK)
|
|
, m_pType(pType)
|
|
, m_pTextAttr(nullptr)
|
|
, m_nLevel(0)
|
|
, m_bAutoGenerated(false)
|
|
, m_bMainEntry(false)
|
|
{
|
|
setNonShareable();
|
|
StartListening(const_cast<SwTOXType*>(m_pType)->GetNotifier());
|
|
}
|
|
|
|
SwTOXMark::SwTOXMark(const SwTOXMark& rCopy)
|
|
: SfxPoolItem(RES_TXTATR_TOXMARK)
|
|
, SvtListener()
|
|
, m_pType(rCopy.m_pType)
|
|
, m_aPrimaryKey(rCopy.m_aPrimaryKey)
|
|
, m_aSecondaryKey(rCopy.m_aSecondaryKey)
|
|
, m_aTextReading(rCopy.m_aTextReading)
|
|
, m_aPrimaryKeyReading(rCopy.m_aPrimaryKeyReading)
|
|
, m_aSecondaryKeyReading(rCopy.m_aSecondaryKeyReading)
|
|
, m_pTextAttr(nullptr)
|
|
, m_nLevel(rCopy.m_nLevel)
|
|
, m_bAutoGenerated(rCopy.m_bAutoGenerated)
|
|
, m_bMainEntry(rCopy.m_bMainEntry)
|
|
{
|
|
setNonShareable();
|
|
if(m_pType)
|
|
StartListening(const_cast<SwTOXType*>(m_pType)->GetNotifier());
|
|
// Copy AlternativString
|
|
m_aAltText = rCopy.m_aAltText;
|
|
}
|
|
|
|
SwTOXMark::~SwTOXMark()
|
|
{
|
|
}
|
|
|
|
void SwTOXMark::SetXTOXMark(rtl::Reference<SwXDocumentIndexMark> const& xMark)
|
|
{ m_wXDocumentIndexMark = xMark.get(); }
|
|
|
|
void SwTOXMark::RegisterToTOXType(SwTOXType& rType)
|
|
{
|
|
SvtListener::EndListeningAll();
|
|
m_pType = &rType;
|
|
StartListening(rType.GetNotifier());
|
|
}
|
|
|
|
bool SwTOXMark::operator==( const SfxPoolItem& rAttr ) const
|
|
{
|
|
assert(SfxPoolItem::operator==(rAttr));
|
|
// tdf#158783 this item was never 'pooled', so operator== was not really
|
|
// ever used. We discussed to implement it (there is quite some
|
|
// content), but we came to the point that it's only safe to say
|
|
// instances are equal when same instance -> fallback to ptr compare.
|
|
// NOTE: Do *not* use areSfxPoolItemPtrsEqual here, with DBG_UTIL
|
|
// active the control/test code there would again call operator==
|
|
return this == &rAttr;
|
|
}
|
|
|
|
SwTOXMark* SwTOXMark::Clone( SfxItemPool* ) const
|
|
{
|
|
return new SwTOXMark( *this );
|
|
}
|
|
|
|
void SwTOXMark::Notify(const SfxHint& rHint)
|
|
{
|
|
if(SfxHintId::SwRemoveUnoObject == rHint.GetId())
|
|
{
|
|
CallSwClientNotify(rHint);
|
|
SetXTOXMark(nullptr);
|
|
}
|
|
else if (rHint.GetId() == SfxHintId::SwLegacyModify)
|
|
{
|
|
CallSwClientNotify(rHint);
|
|
}
|
|
else if (rHint.GetId() == SfxHintId::SwCollectTextMarks)
|
|
{
|
|
auto pCollectHint = static_cast<const sw::CollectTextMarksHint*>(&rHint);
|
|
if(GetTextTOXMark())
|
|
pCollectHint->m_rMarks.push_back(this);
|
|
}
|
|
else if (rHint.GetId() == SfxHintId::SwCollectTextTOXMarksForLayout)
|
|
{
|
|
auto pCollectLayoutHint = static_cast<const sw::CollectTextTOXMarksForLayoutHint*>(&rHint);
|
|
if(!GetTextTOXMark())
|
|
return;
|
|
auto& rTextMark = *GetTextTOXMark();
|
|
auto& rNode = rTextMark.GetTextNode();
|
|
auto pLayout = pCollectLayoutHint->m_pLayout;
|
|
// Check basic sanity and that it is part of our layout and not in undo
|
|
if(!rNode.GetNodes().IsDocNodes() || !rNode.GetText().getLength() || !rNode.HasWriterListeners() || !rNode.getLayoutFrame(pLayout))
|
|
return;
|
|
// Check for being hidden
|
|
if(rNode.IsHiddenByParaField() || SwScriptInfo::IsInHiddenRange(rNode, rTextMark.GetStart()))
|
|
return;
|
|
// Check for being hidden by hidden redlines
|
|
if (pLayout && pLayout->HasMergedParas() && sw::IsMarkHintHidden(*pLayout, rNode, rTextMark))
|
|
return;
|
|
// Check for being hidden by hidden sections
|
|
if (auto pFrame(rNode.getLayoutFrame(pLayout)); !pFrame || pFrame->IsHiddenNow())
|
|
return;
|
|
pCollectLayoutHint->m_rMarks.push_back(rTextMark);
|
|
}
|
|
}
|
|
|
|
void SwTOXMark::InvalidateTOXMark()
|
|
{
|
|
CallSwClientNotify(sw::RemoveUnoObjectHint(this));
|
|
}
|
|
|
|
OUString SwTOXMark::GetText(SwRootFrame const*const pLayout) const
|
|
{
|
|
if( !m_aAltText.isEmpty() )
|
|
return m_aAltText;
|
|
|
|
if( m_pTextAttr && m_pTextAttr->GetpTextNd() )
|
|
{
|
|
const sal_Int32* pEndIdx = m_pTextAttr->GetEnd();
|
|
OSL_ENSURE( pEndIdx, "TOXMark without mark!");
|
|
if( pEndIdx )
|
|
{
|
|
const sal_Int32 nStt = m_pTextAttr->GetStart();
|
|
return m_pTextAttr->GetpTextNd()->GetExpandText(pLayout, nStt, *pEndIdx-nStt);
|
|
}
|
|
}
|
|
|
|
return OUString();
|
|
}
|
|
|
|
// Manage types of TOX
|
|
SwTOXType::SwTOXType(SwDoc& rDoc, TOXTypes eTyp, OUString aName)
|
|
: m_rDoc(rDoc)
|
|
, m_aName(std::move(aName))
|
|
, m_eType(eTyp)
|
|
{
|
|
}
|
|
|
|
SwTOXType::SwTOXType(const SwTOXType& rCopy)
|
|
: m_rDoc(rCopy.m_rDoc)
|
|
, m_aName(rCopy.m_aName)
|
|
, m_eType(rCopy.m_eType)
|
|
{
|
|
if (auto pRegisteredIn = const_cast<SwTOXType&>(rCopy).GetRegisteredIn())
|
|
pRegisteredIn->Add(*this);
|
|
}
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_ARY[] =
|
|
{
|
|
// Subcategory Index-Directories
|
|
STR_POOLCOLL_TOX_IDXH,
|
|
STR_POOLCOLL_TOX_IDX1,
|
|
STR_POOLCOLL_TOX_IDX2,
|
|
STR_POOLCOLL_TOX_IDX3,
|
|
STR_POOLCOLL_TOX_IDXBREAK
|
|
};
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_CNTNT_ARY[] =
|
|
{
|
|
// Subcategory Tables of Contents
|
|
STR_POOLCOLL_TOX_CNTNTH,
|
|
STR_POOLCOLL_TOX_CNTNT1,
|
|
STR_POOLCOLL_TOX_CNTNT2,
|
|
STR_POOLCOLL_TOX_CNTNT3,
|
|
STR_POOLCOLL_TOX_CNTNT4,
|
|
STR_POOLCOLL_TOX_CNTNT5
|
|
};
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_CNTNT_EXTRA_ARY[] =
|
|
{
|
|
// Subcategory Table of Contents more Levels 5 - 10
|
|
STR_POOLCOLL_TOX_CNTNT6,
|
|
STR_POOLCOLL_TOX_CNTNT7,
|
|
STR_POOLCOLL_TOX_CNTNT8,
|
|
STR_POOLCOLL_TOX_CNTNT9,
|
|
STR_POOLCOLL_TOX_CNTNT10
|
|
};
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_USER_ARY[] =
|
|
{
|
|
// Subcategory User-Directories:
|
|
STR_POOLCOLL_TOX_USERH,
|
|
STR_POOLCOLL_TOX_USER1,
|
|
STR_POOLCOLL_TOX_USER2,
|
|
STR_POOLCOLL_TOX_USER3,
|
|
STR_POOLCOLL_TOX_USER4,
|
|
STR_POOLCOLL_TOX_USER5
|
|
};
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_USER_EXTRA_ARY[] =
|
|
{
|
|
// Subcategory User-Directories more Levels 5 - 10
|
|
STR_POOLCOLL_TOX_USER6,
|
|
STR_POOLCOLL_TOX_USER7,
|
|
STR_POOLCOLL_TOX_USER8,
|
|
STR_POOLCOLL_TOX_USER9,
|
|
STR_POOLCOLL_TOX_USER10
|
|
};
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_ILLUS_ARY[] =
|
|
{
|
|
// Illustrations Index
|
|
STR_POOLCOLL_TOX_ILLUSH,
|
|
STR_POOLCOLL_TOX_ILLUS1
|
|
};
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_OBJECT_ARY[] =
|
|
{
|
|
// Object Index
|
|
STR_POOLCOLL_TOX_OBJECTH,
|
|
STR_POOLCOLL_TOX_OBJECT1
|
|
};
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_TABLES_ARY[] =
|
|
{
|
|
// Tables Index
|
|
STR_POOLCOLL_TOX_TABLESH,
|
|
STR_POOLCOLL_TOX_TABLES1
|
|
};
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_AUTHORITIES_ARY[] =
|
|
{
|
|
// Index of Authorities
|
|
STR_POOLCOLL_TOX_AUTHORITIESH,
|
|
STR_POOLCOLL_TOX_AUTHORITIES1
|
|
};
|
|
|
|
const TranslateId STR_POOLCOLL_TOX_CITATION_ARY[] =
|
|
{
|
|
STR_POOLCOLL_TOX_CITATION
|
|
};
|
|
|
|
// Edit forms
|
|
SwForm::SwForm( TOXTypes eTyp ) // #i21237#
|
|
: m_eType( eTyp ), m_nFormMaxLevel( SwForm::GetFormMaxLevel( eTyp )),
|
|
// nFirstTabPos( lNumberIndent ),
|
|
m_bCommaSeparated(false)
|
|
{
|
|
//bHasFirstTabPos =
|
|
m_bIsRelTabPos = true;
|
|
|
|
// The table of contents has a certain number of headlines + headings
|
|
// The user has 10 levels + headings
|
|
// Keyword has 3 levels + headings+ separator
|
|
// Indexes of tables, object illustrations and authorities consist of a heading and one level
|
|
|
|
const TranslateId* pPoolId;
|
|
switch( m_eType )
|
|
{
|
|
case TOX_INDEX: pPoolId = STR_POOLCOLL_TOX_ARY; break;
|
|
case TOX_USER: pPoolId = STR_POOLCOLL_TOX_USER_ARY; break;
|
|
case TOX_CONTENT: pPoolId = STR_POOLCOLL_TOX_CNTNT_ARY; break;
|
|
case TOX_ILLUSTRATIONS: pPoolId = STR_POOLCOLL_TOX_ILLUS_ARY; break;
|
|
case TOX_OBJECTS : pPoolId = STR_POOLCOLL_TOX_OBJECT_ARY; break;
|
|
case TOX_TABLES : pPoolId = STR_POOLCOLL_TOX_TABLES_ARY; break;
|
|
case TOX_AUTHORITIES : pPoolId = STR_POOLCOLL_TOX_AUTHORITIES_ARY; break;
|
|
case TOX_CITATION : pPoolId = STR_POOLCOLL_TOX_CITATION_ARY; break;
|
|
default:
|
|
OSL_ENSURE( false, "invalid TOXTyp");
|
|
return ;
|
|
}
|
|
|
|
SwFormTokens aTokens;
|
|
const bool bNeedsLink
|
|
= TOX_CONTENT == m_eType || TOX_ILLUSTRATIONS == m_eType || TOX_TABLES == m_eType;
|
|
if (bNeedsLink)
|
|
{
|
|
SwFormToken aLinkStt (TOKEN_LINK_START);
|
|
aLinkStt.sCharStyleName = SwResId(STR_POOLCHR_TOXJUMP);
|
|
aTokens.push_back(aLinkStt);
|
|
}
|
|
|
|
if (TOX_CONTENT == m_eType)
|
|
{
|
|
aTokens.emplace_back(TOKEN_ENTRY_NO);
|
|
aTokens.emplace_back(TOKEN_ENTRY_TEXT);
|
|
}
|
|
else
|
|
aTokens.emplace_back(TOKEN_ENTRY);
|
|
|
|
if (TOX_AUTHORITIES != m_eType)
|
|
{
|
|
SwFormToken aToken(TOKEN_TAB_STOP);
|
|
aToken.nTabStopPosition = 0;
|
|
|
|
// #i36870# right aligned tab for all
|
|
aToken.cTabFillChar = '.';
|
|
aToken.eTabAlign = SvxTabAdjust::End;
|
|
|
|
aTokens.push_back(aToken);
|
|
aTokens.emplace_back(TOKEN_PAGE_NUMS);
|
|
}
|
|
|
|
if (bNeedsLink)
|
|
aTokens.emplace_back(TOKEN_LINK_END);
|
|
|
|
SetTemplate(0, SwResId(*pPoolId++));
|
|
|
|
if(TOX_INDEX == m_eType)
|
|
{
|
|
for( sal_uInt16 i = 1; i < 5; ++i )
|
|
{
|
|
if(1 == i)
|
|
{
|
|
SwFormTokens aTmpTokens;
|
|
SwFormToken aTmpToken(TOKEN_ENTRY);
|
|
aTmpTokens.push_back(aTmpToken);
|
|
|
|
SetPattern( i, std::move(aTmpTokens) );
|
|
SetTemplate(i, SwResId(STR_POOLCOLL_TOX_IDXBREAK));
|
|
}
|
|
else
|
|
{
|
|
SetPattern( i, std::vector(aTokens) );
|
|
SetTemplate(i, SwResId(STR_POOLCOLL_TOX_ARY[i - 1]));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (sal_uInt16 i = 1; i < GetFormMax(); ++i, ++pPoolId) // Number 0 is the title
|
|
{
|
|
if (TOX_AUTHORITIES == m_eType)
|
|
{
|
|
SwFormTokens aAuthTokens;
|
|
lcl_FillAuthPattern(aAuthTokens, i);
|
|
SetPattern(i, std::move(aAuthTokens));
|
|
}
|
|
else
|
|
SetPattern( i, std::vector(aTokens) );
|
|
|
|
if( TOX_CONTENT == m_eType && 6 == i )
|
|
pPoolId = STR_POOLCOLL_TOX_CNTNT_EXTRA_ARY;
|
|
else if( TOX_USER == m_eType && 6 == i )
|
|
pPoolId = STR_POOLCOLL_TOX_USER_EXTRA_ARY;
|
|
else if( TOX_AUTHORITIES == m_eType ) //reuse the same STR_POOLCOLL_TOX_AUTHORITIES1 id each time
|
|
pPoolId = STR_POOLCOLL_TOX_AUTHORITIES_ARY + 1;
|
|
SetTemplate(i, SwResId(*pPoolId));
|
|
}
|
|
}
|
|
}
|
|
|
|
SwForm::SwForm(const SwForm& rForm)
|
|
: m_eType( rForm.m_eType )
|
|
{
|
|
*this = rForm;
|
|
}
|
|
|
|
SwForm& SwForm::operator=(const SwForm& rForm)
|
|
{
|
|
m_eType = rForm.m_eType;
|
|
m_nFormMaxLevel = rForm.m_nFormMaxLevel;
|
|
// nFirstTabPos = rForm.nFirstTabPos;
|
|
// bHasFirstTabPos = rForm.bHasFirstTabPos;
|
|
m_bIsRelTabPos = rForm.m_bIsRelTabPos;
|
|
m_bCommaSeparated = rForm.m_bCommaSeparated;
|
|
for(sal_uInt16 i=0; i < m_nFormMaxLevel; ++i)
|
|
{
|
|
m_aPattern[i] = rForm.m_aPattern[i];
|
|
m_aTemplate[i] = rForm.m_aTemplate[i];
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
sal_uInt16 SwForm::GetFormMaxLevel( TOXTypes eTOXType )
|
|
{
|
|
switch( eTOXType )
|
|
{
|
|
case TOX_INDEX:
|
|
return 5;
|
|
case TOX_USER:
|
|
case TOX_CONTENT:
|
|
return MAXLEVEL + 1;
|
|
case TOX_ILLUSTRATIONS:
|
|
case TOX_OBJECTS:
|
|
case TOX_TABLES:
|
|
return 2;
|
|
case TOX_BIBLIOGRAPHY:
|
|
case TOX_CITATION:
|
|
case TOX_AUTHORITIES:
|
|
return AUTH_TYPE_END + 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void SwForm::AdjustTabStops( SwDoc const & rDoc ) // #i21237#
|
|
{
|
|
const sal_uInt16 nFormMax = GetFormMax();
|
|
for ( sal_uInt16 nLevel = 1; nLevel < nFormMax; ++nLevel )
|
|
{
|
|
SwTextFormatColl* pColl = rDoc.FindTextFormatCollByName( GetTemplate(nLevel) );
|
|
if( pColl == nullptr )
|
|
{
|
|
// Paragraph Style for this level has not been created.
|
|
// --> No need to propagate default values
|
|
continue;
|
|
}
|
|
|
|
const SvxTabStopItem& rTabStops = pColl->GetTabStops(false);
|
|
const sal_uInt16 nTabCount = rTabStops.Count();
|
|
if (nTabCount != 0)
|
|
{
|
|
SwFormTokens aCurrentPattern = GetPattern(nLevel);
|
|
SwFormTokens::iterator aIt = aCurrentPattern.begin();
|
|
|
|
bool bChanged = false;
|
|
for(sal_uInt16 nTab = 0; nTab < nTabCount; ++nTab)
|
|
{
|
|
const SvxTabStop& rTab = rTabStops[nTab];
|
|
|
|
if ( rTab.GetAdjustment() == SvxTabAdjust::Default )
|
|
continue; // ignore the default tab stop
|
|
|
|
aIt = find_if( aIt, aCurrentPattern.end(), SwFormTokenEqualToFormTokenType(TOKEN_TAB_STOP) );
|
|
if ( aIt != aCurrentPattern.end() )
|
|
{
|
|
bChanged = true;
|
|
aIt->nTabStopPosition = rTab.GetTabPos();
|
|
aIt->eTabAlign =
|
|
( nTab == nTabCount - 1
|
|
&& rTab.GetAdjustment() == SvxTabAdjust::Right )
|
|
? SvxTabAdjust::End
|
|
: rTab.GetAdjustment();
|
|
aIt->cTabFillChar = rTab.GetFill();
|
|
++aIt;
|
|
}
|
|
else
|
|
break; // no more tokens to replace
|
|
}
|
|
|
|
if ( bChanged )
|
|
SetPattern( nLevel, std::move(aCurrentPattern) );
|
|
}
|
|
}
|
|
}
|
|
|
|
OUString SwForm::GetFormEntry() {return u"<E>"_ustr;}
|
|
OUString SwForm::GetFormTab() {return u"<T>"_ustr;}
|
|
OUString SwForm::GetFormPageNums() {return u"<#>"_ustr;}
|
|
OUString SwForm::GetFormLinkStt() {return u"<LS>"_ustr;}
|
|
OUString SwForm::GetFormLinkEnd() {return u"<LE>"_ustr;}
|
|
OUString SwForm::GetFormEntryNum() {return u"<E#>"_ustr;}
|
|
OUString SwForm::GetFormEntryText() {return u"<ET>"_ustr;}
|
|
OUString SwForm::GetFormChapterMark() {return u"<C>"_ustr;}
|
|
OUString SwForm::GetFormText() {return u"<X>"_ustr;}
|
|
OUString SwForm::GetFormAuth() {return u"<A>"_ustr;}
|
|
|
|
SwTOXBase::SwTOXBase(const SwTOXType* pTyp, const SwForm& rForm,
|
|
SwTOXElement nCreaType, OUString aTitle )
|
|
: SwClient(const_cast<sw::BroadcastingModify*>(static_cast<sw::BroadcastingModify const *>(pTyp)))
|
|
, m_aForm(rForm)
|
|
, m_aTitle(std::move(aTitle))
|
|
, m_eLanguage(::GetAppLanguage())
|
|
, m_nCreateType(nCreaType)
|
|
, m_nOLEOptions(SwTOOElements::NONE)
|
|
, m_eCaptionDisplay(CAPTION_COMPLETE)
|
|
, m_bProtected( true )
|
|
, m_bFromChapter(false)
|
|
, m_bFromObjectNames(false)
|
|
, m_bLevelFromChapter(false)
|
|
, maMSTOCExpression()
|
|
, mbKeepExpression(true)
|
|
{
|
|
m_aData.nOptions = SwTOIOptions::NONE;
|
|
}
|
|
|
|
SwTOXBase::SwTOXBase( const SwTOXBase& rSource, SwDoc* pDoc )
|
|
: SwClient( rSource.GetRegisteredInNonConst() )
|
|
, mbKeepExpression(true)
|
|
{
|
|
CopyTOXBase( pDoc, rSource );
|
|
}
|
|
|
|
void SwTOXBase::RegisterToTOXType( SwTOXType& rType )
|
|
{
|
|
rType.Add(*this);
|
|
}
|
|
|
|
void SwTOXBase::CopyTOXBase( SwDoc* pDoc, const SwTOXBase& rSource )
|
|
{
|
|
maMSTOCExpression = rSource.maMSTOCExpression;
|
|
SwTOXType* pType = const_cast<SwTOXType*>(rSource.GetTOXType());
|
|
if( pDoc &&
|
|
std::find_if(pDoc->GetTOXTypes().begin(), pDoc->GetTOXTypes().end(),
|
|
[=](const std::unique_ptr<SwTOXType> & p) { return p.get() == pType; })
|
|
== pDoc->GetTOXTypes().end())
|
|
{
|
|
// type not in pDoc, so create it now
|
|
const SwTOXTypes& rTypes = pDoc->GetTOXTypes();
|
|
bool bFound = false;
|
|
for( size_t n = rTypes.size(); n; )
|
|
{
|
|
const SwTOXType* pCmp = rTypes[ --n ].get();
|
|
if( pCmp->GetType() == pType->GetType() &&
|
|
pCmp->GetTypeName() == pType->GetTypeName() )
|
|
{
|
|
pType = const_cast<SwTOXType*>(pCmp);
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( !bFound )
|
|
pType = const_cast<SwTOXType*>(pDoc->InsertTOXType( *pType ));
|
|
}
|
|
pType->Add(*this);
|
|
|
|
m_nCreateType = rSource.m_nCreateType;
|
|
m_aTitle = rSource.m_aTitle;
|
|
m_aForm = rSource.m_aForm;
|
|
m_aBookmarkName = rSource.m_aBookmarkName;
|
|
m_bProtected = rSource.m_bProtected;
|
|
m_bFromChapter = rSource.m_bFromChapter;
|
|
m_bFromObjectNames = rSource.m_bFromObjectNames;
|
|
m_sMainEntryCharStyle = rSource.m_sMainEntryCharStyle;
|
|
m_sSequenceName = rSource.m_sSequenceName;
|
|
m_eCaptionDisplay = rSource.m_eCaptionDisplay;
|
|
m_nOLEOptions = rSource.m_nOLEOptions;
|
|
m_eLanguage = rSource.m_eLanguage;
|
|
m_sSortAlgorithm = rSource.m_sSortAlgorithm;
|
|
m_bLevelFromChapter = rSource.m_bLevelFromChapter;
|
|
|
|
for( sal_uInt16 i = 0; i < MAXLEVEL; ++i )
|
|
m_aStyleNames[i] = rSource.m_aStyleNames[i];
|
|
|
|
// it's the same data type!
|
|
m_aData.nOptions = rSource.m_aData.nOptions;
|
|
|
|
if( !pDoc || pDoc->IsCopyIsMove() )
|
|
m_aName = rSource.GetTOXName();
|
|
else
|
|
m_aName = pDoc->GetUniqueTOXBaseName( *pType, rSource.GetTOXName() );
|
|
}
|
|
|
|
// TOX specific functions
|
|
SwTOXBase::~SwTOXBase()
|
|
{
|
|
// if( GetTOXType()->GetType() == TOX_USER )
|
|
// delete aData.pTemplateName;
|
|
}
|
|
|
|
void SwTOXBase::SetTitle(const OUString& rTitle)
|
|
{ m_aTitle = rTitle; }
|
|
|
|
void SwTOXBase::SetBookmarkName(const OUString& bName)
|
|
{
|
|
m_aBookmarkName = bName;
|
|
}
|
|
|
|
SwTOXBase & SwTOXBase::operator = (const SwTOXBase & rSource)
|
|
{
|
|
m_aForm = rSource.m_aForm;
|
|
m_aName = rSource.m_aName;
|
|
m_aTitle = rSource.m_aTitle;
|
|
m_aBookmarkName = rSource.m_aBookmarkName;
|
|
m_sMainEntryCharStyle = rSource.m_sMainEntryCharStyle;
|
|
for(sal_uInt16 nLevel = 0; nLevel < MAXLEVEL; nLevel++)
|
|
m_aStyleNames[nLevel] = rSource.m_aStyleNames[nLevel];
|
|
m_sSequenceName = rSource.m_sSequenceName;
|
|
m_eLanguage = rSource.m_eLanguage;
|
|
m_sSortAlgorithm = rSource.m_sSortAlgorithm;
|
|
m_aData = rSource.m_aData;
|
|
m_nCreateType = rSource.m_nCreateType;
|
|
m_nOLEOptions = rSource.m_nOLEOptions;
|
|
m_eCaptionDisplay = rSource.m_eCaptionDisplay;
|
|
m_bProtected = rSource.m_bProtected;
|
|
m_bFromChapter = rSource.m_bFromChapter;
|
|
m_bFromObjectNames = rSource.m_bFromObjectNames;
|
|
m_bLevelFromChapter = rSource.m_bLevelFromChapter;
|
|
|
|
if (rSource.GetAttrSet())
|
|
SetAttrSet(*rSource.GetAttrSet());
|
|
|
|
return *this;
|
|
}
|
|
|
|
OUString SwFormToken::GetString() const
|
|
{
|
|
OUString sToken;
|
|
|
|
switch( eTokenType )
|
|
{
|
|
case TOKEN_ENTRY_NO:
|
|
sToken = SwForm::GetFormEntryNum();
|
|
break;
|
|
case TOKEN_ENTRY_TEXT:
|
|
sToken = SwForm::GetFormEntryText();
|
|
break;
|
|
case TOKEN_ENTRY:
|
|
sToken = SwForm::GetFormEntry();
|
|
break;
|
|
case TOKEN_TAB_STOP:
|
|
sToken = SwForm::GetFormTab();
|
|
break;
|
|
case TOKEN_TEXT:
|
|
// Return a Token only if Text is not empty!
|
|
if( sText.isEmpty() )
|
|
{
|
|
return OUString();
|
|
}
|
|
sToken = SwForm::GetFormText();
|
|
break;
|
|
case TOKEN_PAGE_NUMS:
|
|
sToken = SwForm::GetFormPageNums();
|
|
break;
|
|
case TOKEN_CHAPTER_INFO:
|
|
sToken = SwForm::GetFormChapterMark();
|
|
break;
|
|
case TOKEN_LINK_START:
|
|
sToken = SwForm::GetFormLinkStt();
|
|
break;
|
|
case TOKEN_LINK_END:
|
|
sToken = SwForm::GetFormLinkEnd();
|
|
break;
|
|
case TOKEN_AUTHORITY:
|
|
{
|
|
sToken = SwForm::GetFormAuth();
|
|
}
|
|
break;
|
|
case TOKEN_END:
|
|
break;
|
|
}
|
|
|
|
OUString sData = " " + sCharStyleName + "," + OUString::number( nPoolId ) + ",";
|
|
|
|
// TabStopPosition and TabAlign or ChapterInfoFormat
|
|
switch (eTokenType)
|
|
{
|
|
case TOKEN_TAB_STOP:
|
|
sData += OUString::number( nTabStopPosition ) + ","
|
|
+ OUString::number( static_cast< sal_Int32 >(eTabAlign) ) + ","
|
|
+ OUStringChar(cTabFillChar) + ","
|
|
+ OUString::number( bWithTab ? 1 : 0 );
|
|
break;
|
|
case TOKEN_CHAPTER_INFO:
|
|
case TOKEN_ENTRY_NO:
|
|
// add also maximum permitted level
|
|
sData += OUString::number( nChapterFormat ) + ","
|
|
+ OUString::number( nOutlineLevel );
|
|
break;
|
|
case TOKEN_TEXT:
|
|
sData += OUStringChar(TOX_STYLE_DELIMITER)
|
|
+ sText.replaceAll(OUStringChar(TOX_STYLE_DELIMITER), "")
|
|
+ OUStringChar(TOX_STYLE_DELIMITER);
|
|
break;
|
|
case TOKEN_AUTHORITY:
|
|
if (nAuthorityField<10)
|
|
{
|
|
sData = "0" + OUString::number( nAuthorityField ) + sData;
|
|
}
|
|
else
|
|
{
|
|
sData = OUString::number( nAuthorityField ) + sData;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return sToken.subView(0, sToken.getLength()-1) + sData + sToken.subView(sToken.getLength()-1);
|
|
}
|
|
|
|
// -> #i21237#
|
|
|
|
/**
|
|
Returns the type of a token.
|
|
|
|
@param sToken the string representation of the token
|
|
@param rTokenLen return parameter the length of the head of the token
|
|
|
|
@return the type of the token
|
|
*/
|
|
static FormTokenType lcl_GetTokenType(std::u16string_view sToken,
|
|
sal_Int32 & rTokenLen)
|
|
{
|
|
static struct
|
|
{
|
|
OUString sTokenStart;
|
|
sal_Int16 nTokenLength;
|
|
FormTokenType eTokenType;
|
|
} const aTokenArr[] = {
|
|
{ SwForm::GetFormTab().copy(0, 2), 3, TOKEN_TAB_STOP },
|
|
{ SwForm::GetFormPageNums().copy(0, 2), 3, TOKEN_PAGE_NUMS },
|
|
{ SwForm::GetFormLinkStt().copy(0, 3), 4, TOKEN_LINK_START },
|
|
{ SwForm::GetFormLinkEnd().copy(0, 3), 4, TOKEN_LINK_END },
|
|
{ SwForm::GetFormEntryNum().copy(0, 3), 4, TOKEN_ENTRY_NO },
|
|
{ SwForm::GetFormEntryText().copy(0, 3), 4, TOKEN_ENTRY_TEXT },
|
|
{ SwForm::GetFormChapterMark().copy(0, 2), 3, TOKEN_CHAPTER_INFO },
|
|
{ SwForm::GetFormText().copy(0, 2), 3, TOKEN_TEXT },
|
|
{ SwForm::GetFormEntry().copy(0, 2), 3, TOKEN_ENTRY },
|
|
{ SwForm::GetFormAuth().copy(0, 2), 5, TOKEN_AUTHORITY }
|
|
};
|
|
|
|
for(const auto & i : aTokenArr)
|
|
{
|
|
if( o3tl::starts_with( sToken, i.sTokenStart ) )
|
|
{
|
|
rTokenLen = i.nTokenLength;
|
|
return i.eTokenType;
|
|
}
|
|
}
|
|
|
|
SAL_WARN("sw.core", "SwFormTokensHelper: invalid token");
|
|
return TOKEN_END;
|
|
}
|
|
|
|
/**
|
|
Returns the string of a token.
|
|
|
|
@param sPattern the whole pattern
|
|
@param nStt starting position of the token
|
|
|
|
@return the string representation of the token
|
|
*/
|
|
static std::u16string_view
|
|
lcl_SearchNextToken(std::u16string_view sPattern, sal_Int32 const nStt)
|
|
{
|
|
size_t nEnd = sPattern.find( u'>', nStt );
|
|
if (nEnd != std::u16string_view::npos)
|
|
{
|
|
// apparently the TOX_STYLE_DELIMITER act as a bracketing for
|
|
// TOKEN_TEXT tokens so that the user can have '>' inside the text...
|
|
const size_t nTextSeparatorFirst = sPattern.find( TOX_STYLE_DELIMITER, nStt );
|
|
if ( nTextSeparatorFirst != std::u16string_view::npos
|
|
&& nTextSeparatorFirst + 1 < sPattern.size()
|
|
&& nTextSeparatorFirst < nEnd)
|
|
{
|
|
const size_t nTextSeparatorSecond = sPattern.find( TOX_STYLE_DELIMITER,
|
|
nTextSeparatorFirst + 1 );
|
|
// Since nEnd>=0 we don't need to check if nTextSeparatorSecond==std::u16string_view::npos!
|
|
if( nEnd < nTextSeparatorSecond )
|
|
nEnd = sPattern.find( '>', nTextSeparatorSecond );
|
|
// FIXME: No check to verify that nEnd is still >=0?
|
|
assert(nEnd != std::u16string_view::npos);
|
|
}
|
|
|
|
++nEnd;
|
|
|
|
return sPattern.substr( nStt, nEnd - nStt );
|
|
}
|
|
|
|
return std::u16string_view();
|
|
}
|
|
|
|
/**
|
|
Builds a token from its string representation.
|
|
|
|
@sPattern the whole pattern
|
|
@nCurPatternPos starting position of the token
|
|
|
|
@return the token
|
|
*/
|
|
static std::optional<SwFormToken>
|
|
lcl_BuildToken(std::u16string_view sPattern, size_t & nCurPatternPos)
|
|
{
|
|
std::u16string_view sToken( lcl_SearchNextToken(sPattern, nCurPatternPos) );
|
|
nCurPatternPos += sToken.size();
|
|
sal_Int32 nTokenLen = 0;
|
|
FormTokenType const eTokenType = lcl_GetTokenType(sToken, nTokenLen);
|
|
if (TOKEN_END == eTokenType) // invalid input? skip it
|
|
{
|
|
nCurPatternPos = sPattern.size();
|
|
return std::optional<SwFormToken>();
|
|
}
|
|
|
|
// at this point sPattern contains the
|
|
// character style name, the PoolId, tab stop position, tab stop alignment, chapter info format
|
|
// the form is: CharStyleName, PoolId[, TabStopPosition|ChapterInfoFormat[, TabStopAlignment[, TabFillChar]]]
|
|
// in text tokens the form differs from the others: CharStyleName, PoolId[,\0xffinserted text\0xff]
|
|
SwFormToken eRet( eTokenType );
|
|
const std::u16string_view sAuthFieldEnum = sToken.substr( 2, 2 );
|
|
sToken = sToken.substr( nTokenLen, sToken.size() - nTokenLen - 1);
|
|
|
|
sal_Int32 nIdx{ 0 };
|
|
eRet.sCharStyleName = o3tl::getToken(sToken, 0, ',', nIdx );
|
|
std::u16string_view sTmp( o3tl::getToken(sToken, 0, ',', nIdx ));
|
|
if( !sTmp.empty() )
|
|
eRet.nPoolId = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(sTmp));
|
|
|
|
switch( eTokenType )
|
|
{
|
|
//i53420
|
|
case TOKEN_CHAPTER_INFO:
|
|
//i53420
|
|
case TOKEN_ENTRY_NO:
|
|
sTmp = o3tl::getToken(sToken, 0, ',', nIdx ); // token 2
|
|
if( !sTmp.empty() )
|
|
eRet.nChapterFormat = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(sTmp));
|
|
sTmp = o3tl::getToken(sToken, 0, ',', nIdx ); // token 3
|
|
if( !sTmp.empty() )
|
|
eRet.nOutlineLevel = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(sTmp)); //the maximum outline level to examine
|
|
break;
|
|
|
|
case TOKEN_TEXT:
|
|
{
|
|
const size_t nStartText = sToken.find( TOX_STYLE_DELIMITER );
|
|
if( nStartText != std::u16string_view::npos && nStartText+1<sToken.size())
|
|
{
|
|
const size_t nEndText = sToken.find( TOX_STYLE_DELIMITER,
|
|
nStartText + 1);
|
|
if( nEndText != std::u16string_view::npos )
|
|
{
|
|
eRet.sText = sToken.substr( nStartText + 1,
|
|
nEndText - nStartText - 1);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOKEN_TAB_STOP:
|
|
sTmp = o3tl::getToken(sToken, 0, ',', nIdx ); // token 2
|
|
if( !sTmp.empty() )
|
|
eRet.nTabStopPosition = o3tl::toInt32(sTmp);
|
|
|
|
sTmp = o3tl::getToken(sToken, 0, ',', nIdx ); // token 3
|
|
if( !sTmp.empty() )
|
|
eRet.eTabAlign = static_cast<SvxTabAdjust>(o3tl::toInt32(sTmp));
|
|
|
|
sTmp = o3tl::getToken(sToken, 0, ',', nIdx ); // token 4
|
|
if( !sTmp.empty() )
|
|
eRet.cTabFillChar = sTmp[0];
|
|
|
|
sTmp = o3tl::getToken(sToken, 0, ',', nIdx ); // token 5
|
|
if( !sTmp.empty() )
|
|
eRet.bWithTab = 0 != o3tl::toInt32(sTmp);
|
|
break;
|
|
|
|
case TOKEN_AUTHORITY:
|
|
eRet.nAuthorityField = o3tl::narrowing<sal_uInt16>(o3tl::toInt32(sAuthFieldEnum));
|
|
break;
|
|
default: break;
|
|
}
|
|
return eRet;
|
|
}
|
|
|
|
SwFormTokensHelper::SwFormTokensHelper(std::u16string_view aPattern)
|
|
{
|
|
size_t nCurPatternPos = 0;
|
|
|
|
while (nCurPatternPos < aPattern.size())
|
|
{
|
|
std::optional<SwFormToken> const oToken(
|
|
lcl_BuildToken(aPattern, nCurPatternPos));
|
|
if (oToken)
|
|
m_Tokens.push_back(*oToken);
|
|
}
|
|
}
|
|
|
|
// <- #i21237#
|
|
|
|
void SwForm::SetPattern(sal_uInt16 nLevel, SwFormTokens&& rTokens)
|
|
{
|
|
OSL_ENSURE(nLevel < GetFormMax(), "Index >= FORM_MAX");
|
|
m_aPattern[nLevel] = std::move(rTokens);
|
|
}
|
|
|
|
void SwForm::SetPattern(sal_uInt16 nLevel, std::u16string_view aStr)
|
|
{
|
|
OSL_ENSURE(nLevel < GetFormMax(), "Index >= FORM_MAX");
|
|
|
|
SwFormTokensHelper aHelper(aStr);
|
|
m_aPattern[nLevel] = aHelper.GetTokens();
|
|
}
|
|
|
|
const SwFormTokens& SwForm::GetPattern(sal_uInt16 nLevel) const
|
|
{
|
|
OSL_ENSURE(nLevel < GetFormMax(), "Index >= FORM_MAX");
|
|
return m_aPattern[nLevel];
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|