1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27
28
29 // INCLUDE ---------------------------------------------------------------
30 #include <tools/list.hxx>
31 #include <sfx2/linkmgr.hxx>
32 #include <sfx2/bindings.hxx>
33 #include <svl/zforlist.hxx>
34
35 #include "ddelink.hxx"
36 #include "brdcst.hxx"
37 #include "document.hxx"
38 #include "scmatrix.hxx"
39 #include "patattr.hxx"
40 #include "rechead.hxx"
41 #include "rangeseq.hxx"
42 #include "sc.hrc"
43 #include "hints.hxx"
44
45 TYPEINIT2(ScDdeLink,::sfx2::SvBaseLink,SfxBroadcaster);
46
47 #define DDE_TXT_ENCODING gsl_getSystemTextEncoding()
48
49 sal_Bool ScDdeLink::bIsInUpdate = sal_False;
50
51 //------------------------------------------------------------------------
52
ScDdeLink(ScDocument * pD,const String & rA,const String & rT,const String & rI,sal_uInt8 nM)53 ScDdeLink::ScDdeLink( ScDocument* pD, const String& rA, const String& rT, const String& rI,
54 sal_uInt8 nM ) :
55 ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
56 pDoc( pD ),
57 aAppl( rA ),
58 aTopic( rT ),
59 aItem( rI ),
60 nMode( nM ),
61 bNeedUpdate( sal_False ),
62 pResult( NULL )
63 {
64 }
65
~ScDdeLink()66 __EXPORT ScDdeLink::~ScDdeLink()
67 {
68 // Verbindung aufheben
69
70 // pResult is refcounted
71 }
72
ScDdeLink(ScDocument * pD,const ScDdeLink & rOther)73 ScDdeLink::ScDdeLink( ScDocument* pD, const ScDdeLink& rOther ) :
74 ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
75 pDoc ( pD ),
76 aAppl ( rOther.aAppl ),
77 aTopic ( rOther.aTopic ),
78 aItem ( rOther.aItem ),
79 nMode ( rOther.nMode ),
80 bNeedUpdate( sal_False ),
81 pResult ( NULL )
82 {
83 if (rOther.pResult)
84 pResult = rOther.pResult->Clone();
85 }
86
ScDdeLink(ScDocument * pD,SvStream & rStream,ScMultipleReadHeader & rHdr)87 ScDdeLink::ScDdeLink( ScDocument* pD, SvStream& rStream, ScMultipleReadHeader& rHdr ) :
88 ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
89 pDoc( pD ),
90 bNeedUpdate( sal_False ),
91 pResult( NULL )
92 {
93 rHdr.StartEntry();
94
95 rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
96 rStream.ReadByteString( aAppl, eCharSet );
97 rStream.ReadByteString( aTopic, eCharSet );
98 rStream.ReadByteString( aItem, eCharSet );
99
100 sal_Bool bHasValue;
101 rStream >> bHasValue;
102 if ( bHasValue )
103 pResult = new ScMatrix( rStream );
104
105 if (rHdr.BytesLeft()) // neu in 388b und der 364w (RealTime-Client) Version
106 rStream >> nMode;
107 else
108 nMode = SC_DDE_DEFAULT;
109
110 rHdr.EndEntry();
111 }
112
Store(SvStream & rStream,ScMultipleWriteHeader & rHdr) const113 void ScDdeLink::Store( SvStream& rStream, ScMultipleWriteHeader& rHdr ) const
114 {
115 rHdr.StartEntry();
116
117 rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
118 rStream.WriteByteString( aAppl, eCharSet );
119 rStream.WriteByteString( aTopic, eCharSet );
120 rStream.WriteByteString( aItem, eCharSet );
121
122 sal_Bool bHasValue = ( pResult != NULL );
123 rStream << bHasValue;
124 if (bHasValue)
125 pResult->Store( rStream );
126
127 if( rStream.GetVersion() > SOFFICE_FILEFORMAT_40 ) // nicht bei 4.0 Export
128 rStream << nMode; // seit 388b
129
130 // Links mit Mode != SC_DDE_DEFAULT werden bei 4.0 Export komplett weggelassen
131 // (aus ScDocument::SaveDdeLinks)
132
133 rHdr.EndEntry();
134 }
135
DataChanged(const String & rMimeType,const::com::sun::star::uno::Any & rValue)136 void __EXPORT ScDdeLink::DataChanged( const String& rMimeType,
137 const ::com::sun::star::uno::Any & rValue )
138 {
139 // wir koennen nur Strings...
140 if ( FORMAT_STRING != SotExchange::GetFormatIdFromMimeType( rMimeType ))
141 return;
142
143 String aLinkStr;
144 ScByteSequenceToString::GetString( aLinkStr, rValue, DDE_TXT_ENCODING );
145 aLinkStr.ConvertLineEnd(LINEEND_LF);
146
147 // wenn String mit Zeilenende aufhoert, streichen:
148
149 xub_StrLen nLen = aLinkStr.Len();
150 if (nLen && aLinkStr.GetChar(nLen-1) == '\n')
151 aLinkStr.Erase(nLen-1);
152
153 String aLine;
154 SCSIZE nCols = 1; // Leerstring -> eine leere Zelle
155 SCSIZE nRows = 1;
156 if (aLinkStr.Len())
157 {
158 nRows = static_cast<SCSIZE>(aLinkStr.GetTokenCount( '\n' ));
159 aLine = aLinkStr.GetToken( 0, '\n' );
160 if (aLine.Len())
161 nCols = static_cast<SCSIZE>(aLine.GetTokenCount( '\t' ));
162 }
163
164 if (!nRows || !nCols) // keine Daten
165 {
166 pResult.Clear();
167 }
168 else // Daten aufteilen
169 {
170 // Matrix immer neu anlegen, damit bIsString nicht durcheinanderkommt
171 pResult = new ScMatrix( nCols, nRows );
172
173 SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
174
175 // nMode bestimmt, wie der Text interpretiert wird (#44455#/#49783#):
176 // SC_DDE_DEFAULT - Zahlformat aus Zellvorlage "Standard"
177 // SC_DDE_ENGLISH - Standard-Zahlformat fuer English/US
178 // SC_DDE_TEXT - ohne NumberFormatter direkt als String
179 sal_uLong nStdFormat = 0;
180 if ( nMode == SC_DDE_DEFAULT )
181 {
182 ScPatternAttr* pDefPattern = pDoc->GetDefPattern(); // enthaelt Standard-Vorlage
183 if ( pDefPattern )
184 nStdFormat = pDefPattern->GetNumberFormat( pFormatter );
185 }
186 else if ( nMode == SC_DDE_ENGLISH )
187 nStdFormat = pFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
188
189 String aEntry;
190 for (SCSIZE nR=0; nR<nRows; nR++)
191 {
192 aLine = aLinkStr.GetToken( (xub_StrLen) nR, '\n' );
193 for (SCSIZE nC=0; nC<nCols; nC++)
194 {
195 aEntry = aLine.GetToken( (xub_StrLen) nC, '\t' );
196 sal_uInt32 nIndex = nStdFormat;
197 double fVal;
198 if ( nMode != SC_DDE_TEXT && pFormatter->IsNumberFormat( aEntry, nIndex, fVal ) )
199 pResult->PutDouble( fVal, nC, nR );
200 else
201 pResult->PutString( aEntry, nC, nR );
202 }
203 }
204 }
205
206 // Es hat sich was getan...
207
208 if (HasListeners())
209 {
210 Broadcast( ScHint( SC_HINT_DATACHANGED, ScAddress(), NULL ) );
211 pDoc->TrackFormulas(); // muss sofort passieren
212 pDoc->StartTrackTimer();
213
214 // StartTrackTimer ruft asynchron TrackFormulas, Broadcast(FID_DATACHANGED),
215 // ResetChanged, SetModified und Invalidate(SID_SAVEDOC/SID_DOC_MODIFIED)
216 // TrackFormulas zusaetzlich nochmal sofort, damit nicht z.B. durch IdleCalc
217 // eine Formel berechnet wird, die noch im FormulaTrack steht (#61676#)
218
219 // notify Uno objects (for XRefreshListener)
220 // must be after TrackFormulas
221 //! do this asynchronously?
222 ScLinkRefreshedHint aHint;
223 aHint.SetDdeLink( aAppl, aTopic, aItem, nMode );
224 pDoc->BroadcastUno( aHint );
225 }
226 }
227
ResetValue()228 void ScDdeLink::ResetValue()
229 {
230 pResult.Clear();
231
232 // Es hat sich was getan...
233 // Tracking, FID_DATACHANGED etc. passiert von aussen
234
235 if (HasListeners())
236 Broadcast( ScHint( SC_HINT_DATACHANGED, ScAddress(), NULL ) );
237 }
238
ListenersGone()239 void __EXPORT ScDdeLink::ListenersGone()
240 {
241 sal_Bool bWas = bIsInUpdate;
242 bIsInUpdate = sal_True; // Remove() kann Reschedule ausloesen??!?
243
244 ScDocument* pStackDoc = pDoc; // member pDoc can't be used after removing the link
245
246 sfx2::LinkManager* pLinkMgr = pDoc->GetLinkManager();
247 pLinkMgr->Remove( this); // deletes this
248
249 if ( !pLinkMgr->GetLinks().Count() ) // letzten geloescht ?
250 {
251 SfxBindings* pBindings = pStackDoc->GetViewBindings(); // don't use member pDoc!
252 if (pBindings)
253 pBindings->Invalidate( SID_LINKS );
254 }
255
256 bIsInUpdate = bWas;
257 }
258
TryUpdate()259 void ScDdeLink::TryUpdate()
260 {
261 if (bIsInUpdate)
262 bNeedUpdate = sal_True; // kann jetzt nicht ausgefuehrt werden
263 else
264 {
265 bIsInUpdate = sal_True;
266 //Application::Reschedule(); //! OS/2-Simulation
267 pDoc->IncInDdeLinkUpdate();
268 Update();
269 pDoc->DecInDdeLinkUpdate();
270 bIsInUpdate = sal_False;
271 bNeedUpdate = sal_False;
272 }
273 }
274
275
276