    /* -*- 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 <com/sun/star/util/SearchAlgorithms2.hpp>
    #include <com/sun/star/util/SearchFlags.hpp>
    #include <i18nutil/transliteration.hxx>
    #include <i18nutil/searchopt.hxx>
    #include <svl/fstathelper.hxx>
    #include <osl/thread.h>
    #include <unotools/textsearch.hxx>
    #include <unotools/syslocale.hxx>

    #include <sfx2/docfile.hxx>

    #include <xmloff/odffields.hxx>

    #include <editeng/unolingu.hxx>

    #include <swtypes.hxx>
    #include <editsh.hxx>
    #include <doc.hxx>
    #include <IDocumentUndoRedo.hxx>
    #include <pam.hxx>
    #include <viewopt.hxx>
    #include <ndtxt.hxx>
    #include <swundo.hxx>
    #include <txttxmrk.hxx>
    #include <edimp.hxx>
    #include <tox.hxx>
    #include <doctxm.hxx>
    #include <docary.hxx>
    #include <mdiexp.hxx>
    #include <strings.hrc>
    #include <bookmrk.hxx>

    using namespace ::com::sun::star;
    using namespace ::com::sun::star::i18n;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::util;

    // Add/delete listing markers to a document

    void SwEditShell::Insert(const SwTOXMark& rMark)
    {
        bool bInsAtPos = rMark.IsAlternativeText();
        StartAllAction();
        for(SwPaM& rPaM : GetCursor()->GetRingContainer())
        {
            const SwPosition *pStt = rPaM.Start(),
                             *pEnd = rPaM.End();
            if( bInsAtPos )
            {
                SwPaM aTmp( *pStt );
                GetDoc()->getIDocumentContentOperations().InsertPoolItem( aTmp, rMark );
            }
            else if( *pEnd != *pStt )
            {
                GetDoc()->getIDocumentContentOperations().InsertPoolItem(
                    rPaM, rMark, SetAttrMode::DONTEXPAND );
            }

        }
        EndAllAction();
    }

    void SwEditShell::DeleteTOXMark( SwTOXMark const * pMark )
    {
        SET_CURR_SHELL( this );
        StartAllAction();

        mxDoc->DeleteTOXMark( pMark );

        EndAllAction();
    }

    /// Collect all listing markers
    void SwEditShell::GetCurTOXMarks(SwTOXMarks& rMarks) const
    {
        SwDoc::GetCurTOXMark( *GetCursor()->Start(), rMarks );
    }

    bool SwEditShell::IsTOXBaseReadonly(const SwTOXBase& rTOXBase)
    {
        OSL_ENSURE( dynamic_cast<const SwTOXBaseSection*>( &rTOXBase) !=  nullptr, "no TOXBaseSection!" );
        const SwTOXBaseSection& rTOXSect = static_cast<const SwTOXBaseSection&>(rTOXBase);
        return  rTOXSect.IsProtect();
    }

    void SwEditShell::SetTOXBaseReadonly(const SwTOXBase& rTOXBase, bool bReadonly)
    {
        OSL_ENSURE( dynamic_cast<const SwTOXBaseSection*>( &rTOXBase) !=  nullptr, "no TOXBaseSection!" );
        const SwTOXBaseSection& rTOXSect = static_cast<const SwTOXBaseSection&>(rTOXBase);
        const_cast<SwTOXBase&>(rTOXBase).SetProtected(bReadonly);
        OSL_ENSURE( rTOXSect.SwSection::GetType() == TOX_CONTENT_SECTION, "not a TOXContentSection" );

        SwSectionData aSectionData(rTOXSect);
        aSectionData.SetProtectFlag(bReadonly);
        UpdateSection( GetSectionFormatPos( *rTOXSect.GetFormat()  ), aSectionData );
    }

    const SwTOXBase*    SwEditShell::GetDefaultTOXBase( TOXTypes eTyp, bool bCreate )
    {
        return GetDoc()->GetDefaultTOXBase( eTyp, bCreate );
    }

    void    SwEditShell::SetDefaultTOXBase(const SwTOXBase& rBase)
    {
        GetDoc()->SetDefaultTOXBase(rBase);
    }

    /// Insert listing and create content
    void SwEditShell::InsertTableOf( const SwTOXBase& rTOX, const SfxItemSet* pSet )
    {
        SET_CURR_SHELL( this );
        StartAllAction();

        SwDocShell* pDocSh = GetDoc()->GetDocShell();
        ::StartProgress( STR_STATSTR_TOX_INSERT, 0, 0, pDocSh );
        ::SetProgressText( STR_STATSTR_TOX_INSERT, pDocSh );

        // Insert listing
        const SwTOXBaseSection* pTOX = mxDoc->InsertTableOf(
                                            *GetCursor()->GetPoint(), rTOX, pSet, true );
        OSL_ENSURE(pTOX, "No current TOx");

        // start formatting
        CalcLayout();

        // insert page numbering
        const_cast<SwTOXBaseSection*>(pTOX)->UpdatePageNum();

        pTOX->SetPosAtStartEnd( *GetCursor()->GetPoint() );

        // Fix for empty listing
        InvalidateWindows( maVisArea );
        ::EndProgress( pDocSh );
        EndAllAction();
    }

    /// update tables of content
    void SwEditShell::UpdateTableOf( const SwTOXBase& rTOX, const SfxItemSet* pSet )
    {
        OSL_ENSURE( dynamic_cast<const SwTOXBaseSection*>( &rTOX) !=  nullptr,  "no TOXBaseSection!" );
        SwTOXBaseSection* pTOX = const_cast<SwTOXBaseSection*>(static_cast<const SwTOXBaseSection*>(&rTOX));
        OSL_ENSURE(pTOX, "no current listing");
        if( pTOX && nullptr != pTOX->GetFormat()->GetSectionNode() )
        {
            SwDoc* pMyDoc = GetDoc();
            SwDocShell* pDocSh = pMyDoc->GetDocShell();

            bool bInIndex = pTOX == GetCurTOX();
            SET_CURR_SHELL( this );
            StartAllAction();

            ::StartProgress( STR_STATSTR_TOX_UPDATE, 0, 0, pDocSh );
            ::SetProgressText( STR_STATSTR_TOX_UPDATE, pDocSh );

            pMyDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::TOXCHANGE, nullptr);

            // create listing stub
            pTOX->Update(pSet);

            // correct Cursor
            if( bInIndex )
                pTOX->SetPosAtStartEnd( *GetCursor()->GetPoint() );

            // start formatting
            CalcLayout();

            // insert page numbering
            pTOX->UpdatePageNum();

            pMyDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::TOXCHANGE, nullptr);

            ::EndProgress( pDocSh );
            EndAllAction();
        }
    }

    /// Get current listing before or at the Cursor
    const SwTOXBase* SwEditShell::GetCurTOX() const
    {
        return SwDoc::GetCurTOX( *GetCursor()->GetPoint() );
    }

    bool SwEditShell::DeleteTOX( const SwTOXBase& rTOXBase, bool bDelNodes )
    {
        return GetDoc()->DeleteTOX( rTOXBase, bDelNodes );
    }

    // manage types of listings

    const SwTOXType* SwEditShell::GetTOXType(TOXTypes eTyp, sal_uInt16 nId) const
    {
        return mxDoc->GetTOXType(eTyp, nId);
    }

    // manage keys for the alphabetical index

    void SwEditShell::GetTOIKeys( SwTOIKeyType eTyp, std::vector<OUString>& rArr ) const
    {
        GetDoc()->GetTOIKeys( eTyp, rArr );
    }

    sal_uInt16 SwEditShell::GetTOXCount() const
    {
        const SwSectionFormats& rFormats = GetDoc()->GetSections();
        sal_uInt16 nRet = 0;
        for( auto n = rFormats.size(); n; )
        {
            const SwSection* pSect = rFormats[ --n ]->GetSection();
            if( TOX_CONTENT_SECTION == pSect->GetType() &&
                pSect->GetFormat()->GetSectionNode() )
                ++nRet;
        }
        return nRet;
    }

    const SwTOXBase* SwEditShell::GetTOX( sal_uInt16 nPos ) const
    {
        const SwSectionFormats& rFormats = GetDoc()->GetSections();
        sal_uInt16 nCnt {0};
        for( const SwSectionFormat *pFormat : rFormats )
        {
            const SwSection* pSect = pFormat->GetSection();
            if( TOX_CONTENT_SECTION == pSect->GetType() &&
                pSect->GetFormat()->GetSectionNode() &&
                nCnt++ == nPos )
            {
                OSL_ENSURE( dynamic_cast<const SwTOXBaseSection*>( pSect) !=  nullptr, "no TOXBaseSection!" );
                return static_cast<const SwTOXBaseSection*>(pSect);
            }
        }
        return nullptr;
    }

    /** Update of all listings after reading-in a file */
    void SwEditShell::SetUpdateTOX( bool bFlag )
    {
        GetDoc()->SetUpdateTOX( bFlag );
    }

    bool SwEditShell::IsUpdateTOX() const
    {
        return GetDoc()->IsUpdateTOX();
    }

    OUString const & SwEditShell::GetTOIAutoMarkURL() const
    {
        return GetDoc()->GetTOIAutoMarkURL();
    }

    void SwEditShell::SetTOIAutoMarkURL(const OUString& rSet)
    {
        GetDoc()->SetTOIAutoMarkURL(rSet);
    }

    void SwEditShell::ApplyAutoMark()
    {
        StartAllAction();
        bool bDoesUndo = DoesUndo();
        DoUndo(false);
        //1. remove all automatic generated index entries if AutoMarkURL has a
        //   length and the file exists
        //2. load file
        //3. select all occurrences of the searched words
        //4. apply index entries

        OUString sAutoMarkURL(GetDoc()->GetTOIAutoMarkURL());
        if( !sAutoMarkURL.isEmpty() && FStatHelper::IsDocument( sAutoMarkURL ))
        {
            //1.
            const SwTOXType* pTOXType = GetTOXType(TOX_INDEX, 0);

            SwTOXMarks aMarks;
            SwTOXMark::InsertTOXMarks( aMarks, *pTOXType );
            for( SwTOXMark* pMark : aMarks )
            {
                if(pMark->IsAutoGenerated() && pMark->GetTextTOXMark())
                    // mba: test iteration; objects are deleted in iteration
                    DeleteTOXMark(pMark);
            }

            //2.
            SfxMedium aMedium( sAutoMarkURL, StreamMode::STD_READ );
            SvStream& rStrm = *aMedium.GetInStream();
            Push();
            rtl_TextEncoding eChrSet = ::osl_getThreadTextEncoding();

            // SearchOptions to be used in loop below
            sal_Int32 const nLEV_Other    = 2;    //  -> changedChars;
            sal_Int32 const nLEV_Longer   = 3;    //! -> deletedChars;
            sal_Int32 const nLEV_Shorter  = 1;    //! -> insertedChars;

            i18nutil::SearchOptions2 aSearchOpt(
                                SearchAlgorithms_ABSOLUTE,
                                SearchFlags::LEV_RELAXED,
                                "", "",
                                SvtSysLocale().GetLanguageTag().getLocale(),
                                nLEV_Other, nLEV_Longer, nLEV_Shorter,
                                TransliterationFlags::NONE,
                                SearchAlgorithms2::ABSOLUTE,
                                '\\' );

            while (rStrm.good())
            {
                OString aRdLine;
                rStrm.ReadLine( aRdLine );

                // # -> comment
                // ; -> delimiter between entries ->
                // Format: TextToSearchFor;AlternativeString;PrimaryKey;SecondaryKey;CaseSensitive;WordOnly
                // Leading and trailing blanks are ignored
                if( !aRdLine.isEmpty() && '#' != aRdLine[0] )
                {
                    OUString sLine(OStringToOUString(aRdLine, eChrSet));

                    sal_Int32 nTokenPos = 0;
                    OUString sToSelect( sLine.getToken(0, ';', nTokenPos ) );
                    if( !sToSelect.isEmpty() )
                    {
                        OUString sAlternative = sLine.getToken(0, ';', nTokenPos);
                        OUString sPrimary     = sLine.getToken(0, ';', nTokenPos);
                        OUString sSecondary   = sLine.getToken(0, ';', nTokenPos);
                        OUString sCase        = sLine.getToken(0, ';', nTokenPos);
                        OUString sWordOnly    = sLine.getToken(0, ';', nTokenPos);

                        //3.
                        bool bCaseSensitive = !sCase.isEmpty() && sCase != "0";
                        bool bWordOnly = !sWordOnly.isEmpty() && sWordOnly != "0";

                        if (!bCaseSensitive)
                        {
                            aSearchOpt.transliterateFlags |=
                                         TransliterationFlags::IGNORE_CASE;
                        }
                        else
                        {
                            aSearchOpt.transliterateFlags &=
                                        ~TransliterationFlags::IGNORE_CASE;
                        }
                        if ( bWordOnly)
                            aSearchOpt.searchFlag |=  SearchFlags::NORM_WORD_ONLY;
                        else
                            aSearchOpt.searchFlag &= ~SearchFlags::NORM_WORD_ONLY;

                        aSearchOpt.searchString = sToSelect;

                        KillPams();
                        bool bCancel;

                        // todo/mba: assuming that notes shouldn't be searched
                        sal_uLong nRet = Find( aSearchOpt, false/*bSearchInNotes*/, SwDocPositions::Start, SwDocPositions::End, bCancel,
                                        FindRanges::InSelAll );

                        if(nRet)
                        {
                            SwTOXMark* pTmpMark = new SwTOXMark(pTOXType);
                            if( !sPrimary.isEmpty() )
                            {
                                pTmpMark->SetPrimaryKey( sPrimary );
                                if( !sSecondary.isEmpty() )
                                    pTmpMark->SetSecondaryKey( sSecondary );
                            }
                            if( !sAlternative.isEmpty() )
                                pTmpMark->SetAlternativeText(sAlternative);
                            pTmpMark->SetMainEntry(false);
                            pTmpMark->SetAutoGenerated(true);
                            //4.
                            SwEditShell::Insert(*pTmpMark);
                        }
                    }
                }
            }
            KillPams();
            Pop(PopMode::DeleteCurrent);
        }
        DoUndo(bDoesUndo);
        EndAllAction();
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V560 A part of conditional expression is always true: pTOX.