1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/string.hxx>
21 #include <osl/thread.h>
22 #include <sfx2/linkmgr.hxx>
23 #include <sfx2/bindings.hxx>
24 #include <svl/zforlist.hxx>
25 #include <svl/sharedstringpool.hxx>
27 #include "ddelink.hxx"
29 #include "document.hxx"
30 #include "scmatrix.hxx"
31 #include "patattr.hxx"
32 #include "rechead.hxx"
33 #include "rangeseq.hxx"
37 TYPEINIT2(ScDdeLink
,::sfx2::SvBaseLink
,SfxBroadcaster
);
39 #define DDE_TXT_ENCODING osl_getThreadTextEncoding()
41 bool ScDdeLink::bIsInUpdate
= false;
43 ScDdeLink::ScDdeLink( ScDocument
* pD
, const OUString
& rA
, const OUString
& rT
, const OUString
& rI
,
45 ::sfx2::SvBaseLink(SfxLinkUpdateMode::ALWAYS
,SotClipboardFormatId::STRING
),
56 ScDdeLink::~ScDdeLink()
58 // Verbindung aufheben
60 // pResult is refcounted
63 ScDdeLink::ScDdeLink( ScDocument
* pD
, const ScDdeLink
& rOther
) :
64 ::sfx2::SvBaseLink(SfxLinkUpdateMode::ALWAYS
,SotClipboardFormatId::STRING
),
66 aAppl ( rOther
.aAppl
),
67 aTopic ( rOther
.aTopic
),
68 aItem ( rOther
.aItem
),
69 nMode ( rOther
.nMode
),
74 pResult
= rOther
.pResult
->Clone();
77 ScDdeLink::ScDdeLink( ScDocument
* pD
, SvStream
& rStream
, ScMultipleReadHeader
& rHdr
) :
78 ::sfx2::SvBaseLink(SfxLinkUpdateMode::ALWAYS
,SotClipboardFormatId::STRING
),
85 rtl_TextEncoding eCharSet
= rStream
.GetStreamCharSet();
86 aAppl
= rStream
.ReadUniOrByteString( eCharSet
);
87 aTopic
= rStream
.ReadUniOrByteString( eCharSet
);
88 aItem
= rStream
.ReadUniOrByteString( eCharSet
);
91 rStream
.ReadCharAsBool( bHasValue
);
93 pResult
= new ScMatrix(0, 0);
95 if (rHdr
.BytesLeft()) // neu in 388b und der 364w (RealTime-Client) Version
96 rStream
.ReadUChar( nMode
);
98 nMode
= SC_DDE_DEFAULT
;
103 void ScDdeLink::Store( SvStream
& rStream
, ScMultipleWriteHeader
& rHdr
) const
107 rtl_TextEncoding eCharSet
= rStream
.GetStreamCharSet();
108 rStream
.WriteUniOrByteString( aAppl
, eCharSet
);
109 rStream
.WriteUniOrByteString( aTopic
, eCharSet
);
110 rStream
.WriteUniOrByteString( aItem
, eCharSet
);
112 bool bHasValue
= ( pResult
!= 0 );
113 rStream
.WriteBool( bHasValue
);
115 if( rStream
.GetVersion() > SOFFICE_FILEFORMAT_40
) // nicht bei 4.0 Export
116 rStream
.WriteUChar( nMode
); // seit 388b
118 // Links mit Mode != SC_DDE_DEFAULT werden bei 4.0 Export komplett weggelassen
119 // (aus ScDocument::SaveDdeLinks)
124 sfx2::SvBaseLink::UpdateResult
ScDdeLink::DataChanged(
125 const OUString
& rMimeType
, const ::com::sun::star::uno::Any
& rValue
)
127 // wir koennen nur Strings...
128 if ( SotClipboardFormatId::STRING
!= SotExchange::GetFormatIdFromMimeType( rMimeType
))
132 ScByteSequenceToString::GetString( aLinkStr
, rValue
, DDE_TXT_ENCODING
);
133 aLinkStr
= convertLineEnd(aLinkStr
, LINEEND_LF
);
135 // wenn String mit Zeilenende aufhoert, streichen:
137 sal_Int32 nLen
= aLinkStr
.getLength();
138 if (nLen
&& aLinkStr
[nLen
-1] == '\n')
139 aLinkStr
= aLinkStr
.copy(0, nLen
-1);
142 SCSIZE nCols
= 1; // Leerstring -> eine leere Zelle
144 if (!aLinkStr
.isEmpty())
146 nRows
= static_cast<SCSIZE
>(comphelper::string::getTokenCount(aLinkStr
, '\n'));
147 aLine
= aLinkStr
.getToken( 0, '\n' );
148 if (!aLine
.isEmpty())
149 nCols
= static_cast<SCSIZE
>(comphelper::string::getTokenCount(aLine
, '\t'));
152 if (!nRows
|| !nCols
) // keine Daten
156 else // Daten aufteilen
158 // Matrix immer neu anlegen, damit bIsString nicht durcheinanderkommt
159 pResult
= new ScMatrix(nCols
, nRows
, 0.0);
161 SvNumberFormatter
* pFormatter
= pDoc
->GetFormatTable();
162 svl::SharedStringPool
& rPool
= pDoc
->GetSharedStringPool();
164 // nMode bestimmt, wie der Text interpretiert wird (#44455#/#49783#):
165 // SC_DDE_DEFAULT - Zahlformat aus Zellvorlage "Standard"
166 // SC_DDE_ENGLISH - Standard-Zahlformat fuer English/US
167 // SC_DDE_TEXT - ohne NumberFormatter direkt als String
168 sal_uLong nStdFormat
= 0;
169 if ( nMode
== SC_DDE_DEFAULT
)
171 ScPatternAttr
* pDefPattern
= pDoc
->GetDefPattern(); // enthaelt Standard-Vorlage
173 nStdFormat
= pDefPattern
->GetNumberFormat( pFormatter
);
175 else if ( nMode
== SC_DDE_ENGLISH
)
176 nStdFormat
= pFormatter
->GetStandardIndex(LANGUAGE_ENGLISH_US
);
179 for (SCSIZE nR
=0; nR
<nRows
; nR
++)
181 aLine
= aLinkStr
.getToken( (sal_Int32
) nR
, '\n' );
182 for (SCSIZE nC
=0; nC
<nCols
; nC
++)
184 aEntry
= aLine
.getToken( (sal_Int32
) nC
, '\t' );
185 sal_uInt32 nIndex
= nStdFormat
;
186 double fVal
= double();
187 if ( nMode
!= SC_DDE_TEXT
&& pFormatter
->IsNumberFormat( aEntry
, nIndex
, fVal
) )
188 pResult
->PutDouble( fVal
, nC
, nR
);
189 else if (aEntry
.isEmpty())
191 pResult
->PutEmpty(nC
, nR
);
193 pResult
->PutString(rPool
.intern(aEntry
), nC
, nR
);
198 // Es hat sich was getan...
202 Broadcast(ScHint(SC_HINT_DATACHANGED
, ScAddress()));
203 pDoc
->TrackFormulas(); // muss sofort passieren
204 pDoc
->StartTrackTimer();
206 // StartTrackTimer ruft asynchron TrackFormulas, Broadcast(FID_DATACHANGED),
207 // ResetChanged, SetModified und Invalidate(SID_SAVEDOC/SID_DOC_MODIFIED)
208 // TrackFormulas zusaetzlich nochmal sofort, damit nicht z.B. durch IdleCalc
209 // eine Formel berechnet wird, die noch im FormulaTrack steht (#61676#)
211 // notify Uno objects (for XRefreshListener)
212 // must be after TrackFormulas
213 //TODO: do this asynchronously?
214 ScLinkRefreshedHint aHint
;
215 aHint
.SetDdeLink( aAppl
, aTopic
, aItem
, nMode
);
216 pDoc
->BroadcastUno( aHint
);
222 void ScDdeLink::ListenersGone()
224 bool bWas
= bIsInUpdate
;
225 bIsInUpdate
= true; // Remove() kann Reschedule ausloesen??!?
227 ScDocument
* pStackDoc
= pDoc
; // member pDoc can't be used after removing the link
229 sfx2::LinkManager
* pLinkMgr
= pDoc
->GetLinkManager();
230 pLinkMgr
->Remove( this); // deletes this
232 if ( pLinkMgr
->GetLinks().empty() ) // letzten geloescht ?
234 SfxBindings
* pBindings
= pStackDoc
->GetViewBindings(); // don't use member pDoc!
236 pBindings
->Invalidate( SID_LINKS
);
242 const ScMatrix
* ScDdeLink::GetResult() const
244 return pResult
.get();
247 void ScDdeLink::SetResult( const ScMatrixRef
& pRes
)
252 void ScDdeLink::TryUpdate()
255 bNeedUpdate
= true; // kann jetzt nicht ausgefuehrt werden
259 pDoc
->IncInDdeLinkUpdate();
261 pDoc
->DecInDdeLinkUpdate();
267 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */