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 :
21 : #include <comphelper/string.hxx>
22 : #include <sfx2/linkmgr.hxx>
23 : #include <sfx2/bindings.hxx>
24 : #include <svl/zforlist.hxx>
25 :
26 : #include "ddelink.hxx"
27 : #include "brdcst.hxx"
28 : #include "document.hxx"
29 : #include "scmatrix.hxx"
30 : #include "patattr.hxx"
31 : #include "rechead.hxx"
32 : #include "rangeseq.hxx"
33 : #include "sc.hrc"
34 : #include "hints.hxx"
35 :
36 0 : TYPEINIT2(ScDdeLink,::sfx2::SvBaseLink,SfxBroadcaster);
37 :
38 : #define DDE_TXT_ENCODING osl_getThreadTextEncoding()
39 :
40 : bool ScDdeLink::bIsInUpdate = false;
41 :
42 : //------------------------------------------------------------------------
43 :
44 0 : ScDdeLink::ScDdeLink( ScDocument* pD, const String& rA, const String& rT, const String& rI,
45 : sal_uInt8 nM ) :
46 : ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
47 : pDoc( pD ),
48 : aAppl( rA ),
49 : aTopic( rT ),
50 : aItem( rI ),
51 : nMode( nM ),
52 : bNeedUpdate( false ),
53 0 : pResult( NULL )
54 : {
55 0 : }
56 :
57 0 : ScDdeLink::~ScDdeLink()
58 : {
59 : // Verbindung aufheben
60 :
61 : // pResult is refcounted
62 0 : }
63 :
64 0 : ScDdeLink::ScDdeLink( ScDocument* pD, const ScDdeLink& rOther ) :
65 : ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
66 : pDoc ( pD ),
67 : aAppl ( rOther.aAppl ),
68 : aTopic ( rOther.aTopic ),
69 : aItem ( rOther.aItem ),
70 : nMode ( rOther.nMode ),
71 : bNeedUpdate( false ),
72 0 : pResult ( NULL )
73 : {
74 0 : if (rOther.pResult)
75 0 : pResult = rOther.pResult->Clone();
76 0 : }
77 :
78 0 : ScDdeLink::ScDdeLink( ScDocument* pD, SvStream& rStream, ScMultipleReadHeader& rHdr ) :
79 : ::sfx2::SvBaseLink(sfx2::LINKUPDATE_ALWAYS,FORMAT_STRING),
80 : pDoc( pD ),
81 : bNeedUpdate( false ),
82 0 : pResult( NULL )
83 : {
84 0 : rHdr.StartEntry();
85 :
86 0 : rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
87 0 : aAppl = rStream.ReadUniOrByteString( eCharSet );
88 0 : aTopic = rStream.ReadUniOrByteString( eCharSet );
89 0 : aItem = rStream.ReadUniOrByteString( eCharSet );
90 :
91 : sal_Bool bHasValue;
92 0 : rStream >> bHasValue;
93 0 : if ( bHasValue )
94 0 : pResult = new ScMatrix(0, 0);
95 :
96 0 : if (rHdr.BytesLeft()) // neu in 388b und der 364w (RealTime-Client) Version
97 0 : rStream >> nMode;
98 : else
99 0 : nMode = SC_DDE_DEFAULT;
100 :
101 0 : rHdr.EndEntry();
102 0 : }
103 :
104 0 : void ScDdeLink::Store( SvStream& rStream, ScMultipleWriteHeader& rHdr ) const
105 : {
106 0 : rHdr.StartEntry();
107 :
108 0 : rtl_TextEncoding eCharSet = rStream.GetStreamCharSet();
109 0 : rStream.WriteUniOrByteString( aAppl, eCharSet );
110 0 : rStream.WriteUniOrByteString( aTopic, eCharSet );
111 0 : rStream.WriteUniOrByteString( aItem, eCharSet );
112 :
113 0 : sal_Bool bHasValue = ( pResult != NULL );
114 0 : rStream << bHasValue;
115 :
116 0 : if( rStream.GetVersion() > SOFFICE_FILEFORMAT_40 ) // nicht bei 4.0 Export
117 0 : rStream << nMode; // seit 388b
118 :
119 : // Links mit Mode != SC_DDE_DEFAULT werden bei 4.0 Export komplett weggelassen
120 : // (aus ScDocument::SaveDdeLinks)
121 :
122 0 : rHdr.EndEntry();
123 0 : }
124 :
125 0 : sfx2::SvBaseLink::UpdateResult ScDdeLink::DataChanged(
126 : const String& rMimeType, const ::com::sun::star::uno::Any & rValue )
127 : {
128 : // wir koennen nur Strings...
129 0 : if ( FORMAT_STRING != SotExchange::GetFormatIdFromMimeType( rMimeType ))
130 0 : return SUCCESS;
131 :
132 0 : String aLinkStr;
133 0 : ScByteSequenceToString::GetString( aLinkStr, rValue, DDE_TXT_ENCODING );
134 0 : aLinkStr = convertLineEnd(aLinkStr, LINEEND_LF);
135 :
136 : // wenn String mit Zeilenende aufhoert, streichen:
137 :
138 0 : xub_StrLen nLen = aLinkStr.Len();
139 0 : if (nLen && aLinkStr.GetChar(nLen-1) == '\n')
140 0 : aLinkStr.Erase(nLen-1);
141 :
142 0 : String aLine;
143 0 : SCSIZE nCols = 1; // Leerstring -> eine leere Zelle
144 0 : SCSIZE nRows = 1;
145 0 : if (aLinkStr.Len())
146 : {
147 0 : nRows = static_cast<SCSIZE>(comphelper::string::getTokenCount(aLinkStr, '\n'));
148 0 : aLine = aLinkStr.GetToken( 0, '\n' );
149 0 : if (aLine.Len())
150 0 : nCols = static_cast<SCSIZE>(comphelper::string::getTokenCount(aLine, '\t'));
151 : }
152 :
153 0 : if (!nRows || !nCols) // keine Daten
154 : {
155 0 : pResult.reset();
156 : }
157 : else // Daten aufteilen
158 : {
159 : // Matrix immer neu anlegen, damit bIsString nicht durcheinanderkommt
160 0 : pResult = new ScMatrix(nCols, nRows, 0.0);
161 :
162 0 : SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
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 : String aEntry;
179 0 : for (SCSIZE nR=0; nR<nRows; nR++)
180 : {
181 0 : aLine = aLinkStr.GetToken( (xub_StrLen) nR, '\n' );
182 0 : for (SCSIZE nC=0; nC<nCols; nC++)
183 : {
184 0 : aEntry = aLine.GetToken( (xub_StrLen) 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.Len() == 0)
190 : // empty cell
191 0 : pResult->PutEmpty(nC, nR);
192 : else
193 0 : pResult->PutString( 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(), NULL ) );
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 : void ScDdeLink::TryUpdate()
243 : {
244 0 : if (bIsInUpdate)
245 0 : bNeedUpdate = true; // kann jetzt nicht ausgefuehrt werden
246 : else
247 : {
248 0 : bIsInUpdate = true;
249 0 : pDoc->IncInDdeLinkUpdate();
250 0 : Update();
251 0 : pDoc->DecInDdeLinkUpdate();
252 0 : bIsInUpdate = false;
253 0 : bNeedUpdate = false;
254 : }
255 0 : }
256 :
257 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|