diff options
Diffstat (limited to 'sw/source/core/tox/tox.cxx')
-rw-r--r-- | sw/source/core/tox/tox.cxx | 949 |
1 files changed, 949 insertions, 0 deletions
diff --git a/sw/source/core/tox/tox.cxx b/sw/source/core/tox/tox.cxx new file mode 100644 index 000000000..53fc36d38 --- /dev/null +++ b/sw/source/core/tox/tox.cxx @@ -0,0 +1,949 @@ +/* -*- 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 <optional> +#include <sal/log.hxx> +#include <o3tl/string_view.hxx> +#include <osl/diagnose.h> + +#include <algorithm> +#include <string_view> + + +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) +{ +} + +SwTOXMark::SwTOXMark(const SwTOXType* pType) + : SfxPoolItem(RES_TXTATR_TOXMARK) + , m_pType(pType) + , m_pTextAttr(nullptr) + , m_nLevel(0) + , m_bAutoGenerated(false) + , m_bMainEntry(false) +{ + 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) +{ + if(m_pType) + StartListening(const_cast<SwTOXType*>(m_pType)->GetNotifier()); + // Copy AlternativString + m_aAltText = rCopy.m_aAltText; +} + +SwTOXMark::~SwTOXMark() +{ +} + +void SwTOXMark::RegisterToTOXType(SwTOXType& rType) +{ + SvtListener::EndListeningAll(); + m_pType = &rType; + StartListening(rType.GetNotifier()); +} + +bool SwTOXMark::operator==( const SfxPoolItem& rAttr ) const +{ + assert(SfxPoolItem::operator==(rAttr)); + return m_pType == static_cast<const SwTOXMark&>(rAttr).m_pType; +} + +SwTOXMark* SwTOXMark::Clone( SfxItemPool* ) const +{ + return new SwTOXMark( *this ); +} + +void SwTOXMark::Notify(const SfxHint& rHint) +{ + if (rHint.GetId() == SfxHintId::SwLegacyModify) + { + auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint); + CallSwClientNotify(rHint); + if (pLegacyHint->m_pOld && (RES_REMOVE_UNO_OBJECT == pLegacyHint->m_pOld->Which())) + SetXTOXMark(css::uno::Reference<css::text::XDocumentIndexMark>(nullptr)); + } else if (auto pCollectHint = dynamic_cast<const sw::CollectTextMarksHint*>(&rHint)) + { + if(GetTextTOXMark()) + pCollectHint->m_rMarks.push_back(this); + } else if (auto pCollectLayoutHint = dynamic_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; + pCollectLayoutHint->m_rMarks.push_back(rTextMark); + } +} + +void SwTOXMark::InvalidateTOXMark() +{ + const SwPtrMsgPoolItem aMsgHint(RES_REMOVE_UNO_OBJECT, &static_cast<sw::BroadcastingModify&>(*this)); + CallSwClientNotify(sw::LegacyModifyHint(&aMsgHint, &aMsgHint)); +} + +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, const OUString& rName) + : m_rDoc(rDoc) + , m_aName(rName) + , 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; + if (TOX_CONTENT == m_eType || TOX_ILLUSTRATIONS == m_eType ) + { + 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 (TOX_CONTENT == m_eType || TOX_ILLUSTRATIONS == m_eType) + 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 "<E>";} +OUString SwForm::GetFormTab() {return "<T>";} +OUString SwForm::GetFormPageNums() {return "<#>";} +OUString SwForm::GetFormLinkStt() {return "<LS>";} +OUString SwForm::GetFormLinkEnd() {return "<LE>";} +OUString SwForm::GetFormEntryNum() {return "<E#>";} +OUString SwForm::GetFormEntryText() {return "<ET>";} +OUString SwForm::GetFormChapterMark() {return "<C>";} +OUString SwForm::GetFormText() {return "<X>";} +OUString SwForm::GetFormAuth() {return "<A>";} + +SwTOXBase::SwTOXBase(const SwTOXType* pTyp, const SwForm& rForm, + SwTOXElement nCreaType, const OUString& rTitle ) + : SwClient(const_cast<sw::BroadcastingModify*>(static_cast<sw::BroadcastingModify const *>(pTyp))) + , m_aForm(rForm) + , m_aTitle(rTitle) + , 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 OUString +lcl_SearchNextToken(const OUString & sPattern, sal_Int32 const nStt) +{ + sal_Int32 nEnd = sPattern.indexOf( '>', nStt ); + if (nEnd >= 0) + { + // apparently the TOX_STYLE_DELIMITER act as a bracketing for + // TOKEN_TEXT tokens so that the user can have '>' inside the text... + const sal_Int32 nTextSeparatorFirst = sPattern.indexOf( TOX_STYLE_DELIMITER, nStt ); + if ( nTextSeparatorFirst >= 0 + && nTextSeparatorFirst + 1 < sPattern.getLength() + && nTextSeparatorFirst < nEnd) + { + const sal_Int32 nTextSeparatorSecond = sPattern.indexOf( TOX_STYLE_DELIMITER, + nTextSeparatorFirst + 1 ); + // Since nEnd>=0 we don't need to check if nTextSeparatorSecond<0! + if( nEnd < nTextSeparatorSecond ) + nEnd = sPattern.indexOf( '>', nTextSeparatorSecond ); + // FIXME: No check to verify that nEnd is still >=0? + assert(nEnd >= 0); + } + + ++nEnd; + + return sPattern.copy( nStt, nEnd - nStt ); + } + + return OUString(); +} + +/** + 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(const OUString & sPattern, sal_Int32 & nCurPatternPos) +{ + OUString sToken( lcl_SearchNextToken(sPattern, nCurPatternPos) ); + nCurPatternPos += sToken.getLength(); + sal_Int32 nTokenLen = 0; + FormTokenType const eTokenType = lcl_GetTokenType(sToken, nTokenLen); + if (TOKEN_END == eTokenType) // invalid input? skip it + { + nCurPatternPos = sPattern.getLength(); + 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 OUString sAuthFieldEnum = sToken.copy( 2, 2 ); + sToken = sToken.copy( nTokenLen, sToken.getLength() - nTokenLen - 1); + + sal_Int32 nIdx{ 0 }; + eRet.sCharStyleName = sToken.getToken( 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 sal_Int32 nStartText = sToken.indexOf( TOX_STYLE_DELIMITER ); + if( nStartText>=0 && nStartText+1<sToken.getLength()) + { + const sal_Int32 nEndText = sToken.indexOf( TOX_STYLE_DELIMITER, + nStartText + 1); + if( nEndText>=0 ) + { + eRet.sText = sToken.copy( 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>(sAuthFieldEnum.toInt32()); + break; + default: break; + } + return eRet; +} + +SwFormTokensHelper::SwFormTokensHelper(const OUString & rPattern) +{ + sal_Int32 nCurPatternPos = 0; + + while (nCurPatternPos < rPattern.getLength()) + { + std::optional<SwFormToken> const oToken( + lcl_BuildToken(rPattern, 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, const OUString & rStr) +{ + OSL_ENSURE(nLevel < GetFormMax(), "Index >= FORM_MAX"); + + SwFormTokensHelper aHelper(rStr); + 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: */ |