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 17 kB image not shown  

Quelle  arealink.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 <sfx2/fcontnr.hxx>
#include <sfx2/linkmgr.hxx>
#include <utility>
#include <vcl/svapp.hxx>
#include <vcl/weld.hxx>
#include <unotools/charclass.hxx>
#include <osl/diagnose.h>

#include <arealink.hxx>

#include <tablink.hxx>
#include <document.hxx>
#include <docsh.hxx>
#include <rangenam.hxx>
#include <dbdata.hxx>
#include <undoblk.hxx>
#include <globstr.hrc>
#include <scresid.hxx>
#include <markdata.hxx>
#include <hints.hxx>
#include <filter.hxx>

#include <attrib.hxx>
#include <patattr.hxx>
#include <docpool.hxx>

#include <scabstdlg.hxx>
#include <clipparam.hxx>


ScAreaLink::ScAreaLink( ScDocShell& rShell, OUString aFile,
                        OUString aFilter, OUString aOpt,
                        OUString aArea, const ScRange& rDest,
                        sal_Int32 nRefreshDelaySeconds ) :
    ::sfx2::SvBaseLink(SfxLinkUpdateMode::ONCALL,SotClipboardFormatId::SIMPLE_FILE),
    ScRefreshTimer  ( nRefreshDelaySeconds ),
    m_rDocSh(rShell),
    aFileName       (std::move(aFile)),
    aFilterName     (std::move(aFilter)),
    aOptions        (std::move(aOpt)),
    aSourceArea     (std::move(aArea)),
    aDestArea       (rDest),
    bAddUndo        (true),
    bInCreate       (false),
    bDoInsert       (true)
{
    SetRefreshHandler( LINK( this, ScAreaLink, RefreshHdl ) );
    SetRefreshControl( &m_rDocSh.GetDocument().GetRefreshTimerControlAddress() );
}

ScAreaLink::~ScAreaLink()
{
    StopRefreshTimer();
}

void ScAreaLink::Edit(weld::Window* pParent, const Link<SvBaseLink&,void>& /* rEndEditHdl */ )
{
    //  use own dialog instead of SvBaseLink::Edit...
    ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();

    ScopedVclPtr<AbstractScLinkedAreaDlg> pDlg(pFact->CreateScLinkedAreaDlg(pParent));
    pDlg->InitFromOldLink( aFileName, aFilterName, aOptions, aSourceArea, GetRefreshDelaySeconds() );
    if ( pDlg->Execute() == RET_OK )
    {
        aOptions = pDlg->GetOptions();
        Refresh( pDlg->GetURL(), pDlg->GetFilter(),
                 pDlg->GetSource(), pDlg->GetRefreshDelaySeconds() );

        //  copy source data from members (set in Refresh) into link name for dialog
        OUString aNewLinkName;
        sfx2::MakeLnkName( aNewLinkName, nullptr, aFileName, aSourceArea, &aFilterName );
        SetName( aNewLinkName );
    }
}

::sfx2::SvBaseLink::UpdateResult ScAreaLink::DataChanged(
    const OUString&, const css::uno::Any& )
{
    //  Do not do anything at bInCreate so that update can be called to set
    //  the status in the LinkManager without changing the data in the document

    if (bInCreate)
        return SUCCESS;

    sfx2::LinkManager* pLinkManager=m_rDocSh.GetDocument().GetLinkManager();
    if (pLinkManager!=nullptr)
    {
        OUString aFile, aArea, aFilter;
        sfx2::LinkManager::GetDisplayNames(this, nullptr, &aFile, &aArea, &aFilter);

        //  the file dialog returns the filter name with the application prefix
        //  -> remove prefix
        ScDocumentLoader::RemoveAppPrefix( aFilter );

        // dialog doesn't set area, so keep old one
        if (aArea.isEmpty())
        {
            aArea = aSourceArea;

            // adjust in dialog:
            OUString aNewLinkName;
            OUString aTmp = aFilter;
            sfx2::MakeLnkName(aNewLinkName, nullptr, aFile, aArea, &aTmp);
            aFilter = aTmp;
            SetName( aNewLinkName );
        }

        tools::SvRef<sfx2::SvBaseLink> const xThis(this); // keep yourself alive
        Refresh( aFile, aFilter, aArea, GetRefreshDelaySeconds() );
    }

    return SUCCESS;
}

void ScAreaLink::Closed()
{
    // delete link: Undo

    ScDocument& rDoc = m_rDocSh.GetDocument();
    bool bUndo (rDoc.IsUndoEnabled());
    if (bAddUndo && bUndo)
    {
        m_rDocSh.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoRemoveAreaLink>( m_rDocSh,
                                                        aFileName, aFilterName, aOptions,
                                                        aSourceArea, aDestArea, GetRefreshDelaySeconds() ) );

        bAddUndo = false;   // only once
    }

    SCTAB nDestTab = aDestArea.aStart.Tab();
    rDoc.SetStreamValid(nDestTab, false);

    SvBaseLink::Closed();
}

void ScAreaLink::SetDestArea(const ScRange& rNew)
{
    aDestArea = rNew;           // for Undo
}

void ScAreaLink::SetSource(const OUString& rDoc, const OUString& rFlt, const OUString& rOpt,
                                const OUString& rArea)
{
    aFileName   = rDoc;
    aFilterName = rFlt;
    aOptions    = rOpt;
    aSourceArea = rArea;

    //  also update link name for dialog
    OUString aNewLinkName;
    sfx2::MakeLnkName( aNewLinkName, nullptr, aFileName, aSourceArea, &aFilterName );
    SetName( aNewLinkName );
}

bool ScAreaLink::IsEqual( std::u16string_view rFile, std::u16string_view rFilter, std::u16string_view rOpt,
                            std::u16string_view rSource, const ScRange& rDest ) const
{
    return aFileName == rFile && aFilterName == rFilter && aOptions == rOpt &&
            aSourceArea == rSource && aDestArea.aStart == rDest.aStart;
}

// find a range with name >rAreaName< in >rSrcDoc<, return it in >rRange<
bool ScAreaLink::FindExtRange( ScRange& rRange, const ScDocument& rSrcDoc, const OUString& rAreaName )
{
    bool bFound = false;
    OUString aUpperName = ScGlobal::getCharClass().uppercase(rAreaName);
    ScRangeName* pNames = rSrcDoc.GetRangeName();
    if (pNames)         // named ranges
    {
        const ScRangeData* p = pNames->findByUpperName(aUpperName);
        if (p && p->IsValidReference(rRange))
            bFound = true;
    }
    if (!bFound)        // database ranges
    {
        ScDBCollection* pDBColl = rSrcDoc.GetDBCollection();
        if (pDBColl)
        {
            const ScDBData* pDB = pDBColl->getNamedDBs().findByUpperName(aUpperName);
            if (pDB)
            {
                SCTAB nTab;
                SCCOL nCol1, nCol2;
                SCROW nRow1, nRow2;
                pDB->GetArea(nTab,nCol1,nRow1,nCol2,nRow2);
                rRange = ScRange( nCol1,nRow1,nTab, nCol2,nRow2,nTab );
                bFound = true;
            }
        }
    }
    if (!bFound)        // direct reference (range or cell)
    {
        ScAddress::Details aDetails(rSrcDoc.GetAddressConvention(), 0, 0);
        if ( rRange.ParseAny( rAreaName, rSrcDoc, aDetails ) & ScRefFlags::VALID )
            bFound = true;
    }
    return bFound;
}

//  execute:

bool ScAreaLink::Refresh( const OUString& rNewFile, const OUString& rNewFilter,
                            const OUString& rNewArea, sal_Int32 nNewRefreshDelaySeconds )
{
    //  load document - like TabLink

    if (rNewFile.isEmpty() || rNewFilter.isEmpty())
        return false;

    if (!m_rDocSh.GetEmbeddedObjectContainer().getUserAllowsLinkUpdate())
        return false;

    OUString aNewUrl( ScGlobal::GetAbsDocName( rNewFile, &m_rDocSh ) );
    bool bNewUrlName = (aNewUrl != aFileName);

    std::shared_ptr<const SfxFilter> pFilter = m_rDocSh.GetFactory().GetFilterContainer()->GetFilter4FilterName(rNewFilter);
    if (!pFilter)
        return false;

    ScDocument& rDoc = m_rDocSh.GetDocument();

    bool bUndo (rDoc.IsUndoEnabled());
    rDoc.SetInLinkUpdate( true );

    //  if new filter was selected, forget options
    if ( rNewFilter != aFilterName )
        aOptions.clear();

    SfxMedium* pMed = ScDocumentLoader::CreateMedium( aNewUrl, pFilter, aOptions);

    // aRef->DoClose() will be closed explicitly, but it is still more safe to use SfxObjectShellLock here
    rtl::Reference<ScDocShell> pSrcShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS);
    pSrcShell->DoLoad(pMed);

    ScDocument& rSrcDoc = pSrcShell->GetDocument();

    // options could have been set
    OUString aNewOpt = ScDocumentLoader::GetOptions(*pMed);
    if (aNewOpt.isEmpty())
        aNewOpt = aOptions;

    // correct source range name list for web query import
    OUString aTempArea;

    if( rNewFilter == ScDocShell::GetWebQueryFilterName() )
        aTempArea = ScFormatFilter::Get().GetHTMLRangeNameList( rSrcDoc, rNewArea );
    else
        aTempArea = rNewArea;

    // find total size of source area
    SCCOL nWidth = 0;
    SCROW nHeight = 0;
    ScRangeList aSourceRanges;

    if (rNewFilter == SC_TEXT_CSV_FILTER_NAME && aTempArea == "CSV_all")
    {
        // The dummy All range. All data, including top/left empty
        // rows/columns.
        aTempArea.clear();
        SCCOL nEndCol = 0;
        SCROW nEndRow = 0;
        if (rSrcDoc.GetCellArea( 0, nEndCol, nEndRow))
        {
            aSourceRanges.push_back( ScRange( 0,0,0, nEndCol, nEndRow, 0));
            nWidth = nEndCol + 1;
            nHeight = nEndRow + 2;
        }
    }

    if (!aTempArea.isEmpty())
    {
        sal_Int32 nIdx {0};
        do
        {
            ScRange aTokenRange;
            if( FindExtRange( aTokenRange, rSrcDoc, aTempArea.getToken( 0, ';', nIdx ) ) )
            {
                aSourceRanges.push_back( aTokenRange);
                // columns: find maximum
                nWidth = std::max( nWidth, static_cast<SCCOL>(aTokenRange.aEnd.Col() - aTokenRange.aStart.Col() + 1) );
                // rows: add row range + 1 empty row
                nHeight += aTokenRange.aEnd.Row() - aTokenRange.aStart.Row() + 2;
            }
        }
        while (nIdx>0);
    }
    // remove the last empty row
    if( nHeight > 0 )
        nHeight--;

    //  delete old data / copy new

    ScAddress aDestPos = aDestArea.aStart;
    SCTAB nDestTab = aDestPos.Tab();
    ScRange aOldRange = aDestArea;
    ScRange aNewRange = aDestArea;          // old range, if file not found or similar
    if (nWidth > 0 && nHeight > 0)
    {
        aNewRange.aEnd.SetCol( aNewRange.aStart.Col() + nWidth - 1 );
        aNewRange.aEnd.SetRow( aNewRange.aStart.Row() + nHeight - 1 );
    }

    //! check CanFitBlock only if bDoInsert is set?
    bool bCanDo = rDoc.ValidColRow( aNewRange.aEnd.Col(), aNewRange.aEnd.Row() ) &&
                  rDoc.CanFitBlock( aOldRange, aNewRange );
    if (bCanDo)
    {
        ScDocShellModificator aModificator( m_rDocSh );

        SCCOL nOldEndX = aOldRange.aEnd.Col();
        SCROW nOldEndY = aOldRange.aEnd.Row();
        SCCOL nNewEndX = aNewRange.aEnd.Col();
        SCROW nNewEndY = aNewRange.aEnd.Row();
        ScRange aMaxRange( aDestPos,
                    ScAddress(std::max(nOldEndX,nNewEndX), std::max(nOldEndY,nNewEndY), nDestTab) );

        //  initialise Undo

        ScDocumentUniquePtr pUndoDoc;
        if ( bAddUndo && bUndo )
        {
            pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
            if ( bDoInsert )
            {
                if ( nNewEndX != nOldEndX || nNewEndY != nOldEndY )             // range changed?
                {
                    pUndoDoc->InitUndo( rDoc, 0, rDoc.GetTableCount()-1 );
                    rDoc.CopyToDocument(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
                                        InsertDeleteFlags::FORMULA, false, *pUndoDoc);     // all formulas
                }
                else
                    pUndoDoc->InitUndo( rDoc, nDestTab, nDestTab );             // only destination table
                rDoc.CopyToDocument(aOldRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pUndoDoc);
            }
            else        // without insertion
            {
                pUndoDoc->InitUndo( rDoc, nDestTab, nDestTab );             // only destination table
                rDoc.CopyToDocument(aMaxRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pUndoDoc);
            }
        }

        //  insert / delete cells
        //  DeleteAreaTab also deletes MERGE_FLAG attributes

        if (bDoInsert)
            rDoc.FitBlock( aOldRange, aNewRange );         // incl. deletion
        else
            rDoc.DeleteAreaTab( aMaxRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );

        //  copy data

        if (nWidth > 0 && nHeight > 0)
        {
            ScDocument aClipDoc( SCDOCMODE_CLIP );
            ScRange aNewTokenRange( aNewRange.aStart );
            for (size_t nRange = 0; nRange < aSourceRanges.size(); ++nRange)
            {
                ScRange const & rTokenRange( aSourceRanges[nRange]);
                SCTAB nSrcTab = rTokenRange.aStart.Tab();
                ScMarkData aSourceMark(rSrcDoc.GetSheetLimits());
                aSourceMark.SelectOneTable( nSrcTab );      // selecting for CopyToClip
                aSourceMark.SetMarkArea( rTokenRange );

                ScClipParam aClipParam(rTokenRange, false);
                rSrcDoc.CopyToClip(aClipParam, &aClipDoc, &aSourceMark, falsefalse);

                if ( aClipDoc.HasAttrib( 0,0,nSrcTab, rDoc.MaxCol(),rDoc.MaxRow(),nSrcTab,
                            HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
                {
                    //! ResetAttrib at document !!!

                    ScPatternAttr aPattern( rSrcDoc.getCellAttributeHelper() );
                    aPattern.GetItemSet().Put( ScMergeAttr() );             // Defaults
                    aPattern.GetItemSet().Put( ScMergeFlagAttr() );
                    aClipDoc.ApplyPatternAreaTab( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), nSrcTab, aPattern );
                }

                aNewTokenRange.aEnd.SetCol( aNewTokenRange.aStart.Col() + (rTokenRange.aEnd.Col() - rTokenRange.aStart.Col()) );
                aNewTokenRange.aEnd.SetRow( aNewTokenRange.aStart.Row() + (rTokenRange.aEnd.Row() - rTokenRange.aStart.Row()) );
                ScMarkData aDestMark(rDoc.GetSheetLimits());
                aDestMark.SelectOneTable( nDestTab );
                aDestMark.SetMarkArea( aNewTokenRange );
                rDoc.CopyFromClip( aNewTokenRange, aDestMark, InsertDeleteFlags::ALL, nullptr, &aClipDoc, false );
                aNewTokenRange.aStart.SetRow( aNewTokenRange.aEnd.Row() + 2 );
            }
        }
        else
        {
            OUString aErr = ScResId(STR_LINKERROR);
            rDoc.SetString( aDestPos.Col(), aDestPos.Row(), aDestPos.Tab(), aErr );
        }

        //  enter Undo

        if ( bAddUndo && bUndo)
        {
            ScDocumentUniquePtr pRedoDoc(new ScDocument( SCDOCMODE_UNDO ));
            pRedoDoc->InitUndo( rDoc, nDestTab, nDestTab );
            rDoc.CopyToDocument(aNewRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pRedoDoc);

            m_rDocSh.GetUndoManager()->AddUndoAction(
                std::make_unique<ScUndoUpdateAreaLink>( m_rDocSh,
                                            aFileName, aFilterName, aOptions,
                                            aSourceArea, aOldRange, GetRefreshDelaySeconds(),
                                            aNewUrl, rNewFilter, aNewOpt,
                                            rNewArea, aNewRange, nNewRefreshDelaySeconds,
                                            std::move(pUndoDoc), std::move(pRedoDoc), bDoInsert ) );
        }

        //  remember new settings

        if ( bNewUrlName )
            aFileName = aNewUrl;
        if ( rNewFilter != aFilterName )
            aFilterName = rNewFilter;
        if ( rNewArea != aSourceArea )
            aSourceArea = rNewArea;
        if ( aNewOpt != aOptions )
            aOptions = aNewOpt;

        if ( aNewRange != aDestArea )
            aDestArea = aNewRange;

        if ( nNewRefreshDelaySeconds != GetRefreshDelaySeconds() )
            SetRefreshDelay( nNewRefreshDelaySeconds );

        SCCOL nPaintEndX = std::max( aOldRange.aEnd.Col(), aNewRange.aEnd.Col() );
        SCROW nPaintEndY = std::max( aOldRange.aEnd.Row(), aNewRange.aEnd.Row() );

        if ( aOldRange.aEnd.Col() != aNewRange.aEnd.Col() )
            nPaintEndX = rDoc.MaxCol();
        if ( aOldRange.aEnd.Row() != aNewRange.aEnd.Row() )
            nPaintEndY = rDoc.MaxRow();

        if ( !m_rDocSh.AdjustRowHeight( aDestPos.Row(), nPaintEndY, nDestTab ) )
            m_rDocSh.PostPaint(
                ScRange(aDestPos.Col(), aDestPos.Row(), nDestTab, nPaintEndX, nPaintEndY, nDestTab),
                PaintPartFlags::Grid);
        aModificator.SetDocumentModified();
    }
    else
    {
        //  CanFitBlock sal_False -> Problems with summarized cells or table boundary reached!
        //! cell protection ???

        //! Link dialog must set default parent
        //  "cannot insert rows"
        weld::Window* pWin = Application::GetFrameWeld(m_rDocSh.GetDialogParent());
        std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWin,
                                                      VclMessageType::Info, VclButtonsType::Ok,
                                                      ScResId(STR_MSSG_DOSUBTOTALS_2)));
        xInfoBox->run();
    }

    //  clean up

    pSrcShell->DoClose();

    rDoc.SetInLinkUpdate( false );

    if (bCanDo)
    {
        //  notify Uno objects (for XRefreshListener)
        //! also notify Uno objects if file name was changed!
        ScLinkRefreshedHint aHint;
        aHint.SetAreaLink( aDestPos );
        rDoc.BroadcastUno( aHint );
    }

    return bCanDo;
}

IMPL_LINK_NOARG(ScAreaLink, RefreshHdl, Timer *, void)
{
    Refresh( aFileName, aFilterName, aSourceArea, GetRefreshDelaySeconds() );
}

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

Messung V0.5
C=89 H=96 G=92

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