android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / ui / vba / vbafield.cxx
blobded84a6d8b211a0e30406219fa1569cdfffb1e20
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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 #include <utility>
34 using namespace ::ooo::vba;
35 using namespace ::com::sun::star;
37 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 )
39 mxTextField.set( xTextField, uno::UNO_SET_THROW );
42 sal_Bool SAL_CALL SwVbaField::Update()
44 uno::Reference< util::XUpdatable > xUpdatable( mxTextField, uno::UNO_QUERY );
45 if( xUpdatable.is() )
47 xUpdatable->update();
48 return true;
50 return false;
53 // XHelperInterface
54 OUString
55 SwVbaField::getServiceImplName()
57 return "SwVbaField";
60 uno::Sequence<OUString>
61 SwVbaField::getServiceNames()
63 static uno::Sequence< OUString > const aServiceNames
65 "ooo.vba.word.Field"
67 return aServiceNames;
70 namespace {
72 // FIXME? copy and paste code
73 // the codes are copied from ww8par5.cxx
74 class SwVbaReadFieldParams
76 private:
77 OUString m_aData;
78 sal_Int32 m_nLen, m_nFnd, m_nNext, m_nSavPtr;
79 OUString m_aFieldName;
80 public:
81 explicit SwVbaReadFieldParams( const OUString& rData );
83 tools::Long SkipToNextToken();
85 sal_Int32 FindNextStringPiece( sal_Int32 _nStart );
87 OUString GetResult() const;
88 const OUString& GetFieldName()const { return m_aFieldName; }
93 SwVbaReadFieldParams::SwVbaReadFieldParams( const OUString& _rData )
94 : m_aData( _rData ), m_nLen( _rData.getLength() ), m_nNext( 0 )
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;
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;
111 m_nFnd = m_nNext;
112 m_nSavPtr = m_nNext;
113 m_aFieldName = m_aData.copy( 0, m_nFnd );
116 OUString SwVbaReadFieldParams::GetResult() const
118 return (-1 == m_nFnd)
119 ? OUString()
120 : m_aData.copy( m_nFnd, (m_nSavPtr - m_nFnd) );
123 // ret: -2: NOT a '\' parameter but normal Text
124 tools::Long SwVbaReadFieldParams::SkipToNextToken()
126 tools::Long nRet = -1; // end
127 if (
128 (-1 != m_nNext) && (m_nLen > m_nNext) &&
129 -1 != (m_nFnd = FindNextStringPiece(m_nNext))
132 m_nSavPtr = m_nNext;
134 if ('\\' == m_aData[m_nFnd] && '\\' != m_aData[m_nFnd + 1])
136 nRet = m_aData[++m_nFnd];
137 m_nNext = ++m_nFnd; // and set behind
139 else
141 nRet = -2;
142 if (
143 (-1 != m_nSavPtr ) &&
145 ('"' == m_aData[m_nSavPtr - 1]) ||
146 (0x201d == m_aData[m_nSavPtr - 1])
150 --m_nSavPtr;
154 return nRet;
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.
161 // Output ppNext (if ppNext != 0) beginning of the search for the next parameter or 0
163 // Return value: 0 if String-End reached, otherwise begin of the parameter or the string
165 sal_Int32 SwVbaReadFieldParams::FindNextStringPiece(const sal_Int32 nStart)
167 sal_Int32 n = ( -1 == nStart ) ? m_nFnd : nStart; // Start
168 sal_Int32 n2; // End
170 m_nNext = -1; // Default for not found
172 while( (m_nLen > n) && (m_aData[ n ] == ' ') )
173 ++n;
175 if( m_nLen == n )
176 return -1; // String End reached!
178 if( (m_aData[ n ] == '"') // quotation marks are in front of parenthesis?
179 || (m_aData[ n ] == 0x201c)
180 || (m_aData[ n ] == 132) )
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
190 else // no quotation marks
192 n2 = n; // from here search for the end
193 while( (m_nLen > n2) && (m_aData[ n2 ] != ' ') ) // Search for the end of the parenthesis
195 if( m_aData[ n2 ] == '\\' )
197 if( m_aData[ n2+1 ] == '\\' )
198 n2 += 2; // double-backslash -> OK
199 else
201 if( n2 > n )
202 n2--;
203 break; // single-backslash -> End
206 else
207 n2++; // no backslash -> OK
210 if( m_nLen > n2 )
212 if(m_aData[ n2 ] != ' ') n2++;
213 m_nNext = n2;
215 return n;
218 // SwVbaFields
220 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 )
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 );
228 namespace {
230 class FieldEnumeration : public ::cppu::WeakImplHelper< css::container::XEnumeration >
232 uno::Reference< XHelperInterface > mxParent;
233 uno::Reference< uno::XComponentContext > mxContext;
234 uno::Reference< frame::XModel > mxModel;
235 uno::Reference< container::XEnumeration > mxEnumeration;
236 public:
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 ))
240 virtual sal_Bool SAL_CALL hasMoreElements( ) override
242 return mxEnumeration->hasMoreElements();
244 virtual uno::Any SAL_CALL nextElement( ) override
246 if ( !hasMoreElements() )
247 throw container::NoSuchElementException();
248 return lcl_createField( mxParent, mxContext, mxModel, mxEnumeration->nextElement() );
252 class FieldCollectionHelper : public ::cppu::WeakImplHelper< container::XIndexAccess,
253 container::XEnumerationAccess >
255 uno::Reference< XHelperInterface > mxParent;
256 uno::Reference< uno::XComponentContext > mxContext;
257 uno::Reference< frame::XModel > mxModel;
258 uno::Reference< container::XEnumerationAccess > mxEnumerationAccess;
259 public:
260 /// @throws css::uno::RuntimeException
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 )
263 uno::Reference< text::XTextFieldsSupplier > xSupp( xModel, uno::UNO_QUERY_THROW );
264 mxEnumerationAccess.set( xSupp->getTextFields(), uno::UNO_SET_THROW );
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
272 uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration();
273 sal_Int32 nCount = 0;
274 while( xEnumeration->hasMoreElements() )
276 ++nCount;
277 xEnumeration->nextElement();
279 return nCount;
281 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
283 if( Index < 0 || Index >= getCount() )
284 throw lang::IndexOutOfBoundsException();
286 uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration();
287 sal_Int32 nCount = 0;
288 while( xEnumeration->hasMoreElements() )
290 if( nCount == Index )
292 return xEnumeration->nextElement();
294 ++nCount;
296 throw lang::IndexOutOfBoundsException();
298 // XEnumerationAccess
299 virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override
301 uno::Reference< container::XEnumeration > xEnumeration = mxEnumerationAccess->createEnumeration();
302 return uno::Reference< container::XEnumeration >( new FieldEnumeration( mxParent, mxContext, mxModel, xEnumeration ) );
308 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 )
310 mxMSF.set( mxModel, uno::UNO_QUERY_THROW );
313 uno::Reference< word::XField > SAL_CALL
314 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*/ )
316 sal_Int32 nType = word::WdFieldType::wdFieldEmpty;
317 Type >>= nType;
318 OUString sText;
319 Text >>= sText;
321 OUString sFieldName;
322 if( ( nType == word::WdFieldType::wdFieldEmpty ) && !sText.isEmpty() )
324 SwVbaReadFieldParams aReadParam(sText);
325 sFieldName = aReadParam.GetFieldName();
326 SAL_INFO("sw.vba", "the field name is " << sFieldName );
329 uno::Reference< text::XTextContent > xTextField;
330 if( nType == word::WdFieldType::wdFieldFileName || sFieldName.equalsIgnoreAsciiCase("FILENAME") )
332 xTextField.set( Create_Field_FileName( sText ), uno::UNO_QUERY_THROW );
334 else if( nType == word::WdFieldType::wdFieldDocProperty || sFieldName.equalsIgnoreAsciiCase("DOCPROPERTY") )
336 xTextField.set( Create_Field_DocProperty( sText ), uno::UNO_QUERY_THROW );
338 else
340 throw uno::RuntimeException("Not implemented" );
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 ) ) );
350 uno::Reference< text::XTextField > SwVbaFields::Create_Field_FileName( const OUString& _text )
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() )
356 tools::Long nRet;
357 SwVbaReadFieldParams aReadParam( _text );
358 while (-1 != (nRet = aReadParam.SkipToNextToken()))
360 switch (nRet)
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;
376 uno::Reference< beans::XPropertySet > xProps( xTextField, uno::UNO_QUERY_THROW );
377 xProps->setPropertyValue("FileFormat", uno::Any( nFileFormat ) );
379 return xTextField;
382 namespace {
384 struct DocPropertyTable
386 const char* sDocPropertyName;
387 const char* sFieldService;
392 const DocPropertyTable aDocPropertyTables[] =
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 }
423 uno::Reference< text::XTextField > SwVbaFields::Create_Field_DocProperty( const OUString& _text )
425 OUString aDocProperty;
426 SwVbaReadFieldParams aReadParam( _text );
427 tools::Long nRet;
428 while( -1 != ( nRet = aReadParam.SkipToNextToken() ))
430 switch( nRet )
432 case -2:
433 if( aDocProperty.isEmpty() )
434 aDocProperty = aReadParam.GetResult();
435 break;
436 case '*':
437 //Skip over MERGEFORMAT
438 aReadParam.SkipToNextToken();
439 break;
442 aDocProperty = aDocProperty.replaceAll("\"", "");
443 SAL_INFO("sw.vba", "SwVbaFields::Create_Field_DocProperty, the document property name is " << aDocProperty );
444 if( aDocProperty.isEmpty() )
446 throw uno::RuntimeException();
449 bool bCustom = true;
450 OUString sFieldService;
451 // find the build in document properties
452 for( const DocPropertyTable* pTable = aDocPropertyTables; pTable->sDocPropertyName != nullptr; pTable++ )
454 if( aDocProperty.equalsIgnoreAsciiCaseAscii( pTable->sDocPropertyName ) )
456 if( pTable->sFieldService != nullptr )
457 sFieldService = OUString::createFromAscii(pTable->sFieldService);
458 bCustom = false;
459 break;
463 if( bCustom )
465 sFieldService = "com.sun.star.text.textfield.docinfo.Custom";
467 else if( sFieldService.isEmpty() )
469 throw uno::RuntimeException("Not implemented" );
472 uno::Reference< text::XTextField > xTextField( mxMSF->createInstance( sFieldService ), uno::UNO_QUERY_THROW );
474 if( bCustom )
476 uno::Reference< beans::XPropertySet > xProps( xTextField, uno::UNO_QUERY_THROW );
477 xProps->setPropertyValue("Name", uno::Any( aDocProperty ) );
480 return xTextField;
483 uno::Reference< container::XEnumeration > SAL_CALL
484 SwVbaFields::createEnumeration()
486 uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW );
487 return xEnumerationAccess->createEnumeration();
490 // ScVbaCollectionBaseImpl
491 uno::Any
492 SwVbaFields::createCollectionObject( const uno::Any& aSource )
494 return lcl_createField( mxParent, mxContext, mxModel, aSource );
497 sal_Int32 SAL_CALL SwVbaFields::Update()
499 sal_Int32 nUpdate = 1;
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;
507 catch(const uno::Exception&)
509 nUpdate = 1;
511 return nUpdate;
514 // XHelperInterface
515 OUString
516 SwVbaFields::getServiceImplName()
518 return "SwVbaFields";
521 // XEnumerationAccess
522 uno::Type SAL_CALL
523 SwVbaFields::getElementType()
525 return cppu::UnoType<word::XField>::get();
528 uno::Sequence<OUString>
529 SwVbaFields::getServiceNames()
531 static uno::Sequence< OUString > const aServiceNames
533 "ooo.vba.word.Fields"
535 return aServiceNames;
538 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */