LibreOffice Module sw (master) 1
vbafield.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19#include "vbafield.hxx"
20#include "vbarange.hxx"
21#include <com/sun/star/beans/XPropertySet.hpp>
22#include <com/sun/star/frame/XModel.hpp>
23#include <com/sun/star/text/XTextFieldsSupplier.hpp>
24#include <com/sun/star/text/FilenameDisplayFormat.hpp>
25#include <com/sun/star/util/XRefreshable.hpp>
26#include <com/sun/star/util/XUpdatable.hpp>
27#include <ooo/vba/word/WdFieldType.hpp>
28#include <basic/sberrors.hxx>
30#include <sal/log.hxx>
31#include <tools/long.hxx>
32#include <utility>
33
34using namespace ::ooo::vba;
35using namespace ::com::sun::star;
36
37SwVbaField::SwVbaField( const uno::Reference< ooo::vba::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Reference< css::text::XTextField >& xTextField) : SwVbaField_BASE( rParent, rContext )
38{
39 mxTextField.set( xTextField, uno::UNO_SET_THROW );
40}
41
43{
44 uno::Reference< util::XUpdatable > xUpdatable( mxTextField, uno::UNO_QUERY );
45 if( xUpdatable.is() )
46 {
47 xUpdatable->update();
48 return true;
49 }
50 return false;
51}
52
53// XHelperInterface
54OUString
56{
57 return "SwVbaField";
58}
59
60uno::Sequence<OUString>
62{
63 static uno::Sequence< OUString > const aServiceNames
64 {
65 "ooo.vba.word.Field"
66 };
67 return aServiceNames;
68}
69
70namespace {
71
72// FIXME? copy and paste code
73// the codes are copied from ww8par5.cxx
74class SwVbaReadFieldParams
75{
76private:
77 OUString m_aData;
78 sal_Int32 m_nLen, m_nFnd, m_nNext, m_nSavPtr;
79 OUString m_aFieldName;
80public:
81 explicit SwVbaReadFieldParams( const OUString& rData );
82
83 tools::Long SkipToNextToken();
84
85 sal_Int32 FindNextStringPiece( sal_Int32 _nStart );
86
87 OUString GetResult() const;
88 const OUString& GetFieldName()const { return m_aFieldName; }
89};
90
91}
92
93SwVbaReadFieldParams::SwVbaReadFieldParams( const OUString& _rData )
94 : m_aData( _rData ), m_nLen( _rData.getLength() ), m_nNext( 0 )
95{
96 // First search for an opening parenthesis or a space or a quotation mark
97 // or a backslash, so that the field command
98 // (thus INCLUDEPICTURE or ...) is ignored.
99 while( (m_nLen > m_nNext) && (m_aData[ m_nNext ] == ' ') )
100 ++m_nNext;
101
102 sal_Unicode c;
103 while( m_nLen > m_nNext
104 && (c = m_aData[ m_nNext ]) != ' '
105 && c != '"'
106 && c != '\\'
107 && c != 132
108 && c != 0x201c )
109 ++m_nNext;
110
111 m_nFnd = m_nNext;
112 m_nSavPtr = m_nNext;
113 m_aFieldName = m_aData.copy( 0, m_nFnd );
114}
115
116OUString SwVbaReadFieldParams::GetResult() const
117{
118 return (-1 == m_nFnd)
119 ? OUString()
120 : m_aData.copy( m_nFnd, (m_nSavPtr - m_nFnd) );
121}
122
123// ret: -2: NOT a '\' parameter but normal Text
124tools::Long SwVbaReadFieldParams::SkipToNextToken()
125{
126 tools::Long nRet = -1; // end
127 if (
128 (-1 != m_nNext) && (m_nLen > m_nNext) &&
129 -1 != (m_nFnd = FindNextStringPiece(m_nNext))
130 )
131 {
132 m_nSavPtr = m_nNext;
133
134 if ('\\' == m_aData[m_nFnd] && '\\' != m_aData[m_nFnd + 1])
135 {
136 nRet = m_aData[++m_nFnd];
137 m_nNext = ++m_nFnd; // and set behind
138 }
139 else
140 {
141 nRet = -2;
142 if (
143 (-1 != m_nSavPtr ) &&
144 (
145 ('"' == m_aData[m_nSavPtr - 1]) ||
146 (0x201d == m_aData[m_nSavPtr - 1])
147 )
148 )
149 {
150 --m_nSavPtr;
151 }
152 }
153 }
154 return nRet;
155}
156
157// FindNextPara is searching for the next Backslash-Parameter or the next string
158// until blank or the next "\" or until the closing quotation mark
159// or until the string end of pStr.
160
161// Output ppNext (if ppNext != 0) beginning of the search for the next parameter or 0
162
163// Return value: 0 if String-End reached, otherwise begin of the parameter or the string
164
165sal_Int32 SwVbaReadFieldParams::FindNextStringPiece(const sal_Int32 nStart)
166{
167 sal_Int32 n = ( -1 == nStart ) ? m_nFnd : nStart; // Start
168 sal_Int32 n2; // End
169
170 m_nNext = -1; // Default for not found
171
172 while( (m_nLen > n) && (m_aData[ n ] == ' ') )
173 ++n;
174
175 if( m_nLen == n )
176 return -1; // String End reached!
177
178 if( (m_aData[ n ] == '"') // quotation marks are in front of parenthesis?
179 || (m_aData[ n ] == 0x201c)
180 || (m_aData[ n ] == 132) )
181 {
182 n++; // ignore quotation marks
183 n2 = n; // From here search for the end
184 while( (m_nLen > n2)
185 && (m_aData[ n2 ] != '"')
186 && (m_aData[ n2 ] != 0x201d)
187 && (m_aData[ n2 ] != 147) )
188 n2++; // Search for the end of the parenthesis
189 }
190 else // no quotation marks
191 {
192 n2 = n; // from here search for the end
193 while( (m_nLen > n2) && (m_aData[ n2 ] != ' ') ) // Search for the end of the parenthesis
194 {
195 if( m_aData[ n2 ] == '\\' )
196 {
197 if( m_aData[ n2+1 ] == '\\' )
198 n2 += 2; // double-backslash -> OK
199 else
200 {
201 if( n2 > n )
202 n2--;
203 break; // single-backslash -> End
204 }
205 }
206 else
207 n2++; // no backslash -> OK
208 }
209 }
210 if( m_nLen > n2 )
211 {
212 if(m_aData[ n2 ] != ' ') n2++;
213 m_nNext = n2;
214 }
215 return n;
216}
217
218// SwVbaFields
219
220static 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 )
221{
222 uno::Reference< text::XTextField > xTextField( aSource, uno::UNO_QUERY_THROW );
223 uno::Reference< text::XTextDocument > xTextDocument( xModel, uno::UNO_QUERY_THROW );
224 uno::Reference< word::XField > xField( new SwVbaField( xParent, xContext, xTextField ) );
225 return uno::Any( xField );
226}
227
228namespace {
229
230class FieldEnumeration : public ::cppu::WeakImplHelper< css::container::XEnumeration >
231{
232 uno::Reference< XHelperInterface > mxParent;
233 uno::Reference< uno::XComponentContext > mxContext;
234 uno::Reference< frame::XModel > mxModel;
235 uno::Reference< container::XEnumeration > mxEnumeration;
236public:
237 FieldEnumeration( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, uno::Reference< frame::XModel > xModel, uno::Reference< container::XEnumeration > xEnumeration ) : mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxModel(std::move( xModel )), mxEnumeration(std::move( xEnumeration ))
238 {
239 }
240 virtual sal_Bool SAL_CALL hasMoreElements( ) override
241 {
242 return mxEnumeration->hasMoreElements();
243 }
244 virtual uno::Any SAL_CALL nextElement( ) override
245 {
246 if ( !hasMoreElements() )
247 throw container::NoSuchElementException();
248 return lcl_createField( mxParent, mxContext, mxModel, mxEnumeration->nextElement() );
249 }
250};
251
252class FieldCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess,
253 container::XEnumerationAccess >
254{
255 uno::Reference< XHelperInterface > mxParent;
256 uno::Reference< uno::XComponentContext > mxContext;
257 uno::Reference< frame::XModel > mxModel;
258 uno::Reference< container::XEnumerationAccess > mxEnumerationAccess;
259public:
261 FieldCollectionHelper( uno::Reference< XHelperInterface > xParent, uno::Reference< uno::XComponentContext > xContext, const uno::Reference< frame::XModel >& xModel ) : mxParent(std::move( xParent )), mxContext(std::move( xContext )), mxModel( xModel )
262 {
263 uno::Reference< text::XTextFieldsSupplier > xSupp( xModel, uno::UNO_QUERY_THROW );
264 mxEnumerationAccess.set( xSupp->getTextFields(), uno::UNO_SET_THROW );
265 }
266 // XElementAccess
267 virtual uno::Type SAL_CALL getElementType( ) override { return mxEnumerationAccess->getElementType(); }
268 virtual sal_Bool SAL_CALL hasElements( ) override { return mxEnumerationAccess->hasElements(); }
269 // XIndexAccess
270 virtual ::sal_Int32 SAL_CALL getCount( ) override
271 {
272 uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration();
273 sal_Int32 nCount = 0;
274 while( xEnumeration->hasMoreElements() )
275 {
276 ++nCount;
277 xEnumeration->nextElement();
278 }
279 return nCount;
280 }
281 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
282 {
283 if( Index < 0 || Index >= getCount() )
284 throw lang::IndexOutOfBoundsException();
285
286 uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration();
287 sal_Int32 nCount = 0;
288 while( xEnumeration->hasMoreElements() )
289 {
290 if( nCount == Index )
291 {
292 return xEnumeration->nextElement();
293 }
294 ++nCount;
295 }
296 throw lang::IndexOutOfBoundsException();
297 }
298 // XEnumerationAccess
299 virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override
300 {
301 uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration();
302 return uno::Reference< container::XEnumeration >( new FieldEnumeration( mxParent, mxContext, mxModel, xEnumeration ) );
303 }
304};
305
306}
307
308SwVbaFields::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 )
309{
310 mxMSF.set( mxModel, uno::UNO_QUERY_THROW );
311}
312
313uno::Reference< word::XField > SAL_CALL
314SwVbaFields::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*/ )
315{
316 sal_Int32 nType = word::WdFieldType::wdFieldEmpty;
317 Type >>= nType;
318 OUString sText;
319 Text >>= sText;
320
321 OUString sFieldName;
322 if( ( nType == word::WdFieldType::wdFieldEmpty ) && !sText.isEmpty() )
323 {
324 SwVbaReadFieldParams aReadParam(sText);
325 sFieldName = aReadParam.GetFieldName();
326 SAL_INFO("sw.vba", "the field name is " << sFieldName );
327 }
328
329 uno::Reference< text::XTextContent > xTextField;
330 if( nType == word::WdFieldType::wdFieldFileName || sFieldName.equalsIgnoreAsciiCase("FILENAME") )
331 {
332 xTextField.set( Create_Field_FileName( sText ), uno::UNO_QUERY_THROW );
333 }
334 else if( nType == word::WdFieldType::wdFieldDocProperty || sFieldName.equalsIgnoreAsciiCase("DOCPROPERTY") )
335 {
336 xTextField.set( Create_Field_DocProperty( sText ), uno::UNO_QUERY_THROW );
337 }
338 else
339 {
340 throw uno::RuntimeException("Not implemented" );
341 }
342
343 SwVbaRange& rVbaRange = dynamic_cast<SwVbaRange&>(*Range);
344 uno::Reference< text::XTextRange > xTextRange = rVbaRange.getXTextRange();
345 uno::Reference< text::XText > xText = xTextRange->getText();
346 xText->insertTextContent( xTextRange, xTextField, true );
347 return uno::Reference< word::XField >( new SwVbaField( mxParent, mxContext, uno::Reference< text::XTextField >( xTextField, uno::UNO_QUERY_THROW ) ) );
348}
349
350uno::Reference< text::XTextField > SwVbaFields::Create_Field_FileName( const OUString& _text )
351{
352 uno::Reference< text::XTextField > xTextField( mxMSF->createInstance("com.sun.star.text.TextField.FileName"), uno::UNO_QUERY_THROW );
353 sal_Int16 nFileFormat = text::FilenameDisplayFormat::NAME_AND_EXT;
354 if( !_text.isEmpty() )
355 {
356 tools::Long nRet;
357 SwVbaReadFieldParams aReadParam( _text );
358 while (-1 != (nRet = aReadParam.SkipToNextToken()))
359 {
360 switch (nRet)
361 {
362 case 'p':
363 nFileFormat = text::FilenameDisplayFormat::FULL;
364 break;
365 case '*':
366 //Skip over MERGEFORMAT
367 aReadParam.SkipToNextToken();
368 break;
369 default:
370 DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {});
371 break;
372 }
373 }
374 }
375
376 uno::Reference< beans::XPropertySet > xProps( xTextField, uno::UNO_QUERY_THROW );
377 xProps->setPropertyValue("FileFormat", uno::Any( nFileFormat ) );
378
379 return xTextField;
380}
381
382namespace {
383
384struct DocPropertyTable
385{
386 const char* sDocPropertyName;
387 const char* sFieldService;
388};
389
390}
391
392const DocPropertyTable aDocPropertyTables[] =
393{
394 { "Author", "com.sun.star.text.textfield.docinfo.CreateAuthor" },
395 { "Bytes", nullptr },
396 { "Category", nullptr },
397 { "Characters",nullptr },
398 { "CharactersWithSpaces", nullptr },
399 { "Comments", "com.sun.star.text.textfield.docinfo.Description" },
400 { "Company", nullptr },
401 { "CreateTime", "com.sun.star.text.textfield.docinfo.CreateDateTime" },
402 { "HyperlinkBase", nullptr },
403 { "Keywords", "com.sun.star.text.textfield.docinfo.Keywords" },
404 { "LastPrinted", "com.sun.star.text.textfield.docinfo.PrintDateTime" },
405 { "LastSavedBy", "com.sun.star.text.textfield.docinfo.ChangeAuthor" },
406 { "LastSavedTime", "com.sun.star.text.textfield.docinfo.ChangeDateTime" },
407 { "Lines", nullptr },
408 { "Manager", nullptr },
409 { "NameofApplication", nullptr },
410 { "ODMADocID", nullptr },
411 { "Pages", "com.sun.star.text.textfield.PageCount" },
412 { "Paragraphs", "com.sun.star.text.textfield.ParagraphCount" },
413 { "RevisionNumber", "com.sun.star.text.textfield.docinfo.Revision" },
414 { "Security", nullptr },
415 { "Subject", "com.sun.star.text.textfield.docinfo.Subject" },
416 { "Template", "com.sun.star.text.textfield.TemplateName" },
417 { "Title", "com.sun.star.text.textfield.docinfo.Title" },
418 { "TotalEditingTime", "com.sun.star.text.textfield.docinfo.EditTime" },
419 { "Words", "com.sun.star.text.textfield.WordCount" },
420 { nullptr, nullptr }
421};
422
423uno::Reference< text::XTextField > SwVbaFields::Create_Field_DocProperty( const OUString& _text )
424{
425 OUString aDocProperty;
426 SwVbaReadFieldParams aReadParam( _text );
427 tools::Long nRet;
428 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
429 {
430 switch( nRet )
431 {
432 case -2:
433 if( aDocProperty.isEmpty() )
434 aDocProperty = aReadParam.GetResult();
435 break;
436 case '*':
437 //Skip over MERGEFORMAT
438 aReadParam.SkipToNextToken();
439 break;
440 }
441 }
442 aDocProperty = aDocProperty.replaceAll("\"", "");
443 SAL_INFO("sw.vba", "SwVbaFields::Create_Field_DocProperty, the document property name is " << aDocProperty );
444 if( aDocProperty.isEmpty() )
445 {
446 throw uno::RuntimeException();
447 }
448
449 bool bCustom = true;
450 OUString sFieldService;
451 // find the build in document properties
452 for( const DocPropertyTable* pTable = aDocPropertyTables; pTable->sDocPropertyName != nullptr; pTable++ )
453 {
454 if( aDocProperty.equalsIgnoreAsciiCaseAscii( pTable->sDocPropertyName ) )
455 {
456 if( pTable->sFieldService != nullptr )
457 sFieldService = OUString::createFromAscii(pTable->sFieldService);
458 bCustom = false;
459 break;
460 }
461 }
462
463 if( bCustom )
464 {
465 sFieldService = "com.sun.star.text.textfield.docinfo.Custom";
466 }
467 else if( sFieldService.isEmpty() )
468 {
469 throw uno::RuntimeException("Not implemented" );
470 }
471
472 uno::Reference< text::XTextField > xTextField( mxMSF->createInstance( sFieldService ), uno::UNO_QUERY_THROW );
473
474 if( bCustom )
475 {
476 uno::Reference< beans::XPropertySet > xProps( xTextField, uno::UNO_QUERY_THROW );
477 xProps->setPropertyValue("Name", uno::Any( aDocProperty ) );
478 }
479
480 return xTextField;
481}
482
483uno::Reference< container::XEnumeration > SAL_CALL
485{
486 uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW );
487 return xEnumerationAccess->createEnumeration();
488}
489
490// ScVbaCollectionBaseImpl
493{
494 return lcl_createField( mxParent, mxContext, mxModel, aSource );
495}
496
497sal_Int32 SAL_CALL SwVbaFields::Update()
498{
499 sal_Int32 nUpdate = 1;
500 try
501 {
502 uno::Reference< text::XTextFieldsSupplier > xSupp( mxModel, uno::UNO_QUERY_THROW );
503 uno::Reference< util::XRefreshable > xRef( xSupp->getTextFields(), uno::UNO_QUERY_THROW );
504 xRef->refresh();
505 nUpdate = 0;
506 }
507 catch(const uno::Exception&)
508 {
509 nUpdate = 1;
510 }
511 return nUpdate;
512}
513
514// XHelperInterface
515OUString
517{
518 return "SwVbaFields";
519}
520
521// XEnumerationAccess
522uno::Type SAL_CALL
524{
526}
527
528uno::Sequence<OUString>
530{
531 static uno::Sequence< OUString > const aServiceNames
532 {
533 "ooo.vba.word.Fields"
534 };
535 return aServiceNames;
536}
537
538/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
struct _ADOIndex Index
css::uno::Reference< css::frame::XModel2 > mxModel
unotools::WeakReference< AnimationNode > mxParent
css::uno::Reference< css::uno::XComponentContext > mxContext
css::uno::WeakReference< ov::XHelperInterface > mxParent
css::uno::Reference< css::container::XIndexAccess > m_xIndexAccess
css::uno::Reference< css::text::XTextField > mxTextField
Definition: vbafield.hxx:32
SwVbaField(const css::uno::Reference< ooo::vba::XHelperInterface > &rParent, const css::uno::Reference< css::uno::XComponentContext > &rContext, const css::uno::Reference< css::text::XTextField > &xTextField)
Definition: vbafield.cxx:37
virtual OUString getServiceImplName() override
Definition: vbafield.cxx:55
virtual sal_Bool SAL_CALL Update() override
Definition: vbafield.cxx:42
virtual css::uno::Sequence< OUString > getServiceNames() override
Definition: vbafield.cxx:61
virtual OUString getServiceImplName() override
Definition: vbafield.cxx:516
virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override
Definition: vbafield.cxx:484
css::uno::Reference< css::lang::XMultiServiceFactory > mxMSF
Definition: vbafield.hxx:48
virtual css::uno::Type SAL_CALL getElementType() override
Definition: vbafield.cxx:523
css::uno::Reference< css::text::XTextField > Create_Field_DocProperty(const OUString &_text)
Definition: vbafield.cxx:423
virtual sal_Int32 SAL_CALL Update() override
Definition: vbafield.cxx:497
virtual css::uno::Sequence< OUString > getServiceNames() override
Definition: vbafield.cxx:529
css::uno::Reference< css::frame::XModel > mxModel
Definition: vbafield.hxx:47
virtual css::uno::Reference< ::ooo::vba::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 &PreserveFormatting) override
Definition: vbafield.cxx:314
css::uno::Reference< css::text::XTextField > Create_Field_FileName(const OUString &rText)
Definition: vbafield.cxx:350
SwVbaFields(const css::uno::Reference< ov::XHelperInterface > &xParent, const css::uno::Reference< css::uno::XComponentContext > &xContext, const css::uno::Reference< css::frame::XModel > &xModel)
Definition: vbafield.cxx:308
virtual css::uno::Any createCollectionObject(const css::uno::Any &aSource) override
Definition: vbafield.cxx:492
virtual css::uno::Reference< css::text::XTextRange > SAL_CALL getXTextRange() override
Definition: vbarange.cxx:85
css::uno::Type const & get()
int nCount
uno::Reference< uno::XComponentContext > mxContext
MapData m_aData
Sequence< OUString > aServiceNames
sal_Int64 n
#define SAL_INFO(area, stream)
int n2
double getLength(const B2DPolygon &rCandidate)
Type
Reference
void copy(const fs::path &src, const fs::path &dest)
long Long
QPRO_FUNC_TYPE nType
#define ERRCODE_BASIC_BAD_ARGUMENT
Reference< XModel > xModel
unsigned char sal_Bool
sal_uInt16 sal_Unicode
const DocPropertyTable aDocPropertyTables[]
Definition: vbafield.cxx:392
static 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)
Definition: vbafield.cxx:220