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