/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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(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(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(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(&rHint); CallSwClientNotify(rHint); if (pLegacyHint->m_pOld && (RES_REMOVE_UNO_OBJECT == pLegacyHint->m_pOld->Which())) SetXTOXMark(css::uno::Reference(nullptr)); } else if (auto pCollectHint = dynamic_cast(&rHint)) { if(GetTextTOXMark()) pCollectHint->m_rMarks.push_back(this); } else if (auto pCollectLayoutHint = dynamic_cast(&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(*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(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 "";} OUString SwForm::GetFormTab() {return "";} OUString SwForm::GetFormPageNums() {return "<#>";} OUString SwForm::GetFormLinkStt() {return "";} OUString SwForm::GetFormLinkEnd() {return "";} OUString SwForm::GetFormEntryNum() {return "";} OUString SwForm::GetFormEntryText() {return "";} OUString SwForm::GetFormChapterMark() {return "";} OUString SwForm::GetFormText() {return "";} OUString SwForm::GetFormAuth() {return "";} SwTOXBase::SwTOXBase(const SwTOXType* pTyp, const SwForm& rForm, SwTOXElement nCreaType, const OUString& rTitle ) : SwClient(const_cast(static_cast(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(rSource.GetTOXType()); if( pDoc && std::find_if(pDoc->GetTOXTypes().begin(), pDoc->GetTOXTypes().end(), [=](const std::unique_ptr & 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(pCmp); bFound = true; break; } } if( !bFound ) pType = const_cast(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 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(); } // 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(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(o3tl::toInt32(sTmp)); sTmp = o3tl::getToken(sToken, 0, ',', nIdx ); // token 3 if( !sTmp.empty() ) eRet.nOutlineLevel = o3tl::narrowing(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=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(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(sAuthFieldEnum.toInt32()); break; default: break; } return eRet; } SwFormTokensHelper::SwFormTokensHelper(const OUString & rPattern) { sal_Int32 nCurPatternPos = 0; while (nCurPatternPos < rPattern.getLength()) { std::optional 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: */