xref: /aoo41x/main/sw/source/ui/vba/vbafield.cxx (revision cdf0e10c)
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