fc1b2a0ab2
This reverts
commit 76e9023c8a
Author: Noel Grandin <noelgrandin@gmail.com>
Date: Mon Jan 22 08:36:28 2024 +0200
convert more calc dialogs to async
I fixed some lifetime issues, but even once that was happy,
the Text Attributes dialog was not receiving mouse events
properly, something else is unhappy when we mix async
and modal dialogs.
Change-Id: I4a35d886895c65af2085b606ff5c7a7c02fb5671
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165305
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
497 lines
18 KiB
C++
497 lines
18 KiB
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* pShell, OUString aFile,
|
|
OUString aFilter, OUString aOpt,
|
|
OUString aArea, const ScRange& rDest,
|
|
sal_Int32 nRefreshDelaySeconds ) :
|
|
::sfx2::SvBaseLink(SfxLinkUpdateMode::ONCALL,SotClipboardFormatId::SIMPLE_FILE),
|
|
ScRefreshTimer ( nRefreshDelaySeconds ),
|
|
m_pDocSh(pShell),
|
|
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_pDocSh->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_pDocSh->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_pDocSh->GetDocument();
|
|
bool bUndo (rDoc.IsUndoEnabled());
|
|
if (bAddUndo && bUndo)
|
|
{
|
|
m_pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoRemoveAreaLink>( m_pDocSh,
|
|
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_pDocSh->GetEmbeddedObjectContainer().getUserAllowsLinkUpdate())
|
|
return false;
|
|
|
|
OUString aNewUrl( ScGlobal::GetAbsDocName( rNewFile, m_pDocSh ) );
|
|
bool bNewUrlName = (aNewUrl != aFileName);
|
|
|
|
std::shared_ptr<const SfxFilter> pFilter = m_pDocSh->GetFactory().GetFilterContainer()->GetFilter4FilterName(rNewFilter);
|
|
if (!pFilter)
|
|
return false;
|
|
|
|
ScDocument& rDoc = m_pDocSh->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_pDocSh );
|
|
|
|
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, false, false);
|
|
|
|
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_pDocSh->GetUndoManager()->AddUndoAction(
|
|
std::make_unique<ScUndoUpdateAreaLink>( m_pDocSh,
|
|
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_pDocSh->AdjustRowHeight( aDestPos.Row(), nPaintEndY, nDestTab ) )
|
|
m_pDocSh->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_pDocSh->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: */
|