Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/sc/source/ui/docshell/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 51 kB image not shown  

Quelle  docsh3.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 <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <com/sun/star/document/XDocumentProperties.hpp>

#include <scitems.hxx>
#include <rangelst.hxx>
#include <editeng/flstitem.hxx>
#include <editeng/paperinf.hxx>
#include <editeng/sizeitem.hxx>
#include <o3tl/unit_conversion.hxx>
#include <officecfg/Office/Common.hxx>
#include <sal/log.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/app.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/printer.hxx>
#include <svl/numformat.hxx>
#include <svx/pageitem.hxx>
#include <svx/postattr.hxx>
#include <svx/svxids.hrc>
#include <unotools/configmgr.hxx>
#include <vcl/svapp.hxx>
#include <vcl/virdev.hxx>
#include <vcl/weld.hxx>
#include <osl/diagnose.h>

#include <docsh.hxx>
#include "docshimp.hxx"
#include <scmod.hxx>
#include <tabvwsh.hxx>
#include <viewdata.hxx>
#include <docpool.hxx>
#include <stlpool.hxx>
#include <patattr.hxx>
#include <uiitems.hxx>
#include <hints.hxx>
#include <docoptio.hxx>
#include <viewopti.hxx>
#include <pntlock.hxx>
#include <chgtrack.hxx>
#include <docfunc.hxx>
#include <formulacell.hxx>
#include <chgviset.hxx>
#include <progress.hxx>
#include <redcom.hxx>
#include <inputopt.hxx>
#include <drwlayer.hxx>
#include <inputhdl.hxx>
#include <conflictsdlg.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
#include <markdata.hxx>
#include <memory>
#include <formulaopt.hxx>

#include <comphelper/lok.hxx>
#include <sfx2/lokhelper.hxx>

//          Redraw - Notifications

void ScDocShell::PostEditView( ScEditEngineDefaulter& rEditEngine, const ScAddress& rCursorPos )
{
//  Broadcast( ScEditViewHint( pEditEngine, rCursorPos ) );

        //  Test: only active ViewShell

    ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
    if (pViewSh && &pViewSh->GetViewData().GetDocShell() == this)
    {
        ScEditViewHint aHint(rEditEngine, rCursorPos);
        pViewSh->Notify( *this, aHint );
    }
}

void ScDocShell::PostDataChanged()
{
    Broadcast( SfxHint( SfxHintId::ScDataChanged ) );
    SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScAnyDataChanged ));      // Navigator
    m_pDocument->PrepareFormulaCalc();
    //! notify navigator directly!
}

void ScDocShell::PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
                            SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, PaintPartFlags nPart,
                            sal_uInt16 nExtFlags, tools::Long nMaxWidthAffectedHint )
{
    ScRange aRange(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
    PostPaint(aRange, nPart, nExtFlags, nMaxWidthAffectedHint);
}

void ScDocShell::PostPaint( const ScRangeList& rRanges, PaintPartFlags nPart, sal_uInt16 nExtFlags, tools::Long nMaxWidthAffectedHint )
{
    ScRangeList aPaintRanges;
    std::set<SCTAB> aTabsInvalidated;
    const SCTAB nMaxTab = m_pDocument->GetTableCount() - 1;
    for (size_t i = 0, n = rRanges.size(); i < n; ++i)
    {
        const ScRange& rRange = rRanges[i];
        SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
        SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
        SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = std::min<SCTAB>(nMaxTab, rRange.aEnd.Tab());

        if (nTab1 < 0 || nTab2 < 0)
            continue;

        if (!m_pDocument->ValidCol(nCol1))
        {
            nMaxWidthAffectedHint = -1; // Hint no longer valid
            nCol1 = m_pDocument->MaxCol();
        }
        if (!m_pDocument->ValidRow(nRow1)) nRow1 = m_pDocument->MaxRow();
        if (!m_pDocument->ValidCol(nCol2))
        {
            nMaxWidthAffectedHint = -1; // Hint no longer valid
            nCol2 = m_pDocument->MaxCol();
        }
        if (!m_pDocument->ValidRow(nRow2)) nRow2 = m_pDocument->MaxRow();

        if ( m_pPaintLockData )
        {
            // #i54081# PaintPartFlags::Extras still has to be broadcast because it changes the
            // current sheet if it's invalid. All other flags added to pPaintLockData.
            PaintPartFlags nLockPart = nPart & ~PaintPartFlags::Extras;
            if ( nLockPart != PaintPartFlags::NONE )
            {
                //! nExtFlags ???
                m_pPaintLockData->AddRange( ScRange( nCol1, nRow1, nTab1,
                                                   nCol2, nRow2, nTab2 ), nLockPart );
            }

            nPart &= PaintPartFlags::Extras;  // for broadcasting
            if (nPart == PaintPartFlags::NONE)
                continue;
        }

        if (nExtFlags & SC_PF_LINES)            // respect space for lines
        {
                                                //! check for hidden columns/rows!
            if (nCol1 > 0)
            {
                nMaxWidthAffectedHint = -1; // Hint no longer valid
                --nCol1;
            }
            if (nCol2 < m_pDocument->MaxCol())
            {
                nMaxWidthAffectedHint = -1; // Hint no longer valid
                ++nCol2;
            }
            if (nRow1>0) --nRow1;
            if (nRow2<m_pDocument->MaxRow()) ++nRow2;
        }

                                                // expand for the merged ones
        if (nExtFlags & SC_PF_TESTMERGE)
            m_pDocument->ExtendMerge( nCol1, nRow1, nCol2, nRow2, nTab1 );

        if ( nCol1 != 0 || nCol2 != m_pDocument->MaxCol() )
        {
            //  Extend to whole rows if SC_PF_WHOLEROWS is set, or rotated or non-left
            //  aligned cells are contained (see UpdatePaintExt).
            //  Special handling for RTL text (#i9731#) is unnecessary now with full
            //  support of right-aligned text.

            if ( ( nExtFlags & SC_PF_WHOLEROWS ) ||
                 m_pDocument->HasAttrib( nCol1,nRow1,nTab1,
                                      m_pDocument->MaxCol(),nRow2,nTab2, HasAttrFlags::Rotate | HasAttrFlags::RightOrCenter ) )
            {
                nCol1 = 0;
                nCol2 = m_pDocument->MaxCol();
                nMaxWidthAffectedHint = -1; // Hint no longer valid
            }
        }
        aPaintRanges.push_back(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
        for (auto nTabNum = nTab1; nTabNum <= nTab2; ++nTabNum)
            aTabsInvalidated.insert(nTabNum);
    }

    Broadcast(ScPaintHint(aPaintRanges.Combine(), nPart, nMaxWidthAffectedHint));

    // LOK: we are supposed to update the row / columns headers (and actually
    // the document size too - cell size affects that, obviously)
    if ((nPart & (PaintPartFlags::Top | PaintPartFlags::Left)) && comphelper::LibreOfficeKit::isActive())
    {
        ScModelObj* pModel = GetModel();
        for (auto nTab : aTabsInvalidated)
            SfxLokHelper::notifyPartSizeChangedAllViews(pModel, nTab);
    }
}

void ScDocShell::PostPaintGridAll()
{
    PostPaint( 0,0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB, PaintPartFlags::Grid );
}

void ScDocShell::PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab, tools::Long nMaxWidthAffectedHint )
{
    PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, SC_PF_TESTMERGE, nMaxWidthAffectedHint );
}

void ScDocShell::PostPaintCell( const ScAddress& rPos, tools::Long nMaxWidthAffectedHint )
{
    PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab(), nMaxWidthAffectedHint );
}

void ScDocShell::PostPaintExtras()
{
    PostPaint( 0,0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB, PaintPartFlags::Extras );
}

void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, const ScRange& rRange )
{
    if ( ( rExtFlags & SC_PF_LINES ) == 0 &&
         m_pDocument->HasAttrib( rRange, HasAttrFlags::Lines | HasAttrFlags::Shadow | HasAttrFlags::Conditional ) )
    {
        //  If the range contains lines, shadow or conditional formats,
        //  set SC_PF_LINES to include one extra cell in all directions.

        rExtFlags |= SC_PF_LINES;
    }

    if ( ( rExtFlags & SC_PF_WHOLEROWS ) == 0 &&
         ( rRange.aStart.Col() != 0 || rRange.aEnd.Col() != m_pDocument->MaxCol() ) &&
         m_pDocument->HasAttrib( rRange, HasAttrFlags::Rotate | HasAttrFlags::RightOrCenter ) )
    {
        //  If the range contains (logically) right- or center-aligned cells,
        //  or rotated cells, set SC_PF_WHOLEROWS to paint the whole rows.
        //  This test isn't needed after the cell changes, because it's also
        //  tested in PostPaint. UpdatePaintExt may later be changed to do this
        //  only if called before the changes.

        rExtFlags |= SC_PF_WHOLEROWS;
    }
}

void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
                                                   SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab )
{
    UpdatePaintExt( rExtFlags, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ) );
}

void ScDocShell::LockPaint_Impl(bool bDoc)
{
    if ( !m_pPaintLockData )
        m_pPaintLockData.reset( new ScPaintLockData );
    m_pPaintLockData->IncLevel(bDoc);
}

void ScDocShell::UnlockPaint_Impl(bool bDoc)
{
    if ( m_pPaintLockData )
    {
        if ( m_pPaintLockData->GetLevel(bDoc) )
            m_pPaintLockData->DecLevel(bDoc);
        if (!m_pPaintLockData->GetLevel(!bDoc) && !m_pPaintLockData->GetLevel(bDoc))
        {
            //     Execute Paint now

            // don't continue collecting
            std::unique_ptr<ScPaintLockData> pPaint = std::move(m_pPaintLockData);

            ScRangeListRef xRangeList = pPaint->GetRangeList();
            if ( xRangeList.is() )
            {
                PaintPartFlags nParts = pPaint->GetParts();
                for ( size_t i = 0, nCount = xRangeList->size(); i < nCount; i++ )
                {
                    //! nExtFlags ???
                    ScRange const & rRange = (*xRangeList)[i];
                    PostPaint( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
                                rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
                                nParts );
                }
            }

            if ( pPaint->GetModified() )
                SetDocumentModified();
        }
    }
    else
    {
        OSL_FAIL("UnlockPaint without LockPaint");
    }
}

void ScDocShell::LockDocument_Impl(sal_uInt16 nNew)
{
    if (!m_nDocumentLock)
    {
        ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer();
        if (pDrawLayer)
            pDrawLayer->setLock(true);
    }
    m_nDocumentLock = nNew;
}

void ScDocShell::UnlockDocument_Impl(sal_uInt16 nNew)
{
    m_nDocumentLock = nNew;
    if (!m_nDocumentLock)
    {
        ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer();
        if (pDrawLayer)
            pDrawLayer->setLock(false);
    }
}

void ScDocShell::SetLockCount(sal_uInt16 nNew)
{
    if (nNew)                   // set
    {
        if ( !m_pPaintLockData )
            m_pPaintLockData.reset( new ScPaintLockData );
        m_pPaintLockData->SetDocLevel(nNew-1);
        LockDocument_Impl(nNew);
    }
    else if (m_pPaintLockData)    // delete
    {
        m_pPaintLockData->SetDocLevel(0);  // at unlock, execute immediately
        UnlockPaint_Impl(true);                 // now
        UnlockDocument_Impl(0);
    }
}

void ScDocShell::LockPaint()
{
    LockPaint_Impl(false);
}

void ScDocShell::UnlockPaint()
{
    UnlockPaint_Impl(false);
}

void ScDocShell::LockDocument()
{
    LockPaint_Impl(true);
    LockDocument_Impl(m_nDocumentLock + 1);
}

void ScDocShell::UnlockDocument()
{
    if (m_nDocumentLock)
    {
        UnlockPaint_Impl(true);
        UnlockDocument_Impl(m_nDocumentLock - 1);
    }
    else
    {
        OSL_FAIL("UnlockDocument without LockDocument");
    }
}

void ScDocShell::SetInplace( bool bInplace )
{
    if (m_bIsInplace != bInplace)
    {
        m_bIsInplace = bInplace;
        CalcOutputFactor();
    }
}

void ScDocShell::CalcOutputFactor()
{
    if (m_bIsInplace)
    {
        m_nPrtToScreenFactor = 1.0;           // otherwise it does not match the inactive display
        return;
    }

    bool bTextWysiwyg = ScModule::get()->GetInputOptions().GetTextWysiwyg();
    if (bTextWysiwyg)
    {
        m_nPrtToScreenFactor = 1.0;
        return;
    }

    OUString aTestString(
            u"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789"_ustr);
    tools::Long nPrinterWidth = 0;
    const ScPatternAttr& rPattern(m_pDocument->getCellAttributeHelper().getDefaultCellAttribute());

    vcl::Font aDefFont;
    OutputDevice* pRefDev = GetRefDevice();
    MapMode aOldMode = pRefDev->GetMapMode();
    vcl::Font aOldFont = pRefDev->GetFont();

    pRefDev->SetMapMode(MapMode(MapUnit::MapPixel));
    rPattern.fillFontOnly(aDefFont, pRefDev); // font color doesn't matter here
    pRefDev->SetFont(aDefFont);
    nPrinterWidth = pRefDev->PixelToLogic(Size(pRefDev->GetTextWidth(aTestString), 0), MapMode(MapUnit::Map100thMM)).Width();
    pRefDev->SetFont(aOldFont);
    pRefDev->SetMapMode(aOldMode);

    ScopedVclPtrInstance< VirtualDevice > pVirtWindow( *Application::GetDefaultDevice() );
    pVirtWindow->SetMapMode(MapMode(MapUnit::MapPixel));
    rPattern.fillFontOnly(aDefFont, pVirtWindow); // font color doesn't matter here
    pVirtWindow->SetFont(aDefFont);
    double nWindowWidth = pVirtWindow->GetTextWidth(aTestString) / ScGlobal::nScreenPPTX;
    nWindowWidth = o3tl::convert(nWindowWidth, o3tl::Length::twip, o3tl::Length::mm100);

    if (nPrinterWidth && nWindowWidth)
        m_nPrtToScreenFactor = nPrinterWidth / nWindowWidth;
    else
    {
        OSL_FAIL("GetTextSize returns 0 ??");
        m_nPrtToScreenFactor = 1.0;
    }
}

void ScDocShell::InitOptions(bool bForLoading)      // called from InitNew and Load
{
    //  Settings from the SpellCheckCfg get into Doc- and ViewOptions

    LanguageType nDefLang, nCjkLang, nCtlLang;
    ScModule::GetSpellSettings( nDefLang, nCjkLang, nCtlLang );
    ScModule* pScMod = ScModule::get();

    ScDocOptions  aDocOpt  = pScMod->GetDocOptions();
    ScFormulaOptions aFormulaOpt = pScMod->GetFormulaOptions();
    ScViewOptions aViewOpt = pScMod->GetViewOptions();

    if (!comphelper::IsFuzzing())
    {
        // two-digit year entry from Tools->Options->General
        aDocOpt.SetYear2000(officecfg::Office::Common::DateFormat::TwoDigitYear::get());
    }

    if (bForLoading)
    {
        // #i112123# No style:decimal-places attribute means automatic decimals, not the configured default,
        // so it must not be taken from the global options.
        // Calculation settings are handled separately in ScXMLBodyContext::EndElement.
        aDocOpt.SetStdPrecision( SvNumberFormatter::UNLIMITED_PRECISION );

        // fdo#78294 The default null-date if
        // <table:null-date table:date-value='...' />
        // is absent is 1899-12-30 regardless what the configuration is set to.
        // Import filters may override this value.
        aDocOpt.SetDate( 30, 12, 1899);
    }

    m_pDocument->SetDocOptions( aDocOpt );
    m_pDocument->SetViewOptions( aViewOpt );
    SetFormulaOptions( aFormulaOpt, bForLoading );

    //  print options are now set directly before the printing

    m_pDocument->SetLanguage( nDefLang, nCjkLang, nCtlLang );
}

Printer* ScDocShell::GetDocumentPrinter()       // for OLE
{
    return m_pDocument->GetPrinter();
}

SfxPrinter* ScDocShell::GetPrinter(bool bCreateIfNotExist)
{
    return m_pDocument->GetPrinter(bCreateIfNotExist);
}

void ScDocShell::UpdateFontList()
{
    // pImpl->pFontList = new FontList( GetPrinter(), Application::GetDefaultDevice() );
    m_pImpl->pFontList.reset(new FontList(GetRefDevice(), nullptr));
    SvxFontListItem aFontListItem( m_pImpl->pFontList.get(), SID_ATTR_CHAR_FONTLIST );
    PutItem( aFontListItem );

    CalcOutputFactor();
}

OutputDevice* ScDocShell::GetRefDevice()
{
    return m_pDocument->GetRefDevice();
}

sal_uInt16 ScDocShell::SetPrinter( VclPtr<SfxPrinter> const & pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
{
    SfxPrinter *pOld = m_pDocument->GetPrinter( false );
    if ( pOld && pOld->IsPrinting() )
        return SFX_PRINTERROR_BUSY;

    if (nDiffFlags & SfxPrinterChangeFlags::PRINTER)
    {
        if ( m_pDocument->GetPrinter() != pNewPrinter )
        {
            m_pDocument->SetPrinter( pNewPrinter );
            m_pDocument->SetPrintOptions();

            // MT: Use UpdateFontList: Will use Printer fonts only if needed!
            /*
            delete pImpl->pFontList;
            pImpl->pFontList = new FontList( pNewPrinter, Application::GetDefaultDevice() );
            SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST );
            PutItem( aFontListItem );

            CalcOutputFactor();
            */

            ScModule* pScMod = ScModule::get();
            if (pScMod->GetInputOptions().GetTextWysiwyg())
                UpdateFontList();

            SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this );
            while (pFrame)
            {
                SfxViewShell* pSh = pFrame->GetViewShell();
                if (ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(pSh))
                {
                    ScInputHandler* pInputHdl = pScMod->GetInputHdl(pViewSh);
                    if (pInputHdl)
                        pInputHdl->UpdateRefDevice();
                }
                pFrame = SfxViewFrame::GetNext( *pFrame, this );
            }
        }
    }
    else if (nDiffFlags & SfxPrinterChangeFlags::JOBSETUP)
    {
        SfxPrinter* pOldPrinter = m_pDocument->GetPrinter();
        if (pOldPrinter)
        {
            pOldPrinter->SetJobSetup( pNewPrinter->GetJobSetup() );

            //  #i6706# Call SetPrinter with the old printer again, so the drawing layer
            //  RefDevice is set (calling ReformatAllTextObjects and rebuilding charts),
            //  because the JobSetup (printer device settings) may affect text layout.
            m_pDocument->SetPrinter( pOldPrinter );
            CalcOutputFactor();                         // also with the new settings
        }
    }

    if (nDiffFlags & SfxPrinterChangeFlags::OPTIONS)
    {
        m_pDocument->SetPrintOptions();        //! from new printer ???
    }

    if (nDiffFlags & (SfxPrinterChangeFlags::CHG_ORIENTATION | SfxPrinterChangeFlags::CHG_SIZE))
    {
        OUString aStyle = m_pDocument->GetPageStyle( GetCurTab() );
        ScStyleSheetPool* pStPl = m_pDocument->GetStyleSheetPool();
        SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(pStPl->Find(aStyle, SfxStyleFamily::Page));
        if (pStyleSheet)
        {
            SfxItemSet& rSet = pStyleSheet->GetItemSet();

            if (nDiffFlags & SfxPrinterChangeFlags::CHG_ORIENTATION)
            {
                const SvxPageItem& rOldItem = rSet.Get(ATTR_PAGE);
                bool bWasLand = rOldItem.IsLandscape();
                bool bNewLand = ( pNewPrinter->GetOrientation() == Orientation::Landscape );
                if (bNewLand != bWasLand)
                {
                    SvxPageItem aNewItem( rOldItem );
                    aNewItem.SetLandscape( bNewLand );
                    rSet.Put( aNewItem );

                    // flip size
                    Size aOldSize = rSet.Get(ATTR_PAGE_SIZE).GetSize();
                    // coverity[swapped_arguments : FALSE] - this is in the correct order
                    Size aNewSize(aOldSize.Height(),aOldSize.Width());
                    SvxSizeItem aNewSItem(ATTR_PAGE_SIZE,aNewSize);
                    rSet.Put( aNewSItem );
                }
            }
            if (nDiffFlags & SfxPrinterChangeFlags::CHG_SIZE)
            {
                SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetPaperSize(pNewPrinter) );
                rSet.Put( aPaperSizeItem );
            }
        }
    }

    PostPaint(0,0,0,m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB,PaintPartFlags::All);

    return 0;
}

ScChangeAction* ScDocShell::GetChangeAction( const ScAddress& rPos )
{
    ScChangeTrack* pTrack = GetDocument().GetChangeTrack();
    if (!pTrack)
        return nullptr;

    SCTAB nTab = rPos.Tab();

    const ScChangeAction* pFound = nullptr;
    const ScChangeAction* pAction = pTrack->GetFirst();
    while (pAction)
    {
        ScChangeActionType eType = pAction->GetType();
        //! ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc )...
        if ( pAction->IsVisible() && eType != SC_CAT_DELETE_TABS )
        {
            const ScBigRange& rBig = pAction->GetBigRange();
            if ( rBig.aStart.Tab() == nTab )
            {
                ScRange aRange = rBig.MakeRange( GetDocument() );

                if ( eType == SC_CAT_DELETE_ROWS )
                    aRange.aEnd.SetRow( aRange.aStart.Row() );
                else if ( eType == SC_CAT_DELETE_COLS )
                    aRange.aEnd.SetCol( aRange.aStart.Col() );

                if ( aRange.Contains( rPos ) )
                {
                    pFound = pAction;       // the last one wins
                }
            }
            if ( pAction->GetType() == SC_CAT_MOVE )
            {
                ScRange aRange =
                    static_cast<const ScChangeActionMove*>(pAction)->
                    GetFromRange().MakeRange( GetDocument() );
                if ( aRange.Contains( rPos ) )
                {
                    pFound = pAction;
                }
            }
        }
        pAction = pAction->GetNext();
    }

    return const_cast<ScChangeAction*>(pFound);
}

void ScDocShell::SetChangeComment( ScChangeAction* pAction, const OUString& rComment )
{
    if (!pAction)
        return;

    pAction->SetComment( rComment );
    //! Undo ???
    SetDocumentModified();

    //  Dialog-Notify
    ScChangeTrack* pTrack = GetDocument().GetChangeTrack();
    if (pTrack)
    {
        sal_uLong nNumber = pAction->GetActionNumber();
        pTrack->NotifyModified( ScChangeTrackMsgType::Change, nNumber, nNumber );
    }
}

void ScDocShell::ExecuteChangeCommentDialog( ScChangeAction* pAction, weld::Window* pParent, bool bPrevNext)
{
    if (!pAction) return;           // without action is nothing...

    OUString aComment = pAction->GetComment();
    OUString aAuthor = pAction->GetUser();

    DateTime aDT = pAction->GetDateTime();
    OUString aDate = ScGlobal::getLocaleData().getDate( aDT ) + " " +
        ScGlobal::getLocaleData().getTime( aDT, false );

    SfxItemSetFixed<SID_ATTR_POSTIT_AUTHOR, SID_ATTR_POSTIT_TEXT> aSet( GetPool() );

    aSet.Put( SvxPostItTextItem  ( aComment, SID_ATTR_POSTIT_TEXT ) );
    aSet.Put( SvxPostItAuthorItem( aAuthor,  SID_ATTR_POSTIT_AUTHOR ) );
    aSet.Put( SvxPostItDateItem  ( aDate,    SID_ATTR_POSTIT_DATE ) );

    std::unique_ptr<ScRedComDialog> pDlg(new ScRedComDialog( pParent, aSet,this,pAction,bPrevNext));

    pDlg->Execute();
}

void ScDocShell::CompareDocument( ScDocument& rOtherDoc )
{
    ScChangeTrack* pTrack = m_pDocument->GetChangeTrack();
    if ( pTrack && pTrack->GetFirst() )
    {
        //! there are changes -> inquiry if needs to be deleted
    }

    m_pDocument->EndChangeTracking();
    m_pDocument->StartChangeTracking();

    OUString aOldUser;
    pTrack = m_pDocument->GetChangeTrack();
    if ( pTrack )
    {
        aOldUser = pTrack->GetUser();

        //  check if comparing to same document

        OUString aThisFile;
        const SfxMedium* pThisMed = GetMedium();
        if (pThisMed)
            aThisFile = pThisMed->GetName();
        OUString aOtherFile;
        ScDocShell* pOtherSh = rOtherDoc.GetDocumentShell();
        if (pOtherSh)
        {
            const SfxMedium* pOtherMed = pOtherSh->GetMedium();
            if (pOtherMed)
                aOtherFile = pOtherMed->GetName();
        }
        bool bSameDoc = ( aThisFile == aOtherFile && !aThisFile.isEmpty() );
        if ( !bSameDoc )
        {
            //  create change actions from comparing with the name of the user
            //  who last saved the document
            //  (only if comparing different documents)

            using namespace ::com::sun::star;
            uno::Reference<document::XDocumentProperties> xDocProps(
                GetModel()->getDocumentProperties());
            OSL_ENSURE(xDocProps.is(), "no DocumentProperties");
            OUString aDocUser = xDocProps->getModifiedBy();

            if ( !aDocUser.isEmpty() )
                pTrack->SetUser( aDocUser );
        }
    }

    m_pDocument->CompareDocument( rOtherDoc );

    pTrack = m_pDocument->GetChangeTrack();
    if ( pTrack )
        pTrack->SetUser( aOldUser );

    PostPaintGridAll();
    SetDocumentModified();
}

//              Merge (combine documents)

static bool lcl_Equal( const ScChangeAction* pA, const ScChangeAction* pB, bool bIgnore100Sec )
{
    return pA && pB &&
        pA->GetActionNumber() == pB->GetActionNumber() &&
        pA->GetType()         == pB->GetType() &&
        pA->GetUser()         == pB->GetUser() &&
        (bIgnore100Sec ?
         pA->GetDateTimeUTC().IsEqualIgnoreNanoSec( pB->GetDateTimeUTC() ) :
         pA->GetDateTimeUTC() == pB->GetDateTimeUTC());
    //  don't compare state if an old change has been accepted
}

static bool lcl_FindAction( ScDocument& rDoc, const ScChangeAction* pAction, ScDocument& rSearchDoc, const ScChangeAction* pFirstSearchAction, const ScChangeAction* pLastSearchAction, bool bIgnore100Sec )
{
    if ( !pAction || !pFirstSearchAction || !pLastSearchAction )
    {
        return false;
    }

    sal_uLong nLastSearchAction = pLastSearchAction->GetActionNumber();
    const ScChangeAction* pA = pFirstSearchAction;
    while ( pA && pA->GetActionNumber() <= nLastSearchAction )
    {
        if ( pAction->GetType() == pA->GetType() &&
             pAction->GetUser() == pA->GetUser() &&
             (bIgnore100Sec ?
                pAction->GetDateTimeUTC().IsEqualIgnoreNanoSec( pA->GetDateTimeUTC() ) :
                pAction->GetDateTimeUTC() == pA->GetDateTimeUTC() ) &&
             pAction->GetBigRange() == pA->GetBigRange() )
        {
            OUString aActionDesc = pAction->GetDescription(rDoc, true);
            OUString aADesc = pA->GetDescription(rSearchDoc, true);
            if (aActionDesc == aADesc)
            {
                OSL_FAIL( "lcl_FindAction(): found equal action!" );
                return true;
            }
        }
        pA = pA->GetNext();
    }

    return false;
}

void ScDocShell::MergeDocument( ScDocument& rOtherDoc, bool bShared, bool bCheckDuplicates, sal_uLong nOffset, ScChangeActionMergeMap* pMergeMap, bool bInverseMap )
{
    ScTabViewShell* pViewSh = GetBestViewShell( false );    //! functions to the DocShell
    if (!pViewSh)
        return;

    ScChangeTrack* pSourceTrack = rOtherDoc.GetChangeTrack();
    if (!pSourceTrack)
        return;             //! nothing to do - error notification?

    ScChangeTrack* pThisTrack = m_pDocument->GetChangeTrack();
    if ( !pThisTrack )
    {   // turn on
        m_pDocument->StartChangeTracking();
        pThisTrack = m_pDocument->GetChangeTrack();
        OSL_ENSURE(pThisTrack,"ChangeTracking not enabled?");
        if ( !bShared )
        {
            // turn on visual RedLining
            ScChangeViewSettings aChangeViewSet;
            aChangeViewSet.SetShowChanges(true);
            m_pDocument->SetChangeViewSettings(aChangeViewSet);
        }
    }

    // include Nano seconds in compare?
    bool bIgnore100Sec = !pSourceTrack->IsTimeNanoSeconds() ||
            !pThisTrack->IsTimeNanoSeconds();

    //  find common initial position
    sal_uLong nFirstNewNumber = 0;
    const ScChangeAction* pSourceAction = pSourceTrack->GetFirst();
    const ScChangeAction* pThisAction = pThisTrack->GetFirst();
    // skip identical actions
    while ( lcl_Equal( pSourceAction, pThisAction, bIgnore100Sec ) )
    {
        nFirstNewNumber = pSourceAction->GetActionNumber() + 1;
        pSourceAction = pSourceAction->GetNext();
        pThisAction = pThisAction->GetNext();
    }
    //  pSourceAction and pThisAction now point to the first "own" actions
    //  The common actions before don't interest at all

    //! Inquiry if the documents where equal before the change tracking !!!

    const ScChangeAction* pFirstMergeAction = pSourceAction;
    const ScChangeAction* pFirstSearchAction = pThisAction;

    // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
    const ScChangeAction* pLastSearchAction = pThisTrack->GetLast();

    //  Create MergeChangeData from the following actions
    sal_uLong nNewActionCount = 0;
    const ScChangeAction* pCount = pSourceAction;
    while ( pCount )
    {
        if ( bShared || !ScChangeTrack::MergeIgnore( *pCount, nFirstNewNumber ) )
            ++nNewActionCount;
        pCount = pCount->GetNext();
    }
    if (!nNewActionCount)
        return;             //! nothing to do - error notification?
                            //  from here on no return

    ScProgress aProgress( this, u"..."_ustr, nNewActionCount, true );

    sal_uLong nLastMergeAction = pSourceTrack->GetLast()->GetActionNumber();
    // UpdateReference-Undo, valid references for the last common state
    pSourceTrack->MergePrepare( pFirstMergeAction, bShared );

    //  adjust MergeChangeData to all yet following actions in this document
    //  -> references valid for this document
    while ( pThisAction )
    {
        // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
        if ( !bShared || !ScChangeTrack::MergeIgnore( *pThisAction, nFirstNewNumber ) )
        {
            ScChangeActionType eType = pThisAction->GetType();
            switch ( eType )
            {
                case SC_CAT_INSERT_COLS :
                case SC_CAT_INSERT_ROWS :
                case SC_CAT_INSERT_TABS :
                    pSourceTrack->AppendInsert( pThisAction->GetBigRange().MakeRange( GetDocument() ) );
                break;
                case SC_CAT_DELETE_COLS :
                case SC_CAT_DELETE_ROWS :
                case SC_CAT_DELETE_TABS :
                {
                    const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pThisAction);
                    if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() )
                    {   // deleted table contains deleted cols, which are not
                        sal_uLong nStart, nEnd;
                        pSourceTrack->AppendDeleteRange(
                            pDel->GetOverAllRange().MakeRange( GetDocument() ), nullptr, nStart, nEnd );
                    }
                }
                break;
                case SC_CAT_MOVE :
                {
                    const ScChangeActionMove* pMove = static_cast<const ScChangeActionMove*>(pThisAction);
                    pSourceTrack->AppendMove( pMove->GetFromRange().MakeRange( GetDocument() ),
                        pMove->GetBigRange().MakeRange( GetDocument() ), nullptr );
                }
                break;
                default:
                {
                    // added to avoid warnings
                }
            }
        }
        pThisAction = pThisAction->GetNext();
    }

    LockPaint();    // #i73877# no repainting after each action

    //  take over MergeChangeData into the current document
    bool bHasRejected = false;
    OUString aOldUser = pThisTrack->GetUser();
    pThisTrack->SetUseFixDateTime( true );
    ScMarkData& rMarkData = pViewSh->GetViewData().GetMarkData();
    ScMarkData aOldMarkData( rMarkData );
    pSourceAction = pFirstMergeAction;
    while ( pSourceAction && pSourceAction->GetActionNumber() <= nLastMergeAction )
    {
        bool bMergeAction = false;
        if ( bShared )
        {
            if ( !bCheckDuplicates || !lcl_FindAction( rOtherDoc, pSourceAction, *m_pDocument, pFirstSearchAction, pLastSearchAction, bIgnore100Sec ) )
            {
                bMergeAction = true;
            }
        }
        else
        {
            if ( !ScChangeTrack::MergeIgnore( *pSourceAction, nFirstNewNumber ) )
            {
                bMergeAction = true;
            }
        }

        if ( bMergeAction )
        {
            ScChangeActionType eSourceType = pSourceAction->GetType();
            if ( !bShared && pSourceAction->IsDeletedIn() )
            {
                //! does it need to be determined yet if really deleted in
                //! _this_ document?

                //  lies in a range, which was deleted in this document
                //  -> is omitted
                //! ??? revert deletion action ???
                //! ??? save action somewhere else  ???
#if OSL_DEBUG_LEVEL > 0
                OUString aValue;
                if ( eSourceType == SC_CAT_CONTENT )
                    aValue = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewString( *m_pDocument );
                SAL_WARN( "sc", aValue << " omitted");
#endif
            }
            else
            {
                //! Take over date/author/comment of the source action!

                pThisTrack->SetUser( pSourceAction->GetUser() );
                pThisTrack->SetFixDateTimeUTC( pSourceAction->GetDateTimeUTC() );
                sal_uLong nOldActionMax = pThisTrack->GetActionMax();

                bool bExecute = true;
                sal_uLong nReject = pSourceAction->GetRejectAction();
                if ( nReject )
                {
                    if ( bShared )
                    {
                        if ( nReject >= nFirstNewNumber )
                        {
                            nReject += nOffset;
                        }
                        ScChangeAction* pOldAction = pThisTrack->GetAction( nReject );
                        if ( pOldAction && pOldAction->IsVirgin() )
                        {
                            pThisTrack->Reject( pOldAction );
                            bHasRejected = true;
                            bExecute = false;
                        }
                    }
                    else
                    {
                        //  decline old action (of the common ones)
                        ScChangeAction* pOldAction = pThisTrack->GetAction( nReject );
                        if (pOldAction && pOldAction->GetState() == SC_CAS_VIRGIN)
                        {
                            //! what happens at actions, which were accepted in this document???
                            //! error notification or what???
                            //! or execute reject change normally

                            pThisTrack->Reject(pOldAction);
                            bHasRejected = true;                // for Paint
                        }
                        bExecute = false;
                    }
                }

                if ( bExecute )
                {
                    //  execute normally
                    ScRange aSourceRange = pSourceAction->GetBigRange().MakeRange( GetDocument() );
                    rMarkData.SelectOneTable( aSourceRange.aStart.Tab() );
                    switch ( eSourceType )
                    {
                        case SC_CAT_CONTENT:
                        {
                            //! Test if it was at the very bottom in the document, then automatic
                            //! row insert ???

                            OSL_ENSURE( aSourceRange.aStart == aSourceRange.aEnd, "huch?" );
                            ScAddress aPos = aSourceRange.aStart;
                            OUString aValue = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewString( *m_pDocument );
                            ScMatrixMode eMatrix = ScMatrixMode::NONE;
                            const ScCellValue& rCell = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewCell();
                            if (rCell.getType() == CELLTYPE_FORMULA)
                                eMatrix = rCell.getFormula()->GetMatrixFlag();
                            switch ( eMatrix )
                            {
                                case ScMatrixMode::NONE :
                                    pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue );
                                break;
                                case ScMatrixMode::Formula :
                                {
                                    SCCOL nCols;
                                    SCROW nRows;
                                    rCell.getFormula()->GetMatColsRows(nCols, nRows);
                                    aSourceRange.aEnd.SetCol( aPos.Col() + nCols - 1 );
                                    aSourceRange.aEnd.SetRow( aPos.Row() + nRows - 1 );
                                    aValue = aValue.copy(1, aValue.getLength()-2); // remove the 1st and last characters.
                                    GetDocFunc().EnterMatrix( aSourceRange,
                                        nullptr, nullptr, aValue, falsefalse,
                                        OUString(), formula::FormulaGrammar::GRAM_DEFAULT );
                                }
                                break;
                                case ScMatrixMode::Reference :     // do nothing
                                break;
                            }
                        }
                        break;
                        case SC_CAT_INSERT_TABS :
                        {
                            OUString aName;
                            m_pDocument->CreateValidTabName( aName );
                            (void)GetDocFunc().InsertTable( aSourceRange.aStart.Tab(), aName, truefalse );
                        }
                        break;
                        case SC_CAT_INSERT_ROWS:
                            (void)GetDocFunc().InsertCells( aSourceRange, nullptr, INS_INSROWS_BEFORE, truefalse );
                        break;
                        case SC_CAT_INSERT_COLS:
                            (void)GetDocFunc().InsertCells( aSourceRange, nullptr, INS_INSCOLS_BEFORE, truefalse );
                        break;
                        case SC_CAT_DELETE_TABS :
                            (void)GetDocFunc().DeleteTable( aSourceRange.aStart.Tab(), true );
                        break;
                        case SC_CAT_DELETE_ROWS:
                        {
                            const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pSourceAction);
                            if ( pDel->IsTopDelete() )
                            {
                                aSourceRange = pDel->GetOverAllRange().MakeRange( GetDocument() );
                                (void)GetDocFunc().DeleteCells( aSourceRange, nullptr, DelCellCmd::Rows, false );

                                // #i101099# [Collaboration] Changes are not correctly shown
                                if ( bShared )
                                {
                                    ScChangeAction* pAct = pThisTrack->GetLast();
                                    if ( pAct && pAct->GetType() == eSourceType && pAct->IsDeletedIn() && !pSourceAction->IsDeletedIn() )
                                    {
                                        pAct->RemoveAllDeletedIn();
                                    }
                                }
                            }
                        }
                        break;
                        case SC_CAT_DELETE_COLS:
                        {
                            const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pSourceAction);
                            if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() )
                            {   // deleted table contains deleted cols, which are not
                                aSourceRange = pDel->GetOverAllRange().MakeRange( GetDocument() );
                                (void)GetDocFunc().DeleteCells( aSourceRange, nullptr, DelCellCmd::Cols, false );
                            }
                        }
                        break;
                        case SC_CAT_MOVE :
                        {
                            const ScChangeActionMove* pMove = static_cast<const ScChangeActionMove*>(pSourceAction);
                            ScRange aFromRange( pMove->GetFromRange().MakeRange( GetDocument() ) );
                            (void)GetDocFunc().MoveBlock( aFromRange,
                                aSourceRange.aStart, truetruefalsefalse );
                        }
                        break;
                        default:
                        {
                            // added to avoid warnings
                        }
                    }
                }
                const OUString& rComment = pSourceAction->GetComment();
                if ( !rComment.isEmpty() )
                {
                    ScChangeAction* pAct = pThisTrack->GetLast();
                    if ( pAct && pAct->GetActionNumber() > nOldActionMax )
                        pAct->SetComment( rComment );
                    else
                        OSL_FAIL( "MergeDocument: what to do with the comment?!?" );
                }

                // adjust references
                pSourceTrack->MergeOwn( const_cast<ScChangeAction*>(pSourceAction), nFirstNewNumber, bShared );

                // merge action state
                if ( bShared && !pSourceAction->IsRejected() )
                {
                    ScChangeAction* pAct = pThisTrack->GetLast();
                    if ( pAct && pAct->GetActionNumber() > nOldActionMax )
                    {
                        ScChangeTrack::MergeActionState( pAct, pSourceAction );
                    }
                }

                // fill merge map
                if ( bShared && pMergeMap )
                {
                    ScChangeAction* pAct = pThisTrack->GetLast();
                    if ( pAct && pAct->GetActionNumber() > nOldActionMax )
                    {
                        sal_uLong nActionMax = pAct->GetActionNumber();
                        sal_uLong nActionCount = nActionMax - nOldActionMax;
                        sal_uLong nAction = nActionMax - nActionCount + 1;
                        sal_uLong nSourceAction = pSourceAction->GetActionNumber() - nActionCount + 1;
                        while ( nAction <= nActionMax )
                        {
                            if ( bInverseMap )
                            {
                                (*pMergeMap)[ nAction++ ] = nSourceAction++;
                            }
                            else
                            {
                                (*pMergeMap)[ nSourceAction++ ] = nAction++;
                            }
                        }
                    }
                }
            }
            aProgress.SetStateCountDown( --nNewActionCount );
        }
        pSourceAction = pSourceAction->GetNext();
    }

    rMarkData = std::move(aOldMarkData);
    pThisTrack->SetUser(aOldUser);
    pThisTrack->SetUseFixDateTime( false );

    pSourceTrack->Clear();      //! this one is bungled now

    if (bHasRejected)
        PostPaintGridAll();         // Reject() doesn't paint itself

    UnlockPaint();
}

bool ScDocShell::MergeSharedDocument( ScDocShell* pSharedDocShell )
{
    if ( !pSharedDocShell )
    {
        return false;
    }

    ScChangeTrack* pThisTrack = m_pDocument->GetChangeTrack();
    if ( !pThisTrack )
    {
        return false;
    }

    ScDocument& rSharedDoc = pSharedDocShell->GetDocument();
    ScChangeTrack* pSharedTrack = rSharedDoc.GetChangeTrack();
    if ( !pSharedTrack )
    {
        return false;
    }

    // reset show changes
    ScChangeViewSettings aChangeViewSet;
    aChangeViewSet.SetShowChanges( false );
    m_pDocument->SetChangeViewSettings( aChangeViewSet );

    // find first merge action in this document
    bool bIgnore100Sec = !pThisTrack->IsTimeNanoSeconds() || !pSharedTrack->IsTimeNanoSeconds();
    ScChangeAction* pThisAction = pThisTrack->GetFirst();
    ScChangeAction* pSharedAction = pSharedTrack->GetFirst();
    while ( lcl_Equal( pThisAction, pSharedAction, bIgnore100Sec ) )
    {
        pThisAction = pThisAction->GetNext();
        pSharedAction = pSharedAction->GetNext();
    }

    if ( pSharedAction )
    {
        if ( pThisAction )
        {
            // merge own changes into shared document
            sal_uLong nActStartShared = pSharedAction->GetActionNumber();
            sal_uLong nActEndShared = pSharedTrack->GetActionMax();
            std::optional<ScDocument> pTmpDoc(std::in_place);
            for ( sal_Int32 nIndex = 0; nIndex < m_pDocument->GetTableCount(); ++nIndex )
            {
                OUString sTabName;
                pTmpDoc->CreateValidTabName( sTabName );
                pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName );
            }
            m_pDocument->GetChangeTrack()->Clone( *pTmpDoc );
            ScChangeActionMergeMap aOwnInverseMergeMap;
            pSharedDocShell->MergeDocument( *pTmpDoc, truetrue, 0, &aOwnInverseMergeMap, true );
            pTmpDoc.reset();
            sal_uLong nActStartOwn = nActEndShared + 1;
            sal_uLong nActEndOwn = pSharedTrack->GetActionMax();

            // find conflicts
            ScConflictsList aConflictsList;
            ScConflictsFinder aFinder( pSharedTrack, nActStartShared, nActEndShared, nActStartOwn, nActEndOwn, aConflictsList );
            if ( aFinder.Find() )
            {
                ScConflictsListHelper::TransformConflictsList( aConflictsList, nullptr, &aOwnInverseMergeMap );
                if (ScViewData* pViewData = GetViewData())
                {
                    bool bLoop = true;
                    while ( bLoop )
                    {
                        bLoop = false;
                        weld::Window* pWin = GetActiveDialogParent();
                        ScConflictsDlg aDlg(pWin, *pViewData, rSharedDoc, aConflictsList);
                        if (aDlg.run() == RET_CANCEL)
                        {
                            std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pWin,
                                                                           VclMessageType::Question, VclButtonsType::YesNo,
                                                                           ScResId(STR_DOC_WILLNOTBESAVED)));
                            xQueryBox->set_default_response(RET_YES);
                            if (xQueryBox->run() == RET_YES)
                            {
                                return false;
                            }
                            else
                            {
                                bLoop = true;
                            }
                        }
                    }
                }
            }

            // undo own changes in shared document
            pSharedTrack->Undo( nActStartOwn, nActEndOwn );

            // clone change track for merging into own document
            pTmpDoc.emplace();
            for ( sal_Int32 nIndex = 0; nIndex < m_pDocument->GetTableCount(); ++nIndex )
            {
                OUString sTabName;
                pTmpDoc->CreateValidTabName( sTabName );
                pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName );
            }
            pThisTrack->Clone( *pTmpDoc );

            // undo own changes since last save in own document
            sal_uLong nStartShared = pThisAction->GetActionNumber();
            ScChangeAction* pAction = pThisTrack->GetLast();
            while ( pAction && pAction->GetActionNumber() >= nStartShared )
            {
                pThisTrack->Reject( pAction, true );
                pAction = pAction->GetPrev();
            }

            // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
            pThisTrack->Undo( nStartShared, pThisTrack->GetActionMax(), true );

            // merge shared changes into own document
            ScChangeActionMergeMap aSharedMergeMap;
            MergeDocument( rSharedDoc, truetrue, 0, &aSharedMergeMap );
            sal_uLong nEndShared = pThisTrack->GetActionMax();

            // resolve conflicts for shared non-content actions
            if ( !aConflictsList.empty() )
            {
                ScConflictsListHelper::TransformConflictsList( aConflictsList, &aSharedMergeMap, nullptr );
                ScConflictsResolver aResolver( pThisTrack, aConflictsList );
                pAction = pThisTrack->GetAction( nEndShared );
                while ( pAction && pAction->GetActionNumber() >= nStartShared )
                {
                    aResolver.HandleAction( pAction, true /*bIsSharedAction*/,
                        false /*bHandleContentAction*/, true /*bHandleNonContentAction*/ );
                    pAction = pAction->GetPrev();
                }
            }
            nEndShared = pThisTrack->GetActionMax();

            // only show changes from shared document
            aChangeViewSet.SetShowChanges( true );
            aChangeViewSet.SetShowAccepted( true );
            aChangeViewSet.SetHasActionRange();
            aChangeViewSet.SetTheActionRange( nStartShared, nEndShared );
            m_pDocument->SetChangeViewSettings( aChangeViewSet );

            // merge own changes back into own document
            sal_uLong nStartOwn = nEndShared + 1;
            ScChangeActionMergeMap aOwnMergeMap;
            MergeDocument( *pTmpDoc, truetrue, nEndShared - nStartShared + 1, &aOwnMergeMap );
            pTmpDoc.reset();
            sal_uLong nEndOwn = pThisTrack->GetActionMax();

            // resolve conflicts for shared content actions and own actions
            if ( !aConflictsList.empty() )
            {
                ScConflictsListHelper::TransformConflictsList( aConflictsList, nullptr, &aOwnMergeMap );
                ScConflictsResolver aResolver( pThisTrack, aConflictsList );
                pAction = pThisTrack->GetAction( nEndShared );
                while ( pAction && pAction->GetActionNumber() >= nStartShared )
                {
                    aResolver.HandleAction( pAction, true /*bIsSharedAction*/,
                        true /*bHandleContentAction*/, false /*bHandleNonContentAction*/ );
                    pAction = pAction->GetPrev();
                }

                pAction = pThisTrack->GetAction( nEndOwn );
                while ( pAction && pAction->GetActionNumber() >= nStartOwn )
                {
                    aResolver.HandleAction( pAction, false /*bIsSharedAction*/,
                        true /*bHandleContentAction*/, true /*bHandleNonContentAction*/ );
                    pAction = pAction->GetPrev();
                }
            }
        }
        else
        {
            // merge shared changes into own document
            sal_uLong nStartShared = pThisTrack->GetActionMax() + 1;
            MergeDocument( rSharedDoc, truetrue );
            sal_uLong nEndShared = pThisTrack->GetActionMax();

            // only show changes from shared document
            aChangeViewSet.SetShowChanges( true );
            aChangeViewSet.SetShowAccepted( true );
            aChangeViewSet.SetHasActionRange();
            aChangeViewSet.SetTheActionRange( nStartShared, nEndShared );
            m_pDocument->SetChangeViewSettings( aChangeViewSet );
        }

        // update view
        PostPaintExtras();
        PostPaintGridAll();

        std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
                                                      VclMessageType::Info, VclButtonsType::Ok,
                                                      ScResId(STR_DOC_UPDATED)));
        xInfoBox->run();
    }

    return ( pThisAction != nullptr );
}

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

Messung V0.5
C=93 H=96 G=94

¤ Dauer der Verarbeitung: 0.19 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.