xref: /trunk/main/sc/source/core/tool/ddelink.cxx (revision b3f79822)
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