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