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 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 68 __EXPORT ScDdeLink::~ScDdeLink() 69 { 70 // Verbindung aufheben 71 72 // pResult is refcounted 73 } 74 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 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 115 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 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 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 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 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