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