Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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"
26 :
27 : #include "ddelink.hxx"
28 : #include "brdcst.hxx"
29 : #include "document.hxx"
30 : #include "scmatrix.hxx"
31 : #include "patattr.hxx"
32 : #include "rechead.hxx"
33 : #include "rangeseq.hxx"
34 : #include "sc.hrc"
35 : #include "hints.hxx"
36 :
37 0 : TYPEINIT2(ScDdeLink,::sfx2::SvBaseLink,SfxBroadcaster);
38 :
39 : #define DDE_TXT_ENCODING osl_getThreadTextEncoding()
40 :
41 : bool ScDdeLink::bIsInUpdate = false;
42 :
43 0 : ScDdeLink::ScDdeLink( ScDocument* pD, const OUString& rA, const OUString& rT, const OUString& rI,
44 : sal_uInt8 nM ) :
45 : ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
46 : pDoc( pD ),
47 : aAppl( rA ),
48 : aTopic( rT ),
49 : aItem( rI ),
50 : nMode( nM ),
51 : bNeedUpdate( false ),
52 0 : pResult( NULL )
53 : {
54 0 : }
55 :
56 0 : ScDdeLink::~ScDdeLink()
57 : {
58 : // Verbindung aufheben
59 :
60 : // pResult is refcounted
61 0 : }
62 :
63 0 : ScDdeLink::ScDdeLink( ScDocument* pD, const ScDdeLink& rOther ) :
64 : ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
65 : pDoc ( pD ),
66 : aAppl ( rOther.aAppl ),
67 : aTopic ( rOther.aTopic ),
68 : aItem ( rOther.aItem ),
69 : nMode ( rOther.nMode ),
70 : bNeedUpdate( false ),
71 0 : pResult ( NULL )
72 : {
73 0 : if (rOther.pResult)
74 0 : pResult = rOther.pResult->Clone();
75 0 : }
76 :
77 0 : ScDdeLink::ScDdeLink( ScDocument* pD, SvStream& rStream, ScMultipleReadHeader& rHdr ) :
78 : ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
79 : pDoc( pD ),
80 : bNeedUpdate( false ),
81 0 : pResult( NULL )
82 : {
83 0 : rHdr.StartEntry();
84 :
85 0 : rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
86 0 : aAppl = rStream.ReadUniOrByteString( eCharSet );
87 0 : aTopic = rStream.ReadUniOrByteString( eCharSet );
88 0 : aItem = rStream.ReadUniOrByteString( eCharSet );
89 :
90 : sal_Bool bHasValue;
91 0 : rStream.ReadUChar( bHasValue );
92 0 : if ( bHasValue )
93 0 : pResult = new ScMatrix(0, 0);
94 :
95 0 : if (rHdr.BytesLeft()) // neu in 388b und der 364w (RealTime-Client) Version
96 0 : rStream.ReadUChar( nMode );
97 : else
98 0 : nMode = SC_DDE_DEFAULT;
99 :
100 0 : rHdr.EndEntry();
101 0 : }
102 :
103 0 : void ScDdeLink::Store( SvStream& rStream, ScMultipleWriteHeader& rHdr ) const
104 : {
105 0 : rHdr.StartEntry();
106 :
107 0 : rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
108 0 : rStream.WriteUniOrByteString( aAppl, eCharSet );
109 0 : rStream.WriteUniOrByteString( aTopic, eCharSet );
110 0 : rStream.WriteUniOrByteString( aItem, eCharSet );
111 :
112 0 : sal_Bool bHasValue = ( pResult != 0 );
113 0 : rStream.WriteUChar( bHasValue );
114 :
115 0 : if( rStream.GetVersion() > SOFFICE_FILEFORMAT_40 ) // nicht bei 4.0 Export
116 0 : rStream.WriteUChar( nMode ); // seit 388b
117 :
118 : // Links mit Mode != SC_DDE_DEFAULT werden bei 4.0 Export komplett weggelassen
119 : // (aus ScDocument::SaveDdeLinks)
120 :
121 0 : rHdr.EndEntry();
122 0 : }
123 :
124 0 : sfx2::SvBaseLink::UpdateResult ScDdeLink::DataChanged(
125 : const OUString& rMimeType, const ::com::sun::star::uno::Any & rValue )
126 : {
127 : // wir koennen nur Strings...
128 0 : if ( FORMAT_STRING != SotExchange::GetFormatIdFromMimeType( rMimeType ))
129 0 : return SUCCESS;
130 :
131 0 : OUString aLinkStr;
132 0 : ScByteSequenceToString::GetString( aLinkStr, rValue, DDE_TXT_ENCODING );
133 0 : aLinkStr = convertLineEnd(aLinkStr, LINEEND_LF);
134 :
135 : // wenn String mit Zeilenende aufhoert, streichen:
136 :
137 0 : sal_Int32 nLen = aLinkStr.getLength();
138 0 : if (nLen && aLinkStr[nLen-1] == '\n')
139 0 : aLinkStr = aLinkStr.copy(0, nLen-1);
140 :
141 0 : OUString aLine;
142 0 : SCSIZE nCols = 1; // Leerstring -> eine leere Zelle
143 0 : SCSIZE nRows = 1;
144 0 : if (!aLinkStr.isEmpty())
145 : {
146 0 : nRows = static_cast<SCSIZE>(comphelper::string::getTokenCount(aLinkStr, '\n'));
147 0 : aLine = aLinkStr.getToken( 0, '\n' );
148 0 : if (!aLine.isEmpty())
149 0 : nCols = static_cast<SCSIZE>(comphelper::string::getTokenCount(aLine, '\t'));
150 : }
151 :
152 0 : if (!nRows || !nCols) // keine Daten
153 : {
154 0 : pResult.reset();
155 : }
156 : else // Daten aufteilen
157 : {
158 : // Matrix immer neu anlegen, damit bIsString nicht durcheinanderkommt
159 0 : pResult = new ScMatrix(nCols, nRows, 0.0);
160 :
161 0 : SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
162 0 : svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
163 :
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 0 : sal_uLong nStdFormat = 0;
169 0 : if ( nMode == SC_DDE_DEFAULT )
170 : {
171 0 : ScPatternAttr* pDefPattern = pDoc->GetDefPattern(); // enthaelt Standard-Vorlage
172 0 : if ( pDefPattern )
173 0 : nStdFormat = pDefPattern->GetNumberFormat( pFormatter );
174 : }
175 0 : else if ( nMode == SC_DDE_ENGLISH )
176 0 : nStdFormat = pFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
177 :
178 0 : OUString aEntry;
179 0 : for (SCSIZE nR=0; nR<nRows; nR++)
180 : {
181 0 : aLine = aLinkStr.getToken( (sal_Int32) nR, '\n' );
182 0 : for (SCSIZE nC=0; nC<nCols; nC++)
183 : {
184 0 : aEntry = aLine.getToken( (sal_Int32) nC, '\t' );
185 0 : sal_uInt32 nIndex = nStdFormat;
186 0 : double fVal = double();
187 0 : if ( nMode != SC_DDE_TEXT && pFormatter->IsNumberFormat( aEntry, nIndex, fVal ) )
188 0 : pResult->PutDouble( fVal, nC, nR );
189 0 : else if (aEntry.isEmpty())
190 : // empty cell
191 0 : pResult->PutEmpty(nC, nR);
192 : else
193 0 : pResult->PutString(rPool.intern(aEntry), nC, nR);
194 : }
195 0 : }
196 : }
197 :
198 : // Es hat sich was getan...
199 :
200 0 : if (HasListeners())
201 : {
202 0 : Broadcast(ScHint(SC_HINT_DATACHANGED, ScAddress()));
203 0 : pDoc->TrackFormulas(); // muss sofort passieren
204 0 : pDoc->StartTrackTimer();
205 :
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#)
210 :
211 : // notify Uno objects (for XRefreshListener)
212 : // must be after TrackFormulas
213 : //! do this asynchronously?
214 0 : ScLinkRefreshedHint aHint;
215 0 : aHint.SetDdeLink( aAppl, aTopic, aItem, nMode );
216 0 : pDoc->BroadcastUno( aHint );
217 : }
218 :
219 0 : return SUCCESS;
220 : }
221 :
222 0 : void ScDdeLink::ListenersGone()
223 : {
224 0 : bool bWas = bIsInUpdate;
225 0 : bIsInUpdate = true; // Remove() kann Reschedule ausloesen??!?
226 :
227 0 : ScDocument* pStackDoc = pDoc; // member pDoc can't be used after removing the link
228 :
229 0 : sfx2::LinkManager* pLinkMgr = pDoc->GetLinkManager();
230 0 : pLinkMgr->Remove( this); // deletes this
231 :
232 0 : if ( pLinkMgr->GetLinks().empty() ) // letzten geloescht ?
233 : {
234 0 : SfxBindings* pBindings = pStackDoc->GetViewBindings(); // don't use member pDoc!
235 0 : if (pBindings)
236 0 : pBindings->Invalidate( SID_LINKS );
237 : }
238 :
239 0 : bIsInUpdate = bWas;
240 0 : }
241 :
242 0 : const ScMatrix* ScDdeLink::GetResult() const
243 : {
244 0 : return pResult.get();
245 : }
246 :
247 0 : void ScDdeLink::SetResult( const ScMatrixRef& pRes )
248 : {
249 0 : pResult = pRes;
250 0 : }
251 :
252 0 : void ScDdeLink::TryUpdate()
253 : {
254 0 : if (bIsInUpdate)
255 0 : bNeedUpdate = true; // kann jetzt nicht ausgefuehrt werden
256 : else
257 : {
258 0 : bIsInUpdate = true;
259 0 : pDoc->IncInDdeLinkUpdate();
260 0 : Update();
261 0 : pDoc->DecInDdeLinkUpdate();
262 0 : bIsInUpdate = false;
263 0 : bNeedUpdate = false;
264 : }
265 0 : }
266 :
267 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|