1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 #include "vbafield.hxx" 28 #include "vbarange.hxx" 29 #include <com/sun/star/frame/XModel.hpp> 30 #include <com/sun/star/text/XTextViewCursorSupplier.hpp> 31 #include <com/sun/star/view/XSelectionSupplier.hpp> 32 #include <com/sun/star/text/XTextFieldsSupplier.hpp> 33 #include <ooo/vba/word/WdFieldType.hpp> 34 #include <com/sun/star/text/FilenameDisplayFormat.hpp> 35 #include <com/sun/star/util/XRefreshable.hpp> 36 #include <swtypes.hxx> 37 38 using namespace ::ooo::vba; 39 using namespace ::com::sun::star; 40 41 // *** SwVbaField *********************************************** 42 43 SwVbaField::SwVbaField( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const css::uno::Reference< css::text::XTextDocument >& rDocument, const uno::Reference< css::text::XTextField >& xTextField) throw ( uno::RuntimeException ) : SwVbaField_BASE( rParent, rContext ), mxTextDocument( rDocument ) 44 { 45 mxTextField.set( xTextField, uno::UNO_QUERY_THROW ); 46 } 47 48 // XHelperInterface 49 rtl::OUString& 50 SwVbaField::getServiceImplName() 51 { 52 static rtl::OUString sImplName( RTL_CONSTASCII_USTRINGPARAM("SwVbaField") ); 53 return sImplName; 54 } 55 56 uno::Sequence<rtl::OUString> 57 SwVbaField::getServiceNames() 58 { 59 static uno::Sequence< rtl::OUString > aServiceNames; 60 if ( aServiceNames.getLength() == 0 ) 61 { 62 aServiceNames.realloc( 1 ); 63 aServiceNames[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.word.Field" ) ); 64 } 65 return aServiceNames; 66 } 67 68 // *** _ReadFieldParams *********************************************** 69 // the codes are copied from ww8par5.cxx 70 class _ReadFieldParams 71 { 72 private: 73 String aData; 74 xub_StrLen nLen, nFnd, nNext, nSavPtr; 75 String aFieldName; 76 public: 77 _ReadFieldParams( const String& rData ); 78 ~_ReadFieldParams(); 79 80 xub_StrLen GoToTokenParam(); 81 long SkipToNextToken(); 82 xub_StrLen GetTokenSttPtr() const { return nFnd; } 83 84 xub_StrLen FindNextStringPiece( xub_StrLen _nStart = STRING_NOTFOUND ); 85 bool GetTokenSttFromTo(xub_StrLen* _pFrom, xub_StrLen* _pTo, 86 xub_StrLen _nMax); 87 88 String GetResult() const; 89 String GetFieldName()const { return aFieldName; } 90 }; 91 92 93 _ReadFieldParams::_ReadFieldParams( const String& _rData ) 94 : aData( _rData ), nLen( _rData.Len() ), nNext( 0 ) 95 { 96 /* 97 erstmal nach einer oeffnenden Klammer oder einer Leerstelle oder einem 98 Anfuehrungszeichen oder einem Backslash suchen, damit der Feldbefehl 99 (also INCLUDEPICTURE bzw EINFUeGENGRAFIK bzw ...) ueberlesen wird 100 */ 101 while( (nLen > nNext) && (aData.GetChar( nNext ) == ' ') ) 102 ++nNext; 103 104 sal_Unicode c; 105 while( nLen > nNext 106 && (c = aData.GetChar( nNext )) != ' ' 107 && c != '"' 108 && c != '\\' 109 && c != 132 110 && c != 0x201c ) 111 ++nNext; 112 113 nFnd = nNext; 114 nSavPtr = nNext; 115 aFieldName = aData.Copy( 0, nFnd ); 116 // cLastChar = aData.GetChar( nSavPtr ); 117 } 118 119 120 _ReadFieldParams::~_ReadFieldParams() 121 { 122 // aData.SetChar( nSavPtr, cLastChar ); 123 } 124 125 126 String _ReadFieldParams::GetResult() const 127 { 128 return (STRING_NOTFOUND == nFnd) 129 ? aEmptyStr 130 : aData.Copy( nFnd, (nSavPtr - nFnd) ); 131 } 132 133 134 xub_StrLen _ReadFieldParams::GoToTokenParam() 135 { 136 xub_StrLen nOld = nNext; 137 if( -2 == SkipToNextToken() ) 138 return GetTokenSttPtr(); 139 nNext = nOld; 140 return STRING_NOTFOUND; 141 } 142 143 // ret: -2: NOT a '\' parameter but normal Text 144 long _ReadFieldParams::SkipToNextToken() 145 { 146 long nRet = -1; // Ende 147 if ( 148 (STRING_NOTFOUND != nNext) && (nLen > nNext) && 149 STRING_NOTFOUND != (nFnd = FindNextStringPiece(nNext)) 150 ) 151 { 152 nSavPtr = nNext; 153 154 if ('\\' == aData.GetChar(nFnd) && '\\' != aData.GetChar(nFnd + 1)) 155 { 156 nRet = aData.GetChar(++nFnd); 157 nNext = ++nFnd; // und dahinter setzen 158 } 159 else 160 { 161 nRet = -2; 162 if ( 163 (STRING_NOTFOUND != nSavPtr ) && 164 ( 165 ('"' == aData.GetChar(nSavPtr - 1)) || 166 (0x201d == aData.GetChar(nSavPtr - 1)) 167 ) 168 ) 169 { 170 --nSavPtr; 171 } 172 } 173 } 174 return nRet; 175 } 176 177 // FindNextPara sucht naechsten Backslash-Parameter oder naechste Zeichenkette 178 // bis zum Blank oder naechsten "\" oder zum schliessenden Anfuehrungszeichen 179 // oder zum String-Ende von pStr. 180 // 181 // Ausgabe ppNext (falls ppNext != 0) Suchbeginn fuer naechsten Parameter bzw. 0 182 // 183 // Returnwert: 0 falls String-Ende erreicht, 184 // ansonsten Anfang des Paramters bzw. der Zeichenkette 185 // 186 xub_StrLen _ReadFieldParams::FindNextStringPiece(const xub_StrLen nStart) 187 { 188 xub_StrLen n = ( STRING_NOTFOUND == nStart ) ? nFnd : nStart; // Anfang 189 xub_StrLen n2; // Ende 190 191 nNext = STRING_NOTFOUND; // Default fuer nicht gefunden 192 193 while( (nLen > n) && (aData.GetChar( n ) == ' ') ) 194 ++n; 195 196 if( nLen == n ) 197 return STRING_NOTFOUND; // String End reached! 198 199 if( (aData.GetChar( n ) == '"') // Anfuehrungszeichen vor Para? 200 || (aData.GetChar( n ) == 0x201c) 201 || (aData.GetChar( n ) == 132) ) 202 { 203 n++; // Anfuehrungszeichen ueberlesen 204 n2 = n; // ab hier nach Ende suchen 205 while( (nLen > n2) 206 && (aData.GetChar( n2 ) != '"') 207 && (aData.GetChar( n2 ) != 0x201d) 208 && (aData.GetChar( n2 ) != 147) ) 209 n2++; // Ende d. Paras suchen 210 } 211 else // keine Anfuehrungszeichen 212 { 213 n2 = n; // ab hier nach Ende suchen 214 while( (nLen > n2) && (aData.GetChar( n2 ) != ' ') ) // Ende d. Paras suchen 215 { 216 if( aData.GetChar( n2 ) == '\\' ) 217 { 218 if( aData.GetChar( n2+1 ) == '\\' ) 219 n2 += 2; // Doppel-Backslash -> OK 220 else 221 { 222 if( n2 > n ) 223 n2--; 224 break; // einfach-Backslash -> Ende 225 } 226 } 227 else 228 n2++; // kein Backslash -> OK 229 } 230 } 231 if( nLen > n2 ) 232 { 233 if(aData.GetChar( n2 ) != ' ') n2++; 234 nNext = n2; 235 } 236 return n; 237 } 238 239 240 241 // read parameters "1-3" or 1-3 with both values between 1 and nMax 242 bool _ReadFieldParams::GetTokenSttFromTo(sal_uInt16* pFrom, sal_uInt16* pTo, sal_uInt16 nMax) 243 { 244 sal_uInt16 nStart = 0; 245 sal_uInt16 nEnd = 0; 246 xub_StrLen n = GoToTokenParam(); 247 if( STRING_NOTFOUND != n ) 248 { 249 250 String sParams( GetResult() ); 251 252 xub_StrLen nIndex = 0; 253 String sStart( sParams.GetToken(0, '-', nIndex) ); 254 if( STRING_NOTFOUND != nIndex ) 255 { 256 nStart = static_cast<sal_uInt16>(sStart.ToInt32()); 257 nEnd = static_cast<sal_uInt16>(sParams.Copy(nIndex).ToInt32()); 258 } 259 } 260 if( pFrom ) *pFrom = nStart; 261 if( pTo ) *pTo = nEnd; 262 263 return nStart && nEnd && (nMax >= nStart) && (nMax >= nEnd); 264 } 265 266 // *** SwVbaFields *********************************************** 267 268 uno::Any lcl_createField( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xModel, const uno::Any& aSource ) 269 { 270 uno::Reference< text::XTextField > xTextField( aSource, uno::UNO_QUERY_THROW ); 271 uno::Reference< text::XTextDocument > xTextDocument( xModel, uno::UNO_QUERY_THROW ); 272 uno::Reference< word::XField > xField( new SwVbaField( xParent, xContext, xTextDocument, xTextField ) ); 273 return uno::makeAny( xField ); 274 } 275 276 typedef ::cppu::WeakImplHelper1< css::container::XEnumeration > FieldEnumeration_BASE; 277 typedef ::cppu::WeakImplHelper2< container::XIndexAccess, container::XEnumerationAccess > FieldCollectionHelper_BASE; 278 279 class FieldEnumeration : public FieldEnumeration_BASE 280 { 281 uno::Reference< XHelperInterface > mxParent; 282 uno::Reference< uno::XComponentContext > mxContext; 283 uno::Reference< frame::XModel > mxModel; 284 uno::Reference< container::XEnumeration > mxEnumeration; 285 public: 286 FieldEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel, const uno::Reference< container::XEnumeration >& xEnumeration ) : mxParent( xParent ), mxContext( xContext ), mxModel( xModel ), mxEnumeration( xEnumeration ) 287 { 288 } 289 virtual ::sal_Bool SAL_CALL hasMoreElements( ) throw (uno::RuntimeException) 290 { 291 return mxEnumeration->hasMoreElements(); 292 } 293 virtual uno::Any SAL_CALL nextElement( ) throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException) 294 { 295 if ( !hasMoreElements() ) 296 throw container::NoSuchElementException(); 297 return lcl_createField( mxParent, mxContext, mxModel, mxEnumeration->nextElement() ); 298 } 299 }; 300 301 class FieldCollectionHelper : public FieldCollectionHelper_BASE 302 { 303 uno::Reference< XHelperInterface > mxParent; 304 uno::Reference< uno::XComponentContext > mxContext; 305 uno::Reference< frame::XModel > mxModel; 306 uno::Reference< container::XEnumerationAccess > mxEnumerationAccess; 307 public: 308 FieldCollectionHelper( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xModel ) throw (css::uno::RuntimeException) : mxParent( xParent ), mxContext( xContext ), mxModel( xModel ) 309 { 310 uno::Reference< text::XTextFieldsSupplier > xSupp( xModel, uno::UNO_QUERY_THROW ); 311 mxEnumerationAccess.set( xSupp->getTextFields(), uno::UNO_QUERY_THROW ); 312 } 313 // XElementAccess 314 virtual uno::Type SAL_CALL getElementType( ) throw (uno::RuntimeException) { return mxEnumerationAccess->getElementType(); } 315 virtual ::sal_Bool SAL_CALL hasElements( ) throw (uno::RuntimeException) { return mxEnumerationAccess->hasElements(); } 316 // XIndexAccess 317 virtual ::sal_Int32 SAL_CALL getCount( ) throw (uno::RuntimeException) 318 { 319 uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration(); 320 sal_Int32 nCount = 0; 321 while( xEnumeration->hasMoreElements() ) 322 { 323 ++nCount; 324 xEnumeration->nextElement(); 325 } 326 return nCount; 327 } 328 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException ) 329 { 330 if( Index < 0 || Index >= getCount() ) 331 throw lang::IndexOutOfBoundsException(); 332 333 uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration(); 334 sal_Int32 nCount = 0; 335 while( xEnumeration->hasMoreElements() ) 336 { 337 if( nCount == Index ) 338 { 339 return xEnumeration->nextElement(); 340 } 341 ++nCount; 342 } 343 throw lang::IndexOutOfBoundsException(); 344 } 345 // XEnumerationAccess 346 virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) throw (uno::RuntimeException) 347 { 348 uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration(); 349 return uno::Reference< container::XEnumeration >( new FieldEnumeration( mxParent, mxContext, mxModel, xEnumeration ) ); 350 } 351 }; 352 353 SwVbaFields::SwVbaFields( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel ) : SwVbaFields_BASE( xParent, xContext , uno::Reference< container::XIndexAccess >( new FieldCollectionHelper( xParent, xContext, xModel ) ) ), mxModel( xModel ) 354 { 355 mxMSF.set( mxModel, uno::UNO_QUERY_THROW ); 356 } 357 358 uno::Reference< word::XField > SAL_CALL 359 SwVbaFields::Add( const css::uno::Reference< ::ooo::vba::word::XRange >& Range, const css::uno::Any& Type, const css::uno::Any& Text, const css::uno::Any& /*PreserveFormatting*/ ) throw (css::uno::RuntimeException) 360 { 361 sal_Int32 nType = word::WdFieldType::wdFieldEmpty; 362 Type >>= nType; 363 rtl::OUString sText; 364 Text >>= sText; 365 366 String sFieldName; 367 if( ( nType == word::WdFieldType::wdFieldEmpty ) && ( sText.getLength() > 0 ) ) 368 { 369 _ReadFieldParams aReadParam(sText); 370 sFieldName = aReadParam.GetFieldName(); 371 } 372 373 uno::Reference< text::XTextContent > xTextField; 374 if( nType == word::WdFieldType::wdFieldFileName || sFieldName.EqualsIgnoreCaseAscii("FILENAME") ) 375 { 376 xTextField.set( Create_Field_FileName( sText ), uno::UNO_QUERY_THROW ); 377 } 378 else 379 { 380 throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Not implemented") ), uno::Reference< uno::XInterface >() ); 381 } 382 383 SwVbaRange* pVbaRange = dynamic_cast< SwVbaRange* >( Range.get() ); 384 uno::Reference< text::XTextRange > xTextRange = pVbaRange->getXTextRange(); 385 uno::Reference< text::XText > xText = xTextRange->getText(); 386 xText->insertTextContent( xTextRange, xTextField, true ); 387 return uno::Reference< word::XField >( new SwVbaField( mxParent, mxContext, uno::Reference< text::XTextDocument >( mxModel, uno::UNO_QUERY_THROW ), uno::Reference< text::XTextField >( xTextField, uno::UNO_QUERY_THROW ) ) ); 388 } 389 390 uno::Reference< text::XTextField > SwVbaFields::Create_Field_FileName( const rtl::OUString _text ) throw (uno::RuntimeException) 391 { 392 uno::Reference< text::XTextField > xTextField( mxMSF->createInstance( rtl::OUString::createFromAscii("com.sun.star.text.TextField.FileName") ), uno::UNO_QUERY_THROW ); 393 sal_Int16 nFileFormat = text::FilenameDisplayFormat::NAME_AND_EXT; 394 if( _text.getLength() > 0 ) 395 { 396 long nRet; 397 _ReadFieldParams aReadParam( _text ); 398 while (-1 != (nRet = aReadParam.SkipToNextToken())) 399 { 400 switch (nRet) 401 { 402 case 'p': 403 nFileFormat = text::FilenameDisplayFormat::FULL; 404 break; 405 case '*': 406 //Skip over MERGEFORMAT 407 aReadParam.SkipToNextToken(); 408 break; 409 default: 410 DebugHelper::exception(SbERR_BAD_ARGUMENT, rtl::OUString()); 411 break; 412 } 413 } 414 } 415 416 uno::Reference< beans::XPropertySet > xProps( xTextField, uno::UNO_QUERY_THROW ); 417 xProps->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("FileFormat") ), uno::makeAny( nFileFormat ) ); 418 419 return xTextField; 420 } 421 422 uno::Reference< container::XEnumeration > SAL_CALL 423 SwVbaFields::createEnumeration() throw (uno::RuntimeException) 424 { 425 uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); 426 return xEnumerationAccess->createEnumeration(); 427 } 428 429 // ScVbaCollectionBaseImpl 430 uno::Any 431 SwVbaFields::createCollectionObject( const uno::Any& aSource ) 432 { 433 return lcl_createField( mxParent, mxContext, mxModel, aSource ); 434 } 435 436 sal_Int32 SAL_CALL SwVbaFields::Update() throw (uno::RuntimeException) 437 { 438 sal_Int32 nUpdate = 1; 439 try 440 { 441 uno::Reference< text::XTextFieldsSupplier > xSupp( mxModel, uno::UNO_QUERY_THROW ); 442 uno::Reference< util::XRefreshable > xRef( xSupp->getTextFields(), uno::UNO_QUERY_THROW ); 443 xRef->refresh(); 444 nUpdate = 0; 445 }catch( uno::Exception ) 446 { 447 nUpdate = 1; 448 } 449 return nUpdate; 450 } 451 452 // XHelperInterface 453 rtl::OUString& 454 SwVbaFields::getServiceImplName() 455 { 456 static rtl::OUString sImplName( RTL_CONSTASCII_USTRINGPARAM("SwVbaFields") ); 457 return sImplName; 458 } 459 460 // XEnumerationAccess 461 uno::Type SAL_CALL 462 SwVbaFields::getElementType() throw (uno::RuntimeException) 463 { 464 return word::XField::static_type(0); 465 } 466 467 uno::Sequence<rtl::OUString> 468 SwVbaFields::getServiceNames() 469 { 470 static uno::Sequence< rtl::OUString > aServiceNames; 471 if ( aServiceNames.getLength() == 0 ) 472 { 473 aServiceNames.realloc( 1 ); 474 aServiceNames[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.word.Fields" ) ); 475 } 476 return aServiceNames; 477 } 478 479