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 // System - Includes ----------------------------------------------------- 27 28 29 30 #include <sot/formats.hxx> 31 #include <sfx2/app.hxx> 32 #include <sfx2/linkmgr.hxx> 33 #include "servobj.hxx" 34 #include "docsh.hxx" 35 #include "impex.hxx" 36 #include "brdcst.hxx" 37 #include "rangenam.hxx" 38 #include "sc.hrc" // SC_HINT_AREAS_CHANGED 39 40 // ----------------------------------------------------------------------- 41 42 sal_Bool lcl_FillRangeFromName( ScRange& rRange, ScDocShell* pDocSh, const String& rName ) 43 { 44 if (pDocSh) 45 { 46 ScDocument* pDoc = pDocSh->GetDocument(); 47 ScRangeName* pNames = pDoc->GetRangeName(); 48 if (pNames) 49 { 50 sal_uInt16 nPos; 51 if( pNames->SearchName( rName, nPos ) ) 52 { 53 ScRangeData* pData = (*pNames)[ nPos ]; 54 if ( pData->IsValidReference( rRange ) ) 55 return sal_True; 56 } 57 } 58 } 59 return sal_False; 60 } 61 62 ScServerObjectSvtListenerForwarder::ScServerObjectSvtListenerForwarder( 63 ScServerObject* pObjP) 64 : pObj(pObjP) 65 { 66 } 67 68 ScServerObjectSvtListenerForwarder::~ScServerObjectSvtListenerForwarder() 69 { 70 //! do NOT access pObj 71 } 72 73 void ScServerObjectSvtListenerForwarder::Notify( SvtBroadcaster& /* rBC */, const SfxHint& rHint) 74 { 75 pObj->Notify( aBroadcaster, rHint); 76 } 77 78 ScServerObject::ScServerObject( ScDocShell* pShell, const String& rItem ) : 79 aForwarder( this ), 80 pDocSh( pShell ), 81 bRefreshListener( sal_False ) 82 { 83 // parse item string 84 85 if ( lcl_FillRangeFromName( aRange, pDocSh, rItem ) ) 86 { 87 aItemStr = rItem; // must be parsed again on ref update 88 } 89 else 90 { 91 // parse ref 92 ScDocument* pDoc = pDocSh->GetDocument(); 93 SCTAB nTab = pDocSh->GetCurTab(); 94 aRange.aStart.SetTab( nTab ); 95 96 if ( aRange.Parse( rItem, pDoc ) & SCA_VALID ) 97 { 98 // area reference 99 } 100 else if ( aRange.aStart.Parse( rItem, pDoc, pDoc->GetAddressConvention() ) & SCA_VALID ) 101 { 102 // cell reference 103 aRange.aEnd = aRange.aStart; 104 } 105 else 106 { 107 DBG_ERROR("ScServerObject: invalid item"); 108 } 109 } 110 111 pDocSh->GetDocument()->GetLinkManager()->InsertServer( this ); 112 pDocSh->GetDocument()->StartListeningArea( aRange, &aForwarder ); 113 114 StartListening(*pDocSh); // um mitzubekommen, wenn die DocShell geloescht wird 115 StartListening(*SFX_APP()); // for SC_HINT_AREAS_CHANGED 116 } 117 118 __EXPORT ScServerObject::~ScServerObject() 119 { 120 Clear(); 121 } 122 123 void ScServerObject::Clear() 124 { 125 if (pDocSh) 126 { 127 ScDocShell* pTemp = pDocSh; 128 pDocSh = NULL; 129 130 pTemp->GetDocument()->EndListeningArea( aRange, &aForwarder ); 131 pTemp->GetDocument()->GetLinkManager()->RemoveServer( this ); 132 EndListening(*pTemp); 133 EndListening(*SFX_APP()); 134 } 135 } 136 137 void ScServerObject::EndListeningAll() 138 { 139 aForwarder.EndListeningAll(); 140 SfxListener::EndListeningAll(); 141 } 142 143 sal_Bool __EXPORT ScServerObject::GetData( 144 ::com::sun::star::uno::Any & rData /*out param*/, 145 const String & rMimeType, sal_Bool /* bSynchron */ ) 146 { 147 if (!pDocSh) 148 return sal_False; 149 150 // named ranges may have changed -> update aRange 151 if ( aItemStr.Len() ) 152 { 153 ScRange aNew; 154 if ( lcl_FillRangeFromName( aNew, pDocSh, aItemStr ) && aNew != aRange ) 155 { 156 aRange = aNew; 157 bRefreshListener = sal_True; 158 } 159 } 160 161 if ( bRefreshListener ) 162 { 163 // refresh the listeners now (this is called from a timer) 164 165 EndListeningAll(); 166 pDocSh->GetDocument()->StartListeningArea( aRange, &aForwarder ); 167 StartListening(*pDocSh); 168 StartListening(*SFX_APP()); 169 bRefreshListener = sal_False; 170 } 171 172 String aDdeTextFmt = pDocSh->GetDdeTextFmt(); 173 ScDocument* pDoc = pDocSh->GetDocument(); 174 175 if( FORMAT_STRING == SotExchange::GetFormatIdFromMimeType( rMimeType )) 176 { 177 ScImportExport aObj( pDoc, aRange ); 178 if( aDdeTextFmt.GetChar(0) == 'F' ) 179 aObj.SetFormulas( sal_True ); 180 if( aDdeTextFmt.EqualsAscii( "SYLK" ) || 181 aDdeTextFmt.EqualsAscii( "FSYLK" ) ) 182 { 183 ByteString aByteData; 184 if( aObj.ExportByteString( aByteData, gsl_getSystemTextEncoding(), SOT_FORMATSTR_ID_SYLK ) ) 185 { 186 rData <<= ::com::sun::star::uno::Sequence< sal_Int8 >( 187 (sal_Int8*)aByteData.GetBuffer(), 188 aByteData.Len() + 1 ); 189 return 1; 190 } 191 return 0; 192 } 193 if( aDdeTextFmt.EqualsAscii( "CSV" ) || 194 aDdeTextFmt.EqualsAscii( "FCSV" ) ) 195 aObj.SetSeparator( ',' ); 196 aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) ); 197 return aObj.ExportData( rMimeType, rData ) ? 1 : 0; 198 } 199 200 ScImportExport aObj( pDoc, aRange ); 201 aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) ); 202 if( aObj.IsRef() ) 203 return aObj.ExportData( rMimeType, rData ) ? 1 : 0; 204 return 0; 205 } 206 207 void __EXPORT ScServerObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) 208 { 209 sal_Bool bDataChanged = sal_False; 210 211 // DocShell can't be tested via type info, because SFX_HINT_DYING comes from the dtor 212 if ( &rBC == pDocSh ) 213 { 214 // from DocShell, only SFX_HINT_DYING is interesting 215 if ( rHint.ISA(SfxSimpleHint) && ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING ) 216 { 217 pDocSh = NULL; 218 EndListening(*SFX_APP()); 219 // don't access DocShell anymore for EndListening etc. 220 } 221 } 222 else if (rBC.ISA(SfxApplication)) 223 { 224 if ( aItemStr.Len() && rHint.ISA(SfxSimpleHint) && 225 ((const SfxSimpleHint&)rHint).GetId() == SC_HINT_AREAS_CHANGED ) 226 { 227 // check if named range was modified 228 ScRange aNew; 229 if ( lcl_FillRangeFromName( aNew, pDocSh, aItemStr ) && aNew != aRange ) 230 bDataChanged = sal_True; 231 } 232 } 233 else 234 { 235 // must be from Area broadcasters 236 237 const ScHint* pScHint = PTR_CAST( ScHint, &rHint ); 238 if( pScHint && (pScHint->GetId() & (SC_HINT_DATACHANGED | SC_HINT_DYING)) ) 239 bDataChanged = sal_True; 240 else if (rHint.ISA(ScAreaChangedHint)) // position of broadcaster changed 241 { 242 ScRange aNewRange = ((const ScAreaChangedHint&)rHint).GetRange(); 243 if ( aRange != aNewRange ) 244 { 245 bRefreshListener = sal_True; 246 bDataChanged = sal_True; 247 } 248 } 249 else if (rHint.ISA(SfxSimpleHint)) 250 { 251 sal_uLong nId = ((const SfxSimpleHint&)rHint).GetId(); 252 if (nId == SFX_HINT_DYING) 253 { 254 // If the range is being deleted, listening must be restarted 255 // after the deletion is complete (done in GetData) 256 bRefreshListener = sal_True; 257 bDataChanged = sal_True; 258 } 259 } 260 } 261 262 if ( bDataChanged && HasDataLinks() ) 263 SvLinkSource::NotifyDataChanged(); 264 } 265 266 267 268 269 270