264 lines
8.4 KiB
C++
264 lines
8.4 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 <comphelper/fileformat.h>
|
|
#include <comphelper/string.hxx>
|
|
#include <osl/thread.h>
|
|
#include <sot/exchange.hxx>
|
|
#include <sfx2/linkmgr.hxx>
|
|
#include <sfx2/bindings.hxx>
|
|
#include <svl/numformat.hxx>
|
|
#include <svl/sharedstringpool.hxx>
|
|
#include <o3tl/string_view.hxx>
|
|
|
|
#include <ddelink.hxx>
|
|
#include <brdcst.hxx>
|
|
#include <document.hxx>
|
|
#include <scmatrix.hxx>
|
|
#include <patattr.hxx>
|
|
#include <rechead.hxx>
|
|
#include <rangeseq.hxx>
|
|
#include <sc.hrc>
|
|
#include <hints.hxx>
|
|
#include <utility>
|
|
|
|
|
|
bool ScDdeLink::bIsInUpdate = false;
|
|
|
|
ScDdeLink::ScDdeLink( ScDocument& rD, OUString aA, OUString aT, OUString aI,
|
|
sal_uInt8 nM ) :
|
|
::sfx2::SvBaseLink(SfxLinkUpdateMode::ALWAYS,SotClipboardFormatId::STRING),
|
|
rDoc( rD ),
|
|
aAppl(std::move( aA )),
|
|
aTopic(std::move( aT )),
|
|
aItem(std::move( aI )),
|
|
nMode( nM ),
|
|
bNeedUpdate( false ),
|
|
pResult( nullptr )
|
|
{
|
|
}
|
|
|
|
ScDdeLink::~ScDdeLink()
|
|
{
|
|
// cancel connection
|
|
|
|
// pResult is refcounted
|
|
}
|
|
|
|
ScDdeLink::ScDdeLink( ScDocument& rD, const ScDdeLink& rOther ) :
|
|
::sfx2::SvBaseLink(SfxLinkUpdateMode::ALWAYS,SotClipboardFormatId::STRING),
|
|
rDoc ( rD ),
|
|
aAppl ( rOther.aAppl ),
|
|
aTopic ( rOther.aTopic ),
|
|
aItem ( rOther.aItem ),
|
|
nMode ( rOther.nMode ),
|
|
bNeedUpdate( false ),
|
|
pResult ( nullptr )
|
|
{
|
|
if (rOther.pResult)
|
|
pResult = rOther.pResult->Clone();
|
|
}
|
|
|
|
ScDdeLink::ScDdeLink( ScDocument& rD, SvStream& rStream, ScMultipleReadHeader& rHdr ) :
|
|
::sfx2::SvBaseLink(SfxLinkUpdateMode::ALWAYS,SotClipboardFormatId::STRING),
|
|
rDoc( rD ),
|
|
bNeedUpdate( false ),
|
|
pResult( nullptr )
|
|
{
|
|
rHdr.StartEntry();
|
|
|
|
rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
|
|
aAppl = rStream.ReadUniOrByteString( eCharSet );
|
|
aTopic = rStream.ReadUniOrByteString( eCharSet );
|
|
aItem = rStream.ReadUniOrByteString( eCharSet );
|
|
|
|
bool bHasValue;
|
|
rStream.ReadCharAsBool( bHasValue );
|
|
if ( bHasValue )
|
|
pResult = new ScMatrix(0, 0);
|
|
|
|
if (rHdr.BytesLeft()) // new in 388b and the 364w (RealTime Client) version
|
|
rStream.ReadUChar( nMode );
|
|
else
|
|
nMode = SC_DDE_DEFAULT;
|
|
|
|
rHdr.EndEntry();
|
|
}
|
|
|
|
void ScDdeLink::Store( SvStream& rStream, ScMultipleWriteHeader& rHdr ) const
|
|
{
|
|
rHdr.StartEntry();
|
|
|
|
rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
|
|
rStream.WriteUniOrByteString( aAppl, eCharSet );
|
|
rStream.WriteUniOrByteString( aTopic, eCharSet );
|
|
rStream.WriteUniOrByteString( aItem, eCharSet );
|
|
|
|
bool bHasValue = ( pResult != nullptr );
|
|
rStream.WriteBool( bHasValue );
|
|
|
|
if( rStream.GetVersion() > SOFFICE_FILEFORMAT_40 ) // not with 4.0 Export
|
|
rStream.WriteUChar( nMode ); // since 388b
|
|
|
|
// links with Mode != SC_DDE_DEFAULT are completely omitted in 4.0 Export
|
|
// (from ScDocument::SaveDdeLinks)
|
|
|
|
rHdr.EndEntry();
|
|
}
|
|
|
|
sfx2::SvBaseLink::UpdateResult ScDdeLink::DataChanged(
|
|
const OUString& rMimeType, const css::uno::Any & rValue )
|
|
{
|
|
// we only master strings...
|
|
if ( SotClipboardFormatId::STRING != SotExchange::GetFormatIdFromMimeType( rMimeType ))
|
|
return SUCCESS;
|
|
|
|
OUString aLinkStr;
|
|
ScByteSequenceToString::GetString( aLinkStr, rValue );
|
|
aLinkStr = convertLineEnd(aLinkStr, LINEEND_LF);
|
|
|
|
// if string ends with line end, discard:
|
|
|
|
sal_Int32 nLen = aLinkStr.getLength();
|
|
if (nLen && aLinkStr[nLen-1] == '\n')
|
|
aLinkStr = aLinkStr.copy(0, nLen-1);
|
|
|
|
SCSIZE nCols = 1; // empty string -> an empty line
|
|
SCSIZE nRows = 1;
|
|
if (!aLinkStr.isEmpty())
|
|
{
|
|
nRows = static_cast<SCSIZE>(comphelper::string::getTokenCount(aLinkStr, '\n'));
|
|
std::u16string_view aLine = o3tl::getToken(aLinkStr, 0, '\n' );
|
|
if (!aLine.empty())
|
|
nCols = static_cast<SCSIZE>(comphelper::string::getTokenCount(aLine, '\t'));
|
|
}
|
|
|
|
if (!nRows || !nCols) // no data
|
|
{
|
|
pResult.reset();
|
|
}
|
|
else // split data
|
|
{
|
|
// always newly re-create matrix, so that bIsString doesn't get mixed up
|
|
pResult = new ScMatrix(nCols, nRows, 0.0);
|
|
|
|
SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
|
|
svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
|
|
|
|
// nMode determines how the text is interpreted (#44455#/#49783#):
|
|
// SC_DDE_DEFAULT - number format from cell template "Standard"
|
|
// SC_DDE_ENGLISH - standard number format for English/US
|
|
// SC_DDE_TEXT - without NumberFormatter directly as string
|
|
sal_uLong nStdFormat = 0;
|
|
if ( nMode == SC_DDE_DEFAULT )
|
|
{
|
|
nStdFormat = rDoc.getCellAttributeHelper().getDefaultCellAttribute().GetNumberFormat( pFormatter );
|
|
}
|
|
else if ( nMode == SC_DDE_ENGLISH )
|
|
nStdFormat = pFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
|
|
|
|
for (SCSIZE nR=0; nR<nRows; nR++)
|
|
{
|
|
std::u16string_view aLine = o3tl::getToken(aLinkStr, static_cast<sal_Int32>(nR), '\n' );
|
|
for (SCSIZE nC=0; nC<nCols; nC++)
|
|
{
|
|
OUString aEntry( o3tl::getToken(aLine, static_cast<sal_Int32>(nC), '\t' ) );
|
|
sal_uInt32 nIndex = nStdFormat;
|
|
double fVal = double();
|
|
if ( nMode != SC_DDE_TEXT && pFormatter->IsNumberFormat( aEntry, nIndex, fVal ) )
|
|
pResult->PutDouble( fVal, nC, nR );
|
|
else if (aEntry.isEmpty())
|
|
// empty cell
|
|
pResult->PutEmpty(nC, nR);
|
|
else
|
|
pResult->PutString(rPool.intern(aEntry), nC, nR);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Something happened...
|
|
|
|
if (HasListeners())
|
|
{
|
|
Broadcast(ScHint(SfxHintId::ScDataChanged, ScAddress()));
|
|
rDoc.TrackFormulas(); // must happen immediately
|
|
rDoc.StartTrackTimer();
|
|
|
|
// StartTrackTimer asynchronously calls TrackFormulas, Broadcast(FID_DATACHANGED),
|
|
// ResetChanged, SetModified and Invalidate(SID_SAVEDOC/SID_DOC_MODIFIED)
|
|
// TrackFormulas additionally once again immediately, so that, e.g., a formula still
|
|
// located in the FormulaTrack doesn't get calculated by IdleCalc (#61676#)
|
|
|
|
// notify Uno objects (for XRefreshListener)
|
|
// must be after TrackFormulas
|
|
//TODO: do this asynchronously?
|
|
ScLinkRefreshedHint aHint;
|
|
aHint.SetDdeLink( aAppl, aTopic, aItem );
|
|
rDoc.BroadcastUno( aHint );
|
|
}
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
void ScDdeLink::ListenersGone()
|
|
{
|
|
bool bWas = bIsInUpdate;
|
|
bIsInUpdate = true; // Remove() can trigger reschedule??!?
|
|
|
|
ScDocument& rStackDoc = rDoc; // member rDoc can't be used after removing the link
|
|
|
|
sfx2::LinkManager* pLinkMgr = rDoc.GetLinkManager();
|
|
pLinkMgr->Remove( this); // deletes this
|
|
|
|
if ( pLinkMgr->GetLinks().empty() ) // deleted the last one ?
|
|
{
|
|
SfxBindings* pBindings = rStackDoc.GetViewBindings(); // don't use member rDoc!
|
|
if (pBindings)
|
|
pBindings->Invalidate( SID_LINKS );
|
|
}
|
|
|
|
bIsInUpdate = bWas;
|
|
}
|
|
|
|
const ScMatrix* ScDdeLink::GetResult() const
|
|
{
|
|
return pResult.get();
|
|
}
|
|
|
|
void ScDdeLink::SetResult( const ScMatrixRef& pRes )
|
|
{
|
|
pResult = pRes;
|
|
}
|
|
|
|
void ScDdeLink::TryUpdate()
|
|
{
|
|
if (bIsInUpdate)
|
|
bNeedUpdate = true; // cannot be executed now
|
|
else
|
|
{
|
|
bIsInUpdate = true;
|
|
rDoc.IncInDdeLinkUpdate();
|
|
Update();
|
|
rDoc.DecInDdeLinkUpdate();
|
|
bIsInUpdate = false;
|
|
bNeedUpdate = false;
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|