Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  docedt.cxx   Sprache: 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 <fmtanchr.hxx>
#include <fmtcntnt.hxx>
#include <acorrect.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentUndoRedo.hxx>
#include <docsh.hxx>
#include <docary.hxx>
#include <mdiexp.hxx>
#include <mvsave.hxx>
#include <redline.hxx>
#include <rolbck.hxx>
#include <rootfrm.hxx>
#include <splargs.hxx>
#include <swcrsr.hxx>
#include <txtfrm.hxx>
#include <unoflatpara.hxx>
#include <SwGrammarMarkUp.hxx>
#include <docedt.hxx>
#include <frmfmt.hxx>
#include <ndtxt.hxx>
#include <undobj.hxx>
#include <frameformats.hxx>
#include <unotxdoc.hxx>

#include <vector>
#include <com/sun/star/linguistic2/XProofreadingIterator.hpp>
#include <osl/diagnose.h>

using namespace ::com::sun::star;
using namespace ::com::sun::star::linguistic2;


void RestFlyInRange( SaveFlyArr & rArr, const SwPosition& rStartPos,
                      const SwNode* pInsertPos, bool const isForceToStartPos)
{
    SwPosition aPos(rStartPos);
    for(const SaveFly & rSave : rArr)
    {
        // create new anchor
        SwFrameFormat* pFormat = rSave.pFrameFormat;
        SwFormatAnchor aAnchor( pFormat->GetAnchor() );

        if (rSave.isAtInsertNode || isForceToStartPos)
        {
            if( pInsertPos != nullptr )
            {
                if (aAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA)
                {
                    assert(pInsertPos->GetContentNode());
                    aPos.Assign( *pInsertPos->GetContentNode(),
                        rSave.nContentIndex);
                }
                else
                {
                    assert(aAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR);
                    aPos = rStartPos;
                }
            }
            else
            {
                aPos.Assign(rStartPos.GetNode());
                assert(aPos.GetNode().GetContentNode());
            }
        }
        else
        {
            aPos.Assign(rStartPos.GetNodeIndex() + rSave.nNdDiff);
            assert(aPos.GetNode().GetContentNode());
            aPos.SetContent(
                rSave.nNdDiff == SwNodeOffset(0)
                    ? rStartPos.GetContentIndex() + rSave.nContentIndex
                    : rSave.nContentIndex);
        }

        aAnchor.SetAnchor( &aPos );
        pFormat->GetDoc().GetSpzFrameFormats()->push_back(static_cast<sw::SpzFrameFormat*>(pFormat));
        // SetFormatAttr should call Modify() and add it to the node
        pFormat->SetFormatAttr( aAnchor );
        SwContentNode* pCNd = aPos.GetNode().GetContentNode();
        if (pCNd && pCNd->getLayoutFrame(pFormat->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr))
            pFormat->MakeFrames();
    }
    sw::CheckAnchoredFlyConsistency(rStartPos.GetNode().GetDoc());
}

void SaveFlyInRange( const SwNodeRange& rRg, SaveFlyArr& rArr )
{
    sw::SpzFrameFormats& rSpzs = *rRg.aStart.GetNode().GetDoc().GetSpzFrameFormats();
    sw::FrameFormats<sw::SpzFrameFormat*>::size_type n = 0;
    while (n < rSpzs.size())
    {
        auto pSpz = rSpzs[n];
        SwFormatAnchor const*const pAnchor = &pSpz->GetAnchor();
        SwNode const*const pAnchorNode = pAnchor->GetAnchorNode();
        if (pAnchorNode &&
            ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
             (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
            rRg.aStart <= *pAnchorNode && *pAnchorNode < rRg.aEnd.GetNode() )
        {
            SaveFly aSave( pAnchorNode->GetIndex() - rRg.aStart.GetIndex(),
                            (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())
                                ? pAnchor->GetAnchorContentOffset()
                                : 0,
                            pSpz, false );
            rArr.push_back( aSave );
            pSpz->DelFrames();
            // set a dummy anchor position to maintain anchoring invariants
            SwFormatAnchor aAnchor( pSpz->GetAnchor() );
            aAnchor.SetAnchor(nullptr);
            pSpz->SetFormatAttr(aAnchor);
            rSpzs.erase( rSpzs.begin() + n );
            continue;
        }
        ++n;
    }
    sw::CheckAnchoredFlyConsistency(rRg.aStart.GetNode().GetDoc());
}

void SaveFlyInRange( const SwPaM& rPam, const SwPosition& rInsPos,
        SaveFlyArr& rArr, bool bMoveAllFlys, SwHistory *const pHistory)
{
    sw::SpzFrameFormats& rFormats = *rPam.GetPoint()->GetNode().GetDoc().GetSpzFrameFormats();
    sw::SpzFrameFormat* pFormat;
    const SwFormatAnchor* pAnchor;

    const SwPosition* pPos = rPam.Start();
    const SwNode& rSttNd = pPos->GetNode();

    SwPosition atParaEnd(*rPam.End());
    if (bMoveAllFlys)
    {
        assert(!rPam.End()->GetNode().IsTextNode() // can be table end-node
            || rPam.End()->GetContentIndex() == rPam.End()->GetNode().GetTextNode()->Len());
        atParaEnd.Adjust(SwNodeOffset(1));
    }

    for(sw::FrameFormats<sw::SpzFrameFormat*>::size_type n = 0; n < rFormats.size(); ++n )
    {
        pFormat = rFormats[n];
        pAnchor = &pFormat->GetAnchor();
        const SwPosition* pAPos = pAnchor->GetContentAnchor();
        const SwNodeIndex* pContentIdx;
        if (pAPos &&
            ((RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()) ||
             (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())) &&
            // do not move if the InsPos is in the ContentArea of the Fly
            ( nullptr == ( pContentIdx = pFormat->GetContent().GetContentIdx() ) ||
              (*pContentIdx >= rInsPos.GetNode() ||
                rInsPos.GetNode() >= *pContentIdx->GetNode().EndOfSectionNode())))
        {
            bool bInsPos = false;

            if (       (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()
                        && IsDestroyFrameAnchoredAtChar(*pAPos, *rPam.Start(), *rPam.End()))
                    || (RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()
                        && IsSelectFrameAnchoredAtPara(*pAPos, *rPam.Start(), atParaEnd,
                            bMoveAllFlys
                                ? DelContentType::CheckNoCntnt|DelContentType::AllMask
                                : DelContentType::AllMask))
                    || (RndStdIds::FLY_AT_PARA == pAnchor->GetAnchorId()
                            && (bInsPos = (rInsPos.GetNode() == pAPos->GetNode())))
                    || (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId()
                            && (bInsPos = (rInsPos == *pAPos))))
            {
                if (pHistory)
                {
                    pHistory->AddChangeFlyAnchor(*pFormat);
                }
                SaveFly aSave( pAPos->GetNodeIndex() - rSttNd.GetIndex(),
                    (RndStdIds::FLY_AT_CHAR == pAnchor->GetAnchorId())
                        ? (pAPos->GetNode() == rSttNd)
                            ? pAPos->GetContentIndex() - rPam.Start()->GetContentIndex()
                            : pAPos->GetContentIndex()
                        : 0,
                                pFormat, bInsPos );
                rArr.push_back( aSave );
                pFormat->DelFrames();
                // set a dummy anchor position to maintain anchoring invariants
                SwFormatAnchor aAnchor( pFormat->GetAnchor() );
                aAnchor.SetAnchor(nullptr);
                pFormat->SetFormatAttr(aAnchor);
                rFormats.erase( rFormats.begin() + n-- );
            }
        }
    }
    sw::CheckAnchoredFlyConsistency(rPam.GetPoint()->GetNode().GetDoc());
}

/// Delete and move all Flys at the paragraph, that are within the selection.
/// If there is a Fly at the SPoint, it is moved onto the Mark.
void DelFlyInRange( SwNode& rMkNd,
                    SwNode& rPtNd,
                    std::optional<sal_Int32> oMkContentIdx, std::optional<sal_Int32> oPtContentIdx)
{
    assert(oMkContentIdx.has_value() == oPtContentIdx.has_value());
    SwPosition const point(oPtContentIdx
                            ? SwPosition(rPtNd, rPtNd.GetContentNode(), *oPtContentIdx)
                            : SwPosition(rPtNd));
    SwPosition const mark(oPtContentIdx
                            ? SwPosition(rMkNd, rMkNd.GetContentNode(), *oMkContentIdx)
                            : SwPosition(rMkNd));
    SwPosition const& rStart = mark <= point ? mark : point;
    SwPosition const& rEnd   = mark <= point ? point : mark;

    SwDoc& rDoc = rMkNd.GetDoc();
    sw::SpzFrameFormats& rTable = *rDoc.GetSpzFrameFormats();
    for ( auto i = rTable.size(); i; )
    {
        sw::SpzFrameFormat* pFormat = rTable[--i];
        const SwFormatAnchor &rAnch = pFormat->GetAnchor();
        SwPosition const*const pAPos = rAnch.GetContentAnchor();
        if (pAPos &&
            (((rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA)
                && IsSelectFrameAnchoredAtPara(*pAPos, rStart, rEnd, oPtContentIdx
                    ? DelContentType::AllMask|DelContentType::WriterfilterHack
                    : DelContentType::AllMask|DelContentType::WriterfilterHack|DelContentType::CheckNoCntnt))
            || ((rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
                && IsDestroyFrameAnchoredAtChar(*pAPos, rStart, rEnd, oPtContentIdx
                    ? DelContentType::AllMask|DelContentType::WriterfilterHack
                    : DelContentType::AllMask|DelContentType::WriterfilterHack|DelContentType::CheckNoCntnt))))
        {
            // If the Fly is deleted, all Flys in its content have to be deleted too.
            const SwFormatContent &rContent = pFormat->GetContent();
            // But only fly formats own their content, not draw formats.
            if (rContent.GetContentIdx() && pFormat->Which() == RES_FLYFRMFMT)
            {
                DelFlyInRange( rContent.GetContentIdx()->GetNode(),
                               *rContent.GetContentIdx()->
                                        GetNode().EndOfSectionNode() );
                // Position could have been moved!
                if (i > rTable.size())
                    i = rTable.size();
                else if (i == rTable.size() || pFormat != rTable[i])
                    i = std::distance(rTable.begin(), rTable.find(pFormat));
            }

            rDoc.getIDocumentLayoutAccess().DelLayoutFormat( pFormat );

            // DelLayoutFormat can also trigger the deletion of objects.
            if (i > rTable.size())
                i = rTable.size();
        }
    }
}

// #i59534: Redo of insertion of multiple text nodes runs into trouble
// because of unnecessary expanded redlines
// From now on this class saves the redline positions of all redlines which ends exact at the
// insert position (node _and_ content index)
SaveRedlEndPosForRestore::SaveRedlEndPosForRestore( const SwNode& rInsIdx, sal_Int32 nCnt )
    : mnSaveContent( nCnt )
{
    const SwDoc& rDest = rInsIdx.GetDoc();
    if( rDest.getIDocumentRedlineAccess().GetRedlineTable().empty() )
        return;

    SwRedlineTable::size_type nFndPos;
    const SwPosition* pEnd;
    SwPosition aSrcPos( rInsIdx, rInsIdx.GetContentNode(), nCnt );
    rDest.getIDocumentRedlineAccess().GetRedline( aSrcPos, &nFndPos );
    const SwRangeRedline* pRedl;
    while( nFndPos--
          && *( pEnd = ( pRedl = rDest.getIDocumentRedlineAccess().GetRedlineTable()[ nFndPos ] )->End() ) == aSrcPos
          && *pRedl->Start() < aSrcPos )
    {
        if( !moSaveIndex )
        {
            moSaveIndex.emplace( rInsIdx, -1 );
        }
        mvSavArr.push_back( const_cast<SwPosition*>(pEnd) );
    }
}

SaveRedlEndPosForRestore::~SaveRedlEndPosForRestore()
{
    moSaveIndex.reset();
}

void SaveRedlEndPosForRestore::Restore()
{
    if (mvSavArr.empty())
        return;
    ++(*moSaveIndex);
    SwContentNode* pNode = moSaveIndex->GetNode().GetContentNode();
    // If there's no content node at the remembered position, we will not restore the old position
    // This may happen if a table (or section?) will be inserted.
    if( pNode )
    {
        SwPosition aPos( *moSaveIndex, pNode, mnSaveContent );
        forauto n = mvSavArr.size(); n; )
            *mvSavArr[ --n ] = aPos;
    }
}

/// Convert list of ranges of whichIds to a corresponding list of whichIds
static std::vector<sal_uInt16> lcl_RangesToVector(const WhichRangesContainer& pRanges)
{
    std::vector<sal_uInt16> aResult;

    for(const WhichPair& rPair : pRanges)
    {
        for (sal_uInt16 j = rPair.first; j <= rPair.second; j++)
            aResult.push_back(j);
    }

    return aResult;
}

void sw_GetJoinFlags( SwPaM& rPam, bool& rJoinText, bool& rJoinPrev )
{
    rJoinText = false;
    rJoinPrev = false;
    if( rPam.GetPoint()->GetNode() == rPam.GetMark()->GetNode() )
        return;

    auto [pStart, pEnd] = rPam.StartEnd(); // SwPosition*
    SwTextNode *pSttNd = pStart->GetNode().GetTextNode();
    if( !pSttNd )
        return;

    SwTextNode *pEndNd = pEnd->GetNode().GetTextNode();
    rJoinText = nullptr != pEndNd;
    if( !rJoinText )
        return;

    bool bExchange = pStart == rPam.GetPoint();
    if( !pStart->GetContentIndex() &&
        pEndNd->GetText().getLength() != pEnd->GetContentIndex())
        bExchange = !bExchange;
    if( bExchange )
        rPam.Exchange();
    rJoinPrev = rPam.GetPoint() == pStart;
    OSL_ENSURE( !pStart->GetContentIndex() &&
        pEndNd->GetText().getLength() != pEnd->GetContentIndex()
        ? (rPam.GetPoint()->GetNode() < rPam.GetMark()->GetNode())
        : (rPam.GetPoint()->GetNode() > rPam.GetMark()->GetNode()),
        "sw_GetJoinFlags");
}

bool sw_JoinText( SwPaM& rPam, bool bJoinPrev )
{
    SwNodeIndex aIdx( rPam.GetPoint()->GetNode() );
    SwTextNode *pTextNd = aIdx.GetNode().GetTextNode();
    SwNodeIndex aOldIdx( aIdx );
    SwTextNode *pOldTextNd = pTextNd;

    if( pTextNd && pTextNd->CanJoinNext( &aIdx ) )
    {
        SwDoc& rDoc = rPam.GetDoc();
        if( bJoinPrev )
        {
            // We do not need to handle xmlids in this case, because
            // it is only invoked if one paragraph is/becomes completely empty
            // (see sw_GetJoinFlags)
            {
                // If PageBreaks are deleted/set, it must not be added to the Undo history!
                // Also, deleting the Node is not added to the Undo history!
                ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());

                /* PageBreaks, PageDesc, ColumnBreaks */
                // If we need to change something about the logic to copy the PageBreaks,
                // PageDesc, etc. we also have to change SwUndoDelete.
                // There, we copy the AUTO PageBreak from the GetMarkNode!

                /* The MarkNode */
                pTextNd = aIdx.GetNode().GetTextNode();
                if (pTextNd->HasSwAttrSet())
                {
                    if( SfxItemState::SET == pTextNd->GetpSwAttrSet()->GetItemState( RES_BREAK, false) )
                        pTextNd->ResetAttr( RES_BREAK );
                    if( pTextNd->HasSwAttrSet() &&
                        SfxItemState::SET == pTextNd->GetpSwAttrSet()->GetItemState( RES_PAGEDESC, false ) )
                        pTextNd->ResetAttr( RES_PAGEDESC );
                }

                /* The PointNode */
                if( pOldTextNd->HasSwAttrSet() )
                {
                    const SfxPoolItem* pItem;
                    SfxItemSet aSet( rDoc.GetAttrPool(), aBreakSetRange );
                    const SfxItemSet* pSet = pOldTextNd->GetpSwAttrSet();
                    if( SfxItemState::SET == pSet->GetItemState( RES_BREAK,
                        false, &pItem ) )
                        aSet.Put( *pItem );
                    if( SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC,
                        false, &pItem ) )
                        aSet.Put( *pItem );
                    if( aSet.Count() )
                        pTextNd->SetAttr( aSet );
                }
                pOldTextNd->FormatToTextAttr( pTextNd );

                const std::shared_ptr< sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
                pContentStore->Save(rDoc, aOldIdx.GetIndex(), SAL_MAX_INT32);

                SwContentIndex aAlphaIdx(pTextNd);
                pOldTextNd->CutText( pTextNd, aAlphaIdx, SwContentIndex(pOldTextNd),
                                    pOldTextNd->Len() );
                SwPosition aAlphaPos( aIdx, aAlphaIdx );
                rDoc.CorrRel( rPam.GetPoint()->GetNode(), aAlphaPos, 0, true );

                // move all Bookmarks/TOXMarks
                if( !pContentStore->Empty() )
                    pContentStore->Restore( rDoc, aIdx.GetIndex() );

                // If the passed PaM is not in the Cursor ring,
                // treat it separately (e.g. when it's being called from AutoFormat)
                if( pOldTextNd == rPam.GetBound().GetContentNode() )
                    rPam.GetBound() = aAlphaPos;
                if( pOldTextNd == rPam.GetBound( false ).GetContentNode() )
                    rPam.GetBound( false ) = std::move(aAlphaPos);
            }
            // delete the Node, at last!
            SwNode::Merge const eOldMergeFlag(pOldTextNd->GetRedlineMergeFlag());
            if (eOldMergeFlag == SwNode::Merge::First
                && !pTextNd->IsCreateFrameWhenHidingRedlines())
            {
                sw::MoveDeletedPrevFrames(*pOldTextNd, *pTextNd);
            }
            rDoc.GetNodes().Delete( aOldIdx );
            sw::CheckResetRedlineMergeFlag(*pTextNd,
                    eOldMergeFlag == SwNode::Merge::NonFirst
                        ? sw::Recreate::Predecessor
                        : sw::Recreate::No);
        }
        else
        {
            SwTextNode* pDelNd = aIdx.GetNode().GetTextNode();
            if( pTextNd->Len() )
                pDelNd->FormatToTextAttr( pTextNd );
            else
            {
                /* This case was missed:

                   <something></something>   <-- pTextNd
                   <other>ccc</other>        <-- pDelNd

                   <something> and <other> are paragraph
                   attributes. The attribute <something> stayed if not
                   overwritten by an attribute in "ccc". Fixed by
                   first resetting all character attributes in first
                   paragraph (pTextNd).
                */

                std::vector<sal_uInt16> aShorts =
                    lcl_RangesToVector(aCharFormatSetRange);
                pTextNd->ResetAttr(aShorts);

                if( pDelNd->HasSwAttrSet() )
                {
                    // only copy the character attributes
                    SfxItemSet aTmpSet( rDoc.GetAttrPool(), aCharFormatSetRange );
                    aTmpSet.Put( *pDelNd->GetpSwAttrSet() );
                    pTextNd->SetAttr( aTmpSet );
                }
            }

            rDoc.CorrRel( aIdx.GetNode(), *rPam.GetPoint(), 0, true );
            // #i100466# adjust given <rPam>, if it does not belong to the cursors
            if ( pDelNd == rPam.GetBound().GetContentNode() )
            {
                rPam.GetBound().Assign( *pTextNd );
            }
            if( pDelNd == rPam.GetBound( false ).GetContentNode() )
            {
                rPam.GetBound( false ).Assign( *pTextNd );
            }
            pTextNd->JoinNext();
        }
        return true;
    }
    else return false;
}

static void lcl_syncGrammarError( SwTextNode &rTextNode, linguistic2::ProofreadingResult&&nbsp;rResult,
    const ModelToViewHelper &rConversionMap )
{
    if( rTextNode.IsGrammarCheckDirty() )
        return;
    SwGrammarMarkUp* pWrong = rTextNode.GetGrammarCheck();
    linguistic2::SingleProofreadingError* pArray = rResult.aErrors.getArray();
    sal_uInt16 j = 0;
    if( pWrong )
    {
        for( sal_Int32 i = 0; i < rResult.aErrors.getLength(); ++i )
        {
            const linguistic2::SingleProofreadingError &rError = rResult.aErrors[i];
            const sal_Int32 nStart = rConversionMap.ConvertToModelPosition( rError.nErrorStart ).mnPos;
            const sal_Int32 nEnd = rConversionMap.ConvertToModelPosition( rError.nErrorStart + rError.nErrorLength ).mnPos;
            if( i != j )
                pArray[j] = pArray[i];
            if( pWrong->LookForEntry( nStart, nEnd ) )
                ++j;
        }
    }
    if( rResult.aErrors.getLength() > j )
        rResult.aErrors.realloc( j );
}

uno::Any SwDoc::Spell( SwPaM& rPaM,
                    uno::Reference< XSpellChecker1 > const &xSpeller,
                    sal_uInt16* pPageCnt, sal_uInt16* pPageSt,
                    bool bGrammarCheck,
                    SwRootFrame const*const pLayout,
                    SwConversionArgs *pConvArgs  ) const
{
    SwPosition* const pSttPos = rPaM.Start();
    SwPosition* const pEndPos = rPaM.End();

    std::unique_ptr<SwSpellArgs> pSpellArgs;
    if (pConvArgs)
    {
        pConvArgs->SetStart(*pSttPos);
        pConvArgs->SetEnd(*pEndPos);
    }
    else
        pSpellArgs.reset(new SwSpellArgs( xSpeller, *pSttPos, *pEndPos, bGrammarCheck ));

    SwNodeOffset nCurrNd = pSttPos->GetNodeIndex();
    SwNodeOffset nEndNd = pEndPos->GetNodeIndex();

    bool bIsReadOnly = false;
    const SfxObjectShell* pObjShell = GetDocShell();
    if (pObjShell && pObjShell->IsReadOnly())
        bIsReadOnly = true;

    uno::Any aRet;
    if( nCurrNd <= nEndNd )
    {
        SwContentFrame* pContentFrame;
        bool bGoOn = true;
        while( bGoOn )
        {
            SwNode* pNd = GetNodes()[ nCurrNd ];
            switch( pNd->GetNodeType() )
            {
            case SwNodeType::Text:
                if( nullptr != ( pContentFrame = pNd->GetTextNode()->getLayoutFrame( getIDocumentLayoutAccess().GetCurrentLayout() )) )
                {
                    // skip protected and hidden Cells and Flys
                    if( pContentFrame->IsProtected() )
                    {
                        nCurrNd = pNd->EndOfSectionIndex();
                    }
                    else if( !pContentFrame->IsHiddenNow() )
                    {
                        if( pPageCnt && *pPageCnt && pPageSt )
                        {
                            sal_uInt16 nPageNr = pContentFrame->GetPhyPageNum();
                            if( !*pPageSt )
                            {
                                *pPageSt = nPageNr;
                                if( *pPageCnt < *pPageSt )
                                    *pPageCnt = *pPageSt;
                            }
                            tools::Long nStat;
                            if( nPageNr >= *pPageSt )
                                nStat = nPageNr - *pPageSt + 1;
                            else
                                nStat = nPageNr + *pPageCnt - *pPageSt + 1;
                            ::SetProgressState( nStat, GetDocShell() );
                        }
                        //Spell() changes the pSpellArgs in case an error is found
                        sal_Int32 nBeginGrammarCheck = 0;
                        sal_Int32 nEndGrammarCheck = 0;
                        if( pSpellArgs && pSpellArgs->bIsGrammarCheck)
                        {
                            nBeginGrammarCheck = &pSpellArgs->pStartPos->GetNode() == pNd ?  pSpellArgs->pStartPos->GetContentIndex() : 0;
                            // if grammar checking starts inside of a sentence the start position has to be adjusted
                            if( nBeginGrammarCheck )
                            {
                                SwContentIndex aStartIndex( pNd->GetTextNode(), nBeginGrammarCheck );
                                SwPosition aStart( *pNd, aStartIndex );
                                SwCursor aCursor(aStart, nullptr);
                                SwPosition aOrigPos = *aCursor.GetPoint();
                                aCursor.GoSentence( SwCursor::START_SENT );
                                if( aOrigPos != *aCursor.GetPoint() )
                                {
                                    nBeginGrammarCheck = aCursor.GetPoint()->GetContentIndex();
                                }
                            }
                            nEndGrammarCheck = (&pSpellArgs->pEndPos->GetNode() == pNd)
                                ? pSpellArgs->pEndPos->GetContentIndex()
                                : pNd->GetTextNode()
                                    ->GetText().getLength();
                        }

                        sal_Int32 nSpellErrorPosition = pNd->GetTextNode()->GetText().getLength();
                        if ((!pConvArgs && pNd->GetTextNode()->Spell(pSpellArgs.get(), bIsReadOnly))
                            || (pConvArgs && pNd->GetTextNode()->Convert(*pConvArgs)))
                        {
                            // Cancel and remember position
                            if( pSpellArgs )
                                nSpellErrorPosition = pSpellArgs->pStartPos->GetContentIndex() > pSpellArgs->pEndPos->GetContentIndex() ?
                                            pSpellArgs->pEndPos->GetContentIndex() :
                                            pSpellArgs->pStartPos->GetContentIndex();
                            if( nCurrNd != nEndNd )
                            {
                                pSttPos->Assign(nCurrNd, pSttPos->GetContentIndex());
                                pEndPos->Assign(nCurrNd, pEndPos->GetContentIndex());
                                nCurrNd = nEndNd;
                            }
                        }

                        if( pSpellArgs && pSpellArgs->bIsGrammarCheck )
                        {
                            uno::Reference< linguistic2::XProofreadingIterator >  xGCIterator( GetGCIterator() );
                            if (xGCIterator.is())
                            {
                                if (const SwDocShell* pShell = GetDocShell())
                                {
                                    rtl::Reference< SwXTextDocument > xDoc = pShell->GetBaseModel();
                                    // Expand the string:
                                    const ModelToViewHelper aConversionMap(*pNd->GetTextNode(), pLayout);
                                    const OUString& aExpandText = aConversionMap.getViewText();

                                    // get XFlatParagraph to use...
                                    uno::Reference< text::XFlatParagraph > xFlatPara = new SwXFlatParagraph( *pNd->GetTextNode(), aExpandText, aConversionMap );

                                    // get error position of cursor in XFlatParagraph
                                    linguistic2::ProofreadingResult aResult;
                                    bool bGrammarErrors;
                                    do
                                    {
                                        aConversionMap.ConvertToViewPosition( nBeginGrammarCheck );
                                        aResult = xGCIterator->checkSentenceAtPosition(
                                                cppu::getXWeak(xDoc.get()), xFlatPara, aExpandText, lang::Locale(), nBeginGrammarCheck, -1, -1 );

                                        lcl_syncGrammarError( *pNd->GetTextNode(), aResult, aConversionMap );

                                        // get suggestions to use for the specific error position
                                        bGrammarErrors = aResult.aErrors.hasElements();
                                        // if grammar checking doesn't have any progress then quit
                                        if( aResult.nStartOfNextSentencePosition <= nBeginGrammarCheck )
                                            break;
                                        // prepare next iteration
                                        nBeginGrammarCheck = aResult.nStartOfNextSentencePosition;
                                    }
                                    while( nSpellErrorPosition > aResult.nBehindEndOfSentencePosition && !bGrammarErrors && aResult.nBehindEndOfSentencePosition < nEndGrammarCheck );

                                    if( bGrammarErrors && nSpellErrorPosition >= aResult.nBehindEndOfSentencePosition )
                                    {
                                        aRet <<= aResult;
                                        //put the cursor to the current error
                                        const linguistic2::SingleProofreadingError &rError = aResult.aErrors[0];
                                        pSttPos->Assign(nCurrNd, pSttPos->GetContentIndex());
                                        pEndPos->Assign(nCurrNd, pEndPos->GetContentIndex());
                                        pSpellArgs->pStartPos->Assign(*pNd->GetTextNode(), aConversionMap.ConvertToModelPosition( rError.nErrorStart ).mnPos );
                                        pSpellArgs->pEndPos->Assign(*pNd->GetTextNode(), aConversionMap.ConvertToModelPosition( rError.nErrorStart + rError.nErrorLength ).mnPos );
                                        nCurrNd = nEndNd;
                                    }
                                }
                            }
                        }
                    }
                }
                break;
            case SwNodeType::Section:
                ifstatic_cast<SwSectionNode*>(pNd)->GetSection().IsProtect() ||
                    static_cast<SwSectionNode*>(pNd)->GetSection().IsHidden() )
                    nCurrNd = pNd->EndOfSectionIndex();
                break;
            case SwNodeType::End:
                {
                    break;
                }
            defaultbreak;
            }

            bGoOn = nCurrNd < nEndNd;
            ++nCurrNd;
        }
    }

    if( !aRet.hasValue() )
    {
        if (pConvArgs)
            aRet <<= pConvArgs->aConvText;
        else
            aRet <<= pSpellArgs->xSpellAlt;
    }

    return aRet;
}

namespace {

class SwHyphArgs : public SwInterHyphInfo
{
    SwNodeIndex m_aNodeIdx;
    const SwNode *m_pStart;
    const SwNode *m_pEnd;
    sal_uInt16 *m_pPageCnt;
    sal_uInt16 *m_pPageSt;

    sal_Int32 m_nPamStart;
    sal_Int32 m_nPamLen;

public:
    SwHyphArgs( const SwPaM *pPam, const Point &rPoint,
                sal_uInt16* pPageCount, sal_uInt16* pPageStart );
    void SetPam( SwPaM *pPam ) const;
    void SetNode( const SwNode& rNew ) { m_aNodeIdx.Assign(rNew); }
    inline void SetRange( const SwNode *pNew );
    void NextNode() { ++m_aNodeIdx; }
    sal_uInt16 *GetPageCnt() { return m_pPageCnt; }
    sal_uInt16 *GetPageSt() { return m_pPageSt; }
};

}

SwHyphArgs::SwHyphArgs( const SwPaM *pPam, const Point &rCursorPos,
                         sal_uInt16* pPageCount, sal_uInt16* pPageStart )
     : SwInterHyphInfo( rCursorPos ), m_aNodeIdx(pPam->GetPoint()->GetNode()),
     m_pPageCnt( pPageCount ), m_pPageSt( pPageStart )
{
    // The following constraints have to be met:
    // 1) there is at least one Selection
    // 2) SPoint() == Start()
    OSL_ENSURE( pPam->HasMark(), "SwDoc::Hyphenate: blowing in the wind");
    OSL_ENSURE( *pPam->GetPoint() <= *pPam->GetMark(),
            "SwDoc::Hyphenate: New York, New York");

    const SwPosition *pPoint = pPam->GetPoint();

    // Set start
    m_pStart = pPoint->GetNode().GetTextNode();
    m_nPamStart = pPoint->GetContentIndex();

    // Set End and Length
    const SwPosition *pMark = pPam->GetMark();
    m_pEnd = pMark->GetNode().GetTextNode();
    m_nPamLen = pMark->GetContentIndex();
    if( pPoint->GetNode() == pMark->GetNode() )
        m_nPamLen = m_nPamLen - pPoint->GetContentIndex();
}

inline void SwHyphArgs::SetRange( const SwNode *pNew )
{
    m_nStart = m_pStart == pNew ? m_nPamStart : 0;
    m_nEnd   = m_pEnd   == pNew ? m_nPamStart + m_nPamLen : SAL_MAX_INT32;
}

void SwHyphArgs::SetPam( SwPaM *pPam ) const
{
    pPam->GetPoint()->Assign( m_aNodeIdx, m_nWordStart );
    pPam->GetMark()->Assign( m_aNodeIdx, m_nWordStart + m_nWordLen );
}

// Returns true if we can proceed.
static bool lcl_HyphenateNode( SwNode* pNd, void* pArgs )
{
    // Hyphenate returns true if there is a hyphenation point and sets pPam
    SwTextNode *pNode = pNd->GetTextNode();
    SwHyphArgs *pHyphArgs = static_cast<SwHyphArgs*>(pArgs);
    if( pNode )
    {
        // sw_redlinehide: this will be called once per node for merged nodes;
        // the fully deleted ones won't have frames so are skipped.
        SwContentFrame* pContentFrame = pNode->getLayoutFrame( pNode->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() );
        if( pContentFrame && !pContentFrame->IsHiddenNow() )
        {
            sal_uInt16 *pPageSt = pHyphArgs->GetPageSt();
            sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt();
            if( pPageCnt && *pPageCnt && pPageSt )
            {
                sal_uInt16 nPageNr = pContentFrame->GetPhyPageNum();
                if( !*pPageSt )
                {
                    *pPageSt = nPageNr;
                    if( *pPageCnt < *pPageSt )
                        *pPageCnt = *pPageSt;
                }
                tools::Long nStat = nPageNr >= *pPageSt ? nPageNr - *pPageSt + 1
                                         : nPageNr + *pPageCnt - *pPageSt + 1;
                ::SetProgressState( nStat, pNode->GetDoc().GetDocShell() );
            }
            pHyphArgs->SetRange( pNd );
            if( pNode->Hyphenate( *pHyphArgs ) )
            {
                pHyphArgs->SetNode( *pNd );
                return false;
            }
        }
    }
    pHyphArgs->NextNode();
    return true;
}

uno::Reference< XHyphenatedWord >  SwDoc::Hyphenate(
                            SwPaM *pPam, const Point &rCursorPos,
                             sal_uInt16* pPageCnt, sal_uInt16* pPageSt )
{
    OSL_ENSURE(this == &pPam->GetDoc(), "SwDoc::Hyphenate: strangers in the night");

    if( *pPam->GetPoint() > *pPam->GetMark() )
        pPam->Exchange();

    SwHyphArgs aHyphArg( pPam, rCursorPos, pPageCnt, pPageSt );
    SwNodeIndex aTmpIdx( pPam->GetMark()->GetNode(), 1 );
    GetNodes().ForEach( pPam->GetPoint()->GetNode(), aTmpIdx.GetNode(),
                    lcl_HyphenateNode, &aHyphArg );
    aHyphArg.SetPam( pPam );
    return aHyphArg.GetHyphWord();  // will be set by lcl_HyphenateNode
}

// Save the current values to add them as automatic entries to AutoCorrect.
void SwDoc::SetAutoCorrExceptWord( std::unique_ptr<SwAutoCorrExceptWord> pNew )
{
    mpACEWord = std::move(pNew);
}

void SwDoc::DeleteAutoCorrExceptWord()
{
    mpACEWord.reset();
}

void SwDoc::CountWords( const SwPaM& rPaM, SwDocStat& rStat )
{
    // This is a modified version of SwDoc::TransliterateText
    auto [pStart, pEnd] = rPaM.StartEnd(); // SwPosition*

    const SwNodeOffset nSttNd = pStart->GetNodeIndex();
    const SwNodeOffset nEndNd = pEnd->GetNodeIndex();

    const sal_Int32 nSttCnt = pStart->GetContentIndex();
    const sal_Int32 nEndCnt = pEnd->GetContentIndex();

    const SwTextNode* pTNd = pStart->GetNode().GetTextNode();
    if( pStart == pEnd && pTNd )                  // no region ?
    {
        // do nothing
        return;
    }

    if( nSttNd != nEndNd )
    {
        SwNodeIndex aIdx( pStart->GetNode() );
        if( nSttCnt )
        {
            ++aIdx;
            if( pTNd )
                pTNd->CountWords( rStat, nSttCnt, pTNd->GetText().getLength() );
        }

        for( ; aIdx.GetIndex() < nEndNd; ++aIdx )
            if( nullptr != ( pTNd = aIdx.GetNode().GetTextNode() ))
                pTNd->CountWords( rStat, 0, pTNd->GetText().getLength() );

        if( nEndCnt && nullptr != ( pTNd = pEnd->GetNode().GetTextNode() ))
            pTNd->CountWords( rStat, 0, nEndCnt );
    }
    else if( pTNd && nSttCnt < nEndCnt )
        pTNd->CountWords( rStat, nSttCnt, nEndCnt );
}


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

Messung V0.5
C=93 H=92 G=92

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge