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