1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <vcl/formpdfexport.hxx>
23 #include <comphelper/diagnose_ex.hxx>
24 #include <tools/lineend.hxx>
25 #include <unordered_map>
26 #include <sal/log.hxx>
28 #include <com/sun/star/container/XIndexAccess.hpp>
29 #include <com/sun/star/form/XForm.hpp>
30 #include <com/sun/star/container/XChild.hpp>
31 #include <com/sun/star/lang/XServiceInfo.hpp>
32 #include <com/sun/star/beans/XPropertySet.hpp>
33 #include <com/sun/star/form/FormComponentType.hpp>
34 #include <com/sun/star/awt/TextAlign.hpp>
35 #include <com/sun/star/awt/XControl.hpp>
36 #include <com/sun/star/style/VerticalAlignment.hpp>
37 #include <com/sun/star/form/FormButtonType.hpp>
38 #include <com/sun/star/form/FormSubmitMethod.hpp>
40 #include <toolkit/helper/vclunohelper.hxx>
41 #include <vcl/pdfextoutdevdata.hxx>
42 #include <vcl/unohelp.hxx>
48 static vcl::Font
CreateFont( const css::awt::FontDescriptor
& rDescr
)
51 if ( !rDescr
.Name
.isEmpty() )
52 aFont
.SetFamilyName( rDescr
.Name
);
53 if ( !rDescr
.StyleName
.isEmpty() )
54 aFont
.SetStyleName( rDescr
.StyleName
);
56 aFont
.SetFontSize( Size( rDescr
.Width
, rDescr
.Height
) );
57 if ( static_cast<FontFamily
>(rDescr
.Family
) != FAMILY_DONTKNOW
)
58 aFont
.SetFamily( static_cast<FontFamily
>(rDescr
.Family
) );
59 if ( static_cast<rtl_TextEncoding
>(rDescr
.CharSet
) != RTL_TEXTENCODING_DONTKNOW
)
60 aFont
.SetCharSet( static_cast<rtl_TextEncoding
>(rDescr
.CharSet
) );
61 if ( static_cast<FontPitch
>(rDescr
.Pitch
) != PITCH_DONTKNOW
)
62 aFont
.SetPitch( static_cast<FontPitch
>(rDescr
.Pitch
) );
63 if ( rDescr
.CharacterWidth
)
64 aFont
.SetWidthType(vcl::unohelper::ConvertFontWidth(rDescr
.CharacterWidth
));
66 aFont
.SetWeight(vcl::unohelper::ConvertFontWeight(rDescr
.Weight
));
67 if ( rDescr
.Slant
!= css::awt::FontSlant_DONTKNOW
)
68 aFont
.SetItalic(vcl::unohelper::ConvertFontSlant(rDescr
.Slant
));
69 if ( static_cast<FontLineStyle
>(rDescr
.Underline
) != LINESTYLE_DONTKNOW
)
70 aFont
.SetUnderline( static_cast<FontLineStyle
>(rDescr
.Underline
) );
71 if ( static_cast<FontStrikeout
>(rDescr
.Strikeout
) != STRIKEOUT_DONTKNOW
)
72 aFont
.SetStrikeout( static_cast<FontStrikeout
>(rDescr
.Strikeout
) );
75 aFont
.SetOrientation( Degree10(static_cast<sal_Int16
>(rDescr
.Orientation
* 10)) );
76 aFont
.SetKerning( static_cast<FontKerning
>(rDescr
.Kerning
) );
77 aFont
.SetWordLineMode( rDescr
.WordLineMode
);
86 using namespace ::com::sun::star
;
87 using namespace ::com::sun::star::uno
;
88 using namespace ::com::sun::star::awt
;
89 using namespace ::com::sun::star::style
;
90 using namespace ::com::sun::star::beans
;
91 using namespace ::com::sun::star::form
;
92 using namespace ::com::sun::star::lang
;
93 using namespace ::com::sun::star::container
;
95 constexpr OUString FM_PROP_NAME
= u
"Name"_ustr
;
100 /** determines the FormComponentType of a form control
102 sal_Int16
classifyFormControl( const Reference
< XPropertySet
>& _rxModel
)
104 static constexpr OUString FM_PROP_CLASSID
= u
"ClassId"_ustr
;
105 sal_Int16 nControlType
= FormComponentType::CONTROL
;
107 Reference
< XPropertySetInfo
> xPSI
;
109 xPSI
= _rxModel
->getPropertySetInfo();
110 if ( xPSI
.is() && xPSI
->hasPropertyByName( FM_PROP_CLASSID
) )
112 if( ! (_rxModel
->getPropertyValue( FM_PROP_CLASSID
) >>= nControlType
) ) {
113 SAL_WARN("toolkit.helper", "classifyFormControl: unable to get property " << FM_PROP_CLASSID
);
121 /** (default-)creates a PDF widget according to a given FormComponentType
123 std::unique_ptr
<vcl::PDFWriter::AnyWidget
> createDefaultWidget( sal_Int16 _nFormComponentType
)
125 switch ( _nFormComponentType
)
127 case FormComponentType::COMMANDBUTTON
:
128 return std::make_unique
<vcl::PDFWriter::PushButtonWidget
>();
129 case FormComponentType::CHECKBOX
:
130 return std::make_unique
<vcl::PDFWriter::CheckBoxWidget
>();
131 case FormComponentType::RADIOBUTTON
:
132 return std::make_unique
<vcl::PDFWriter::RadioButtonWidget
>();
133 case FormComponentType::LISTBOX
:
134 return std::make_unique
<vcl::PDFWriter::ListBoxWidget
>();
135 case FormComponentType::COMBOBOX
:
136 return std::make_unique
<vcl::PDFWriter::ComboBoxWidget
>();
138 case FormComponentType::TEXTFIELD
:
139 case FormComponentType::FILECONTROL
:
140 case FormComponentType::DATEFIELD
:
141 case FormComponentType::TIMEFIELD
:
142 case FormComponentType::NUMERICFIELD
:
143 case FormComponentType::CURRENCYFIELD
:
144 case FormComponentType::PATTERNFIELD
:
145 return std::make_unique
<vcl::PDFWriter::EditWidget
>();
151 /** determines a unique number for the radio group which the given radio
152 button model belongs to
154 The number is guaranteed to be
155 <ul><li>unique within the document in which the button lives</li>
156 <li>the same for subsequent calls with other radio button models,
157 which live in the same document, and belong to the same group</li>
161 the model must be part of the form component hierarchy in a document
163 sal_Int32
determineRadioGroupId( const Reference
< XPropertySet
>& _rxRadioModel
)
165 OSL_ENSURE( classifyFormControl( _rxRadioModel
) == FormComponentType::RADIOBUTTON
,
166 "determineRadioGroupId: this *is* no radio button model!" );
167 // The fact that radio button groups need to be unique within the complete
168 // host document makes it somewhat difficult ...
169 // Problem is that two form radio buttons belong to the same group if
170 // - they have the same parent
171 // - AND they have the same name or group name
172 // This implies that we need some knowledge about (potentially) *all* radio button
173 // groups in the document.
175 // get the root-level container
176 Reference
< XChild
> xChild( _rxRadioModel
, UNO_QUERY
);
177 Reference
< XForm
> xParentForm( xChild
.is() ? xChild
->getParent() : Reference
< XInterface
>(), UNO_QUERY
);
178 OSL_ENSURE( xParentForm
.is(), "determineRadioGroupId: no parent form -> group id!" );
179 if ( !xParentForm
.is() )
182 while ( xParentForm
.is() )
184 xChild
= xParentForm
.get();
185 xParentForm
.set(xChild
->getParent(), css::uno::UNO_QUERY
);
187 Reference
< XIndexAccess
> xRoot( xChild
->getParent(), UNO_QUERY
);
188 OSL_ENSURE( xRoot
.is(), "determineRadioGroupId: unable to determine the root of the form component hierarchy!" );
192 // count the leafs in the hierarchy, until we encounter radio button
193 ::std::vector
< Reference
< XIndexAccess
> > aAncestors
;
194 ::std::vector
< sal_Int32
> aPath
;
196 Reference
< XInterface
> xNormalizedLookup( _rxRadioModel
, UNO_QUERY
);
197 Reference
< XIndexAccess
> xCurrentContainer( xRoot
);
198 sal_Int32 nStartWithChild
= 0;
199 sal_Int32 nGroupsEncountered
= 0;
202 std::unordered_map
<OUString
,sal_Int32
> GroupNameMap
;
203 std::unordered_map
<OUString
,sal_Int32
> SharedNameMap
;
204 sal_Int32 nCount
= xCurrentContainer
->getCount();
206 for ( i
= nStartWithChild
; i
< nCount
; ++i
)
208 Reference
< XInterface
> xElement( xCurrentContainer
->getByIndex( i
), UNO_QUERY
);
209 if ( !xElement
.is() )
211 OSL_FAIL( "determineRadioGroupId: very suspicious!" );
215 Reference
< XIndexAccess
> xNewContainer( xElement
, UNO_QUERY
);
216 if ( xNewContainer
.is() )
218 // step down the hierarchy
219 aAncestors
.push_back( xCurrentContainer
);
220 xCurrentContainer
= std::move(xNewContainer
);
221 aPath
.push_back( i
);
224 // out of the inner loop, but continue with the outer loop
227 if ( xElement
.get() == xNormalizedLookup
.get() )
229 // Our radio button is in this container.
230 // Now take the time to ID this container's groups and return the button's groupId
231 for ( i
= 0; i
< nCount
; ++i
)
235 xElement
.set( xCurrentContainer
->getByIndex( i
), UNO_QUERY_THROW
);
236 Reference
< XServiceInfo
> xModelSI( xElement
, UNO_QUERY_THROW
);
237 if ( xModelSI
->supportsService(u
"com.sun.star.awt.UnoControlRadioButtonModel"_ustr
) )
239 Reference
< XPropertySet
> aProps( xElement
, UNO_QUERY_THROW
);
242 aProps
->getPropertyValue(u
"GroupName"_ustr
) >>= sGroupName
;
243 if ( !sGroupName
.isEmpty() )
245 // map: unique key is the group name, so attempts to add a different ID value
246 // for an existing group are ignored - keeping the first ID - perfect for this scenario.
247 GroupNameMap
.emplace( sGroupName
, nGroupsEncountered
+ i
);
249 if ( xElement
.get() == xNormalizedLookup
.get() )
250 return GroupNameMap
[sGroupName
];
254 // Old implementation didn't have a GroupName, just identical Control names.
255 aProps
->getPropertyValue( FM_PROP_NAME
) >>= sGroupName
;
256 SharedNameMap
.emplace( sGroupName
, nGroupsEncountered
+ i
);
258 if ( xElement
.get() == xNormalizedLookup
.get() )
259 return SharedNameMap
[sGroupName
];
264 catch( uno::Exception
& )
266 DBG_UNHANDLED_EXCEPTION("toolkit");
269 SAL_WARN("toolkit.helper","determineRadioGroupId: did not find the radios element's group!" );
273 // we encounter this container the first time. In particular, we did not just step up
274 if ( nStartWithChild
== 0 )
276 // Our control wasn't in this container, so consider every item to be a possible unique group.
277 // This is way too much: Not all of the elements in the current container will form groups.
278 // But anyway, this number is sufficient for our purpose, since sequential group ids are not required.
279 // Ultimately, the container contains *at most* this many groups.
280 nGroupsEncountered
+= nCount
;
285 // the loop terminated because there were no more elements
286 // -> step up, if possible
287 if ( aAncestors
.empty() )
290 xCurrentContainer
= aAncestors
.back(); aAncestors
.pop_back();
291 nStartWithChild
= aPath
.back() + 1; aPath
.pop_back();
299 /** copies a StringItemList to a PDF widget's list
301 void getStringItemVector( const Reference
< XPropertySet
>& _rxModel
, ::std::vector
< OUString
>& _rVector
)
303 Sequence
< OUString
> aListEntries
;
304 if( ! (_rxModel
->getPropertyValue( u
"StringItemList"_ustr
) >>= aListEntries
) ) {
305 SAL_WARN("toolkit.helper", "getStringItemVector: unable to get property StringItemList");
307 _rVector
.insert( _rVector
.end(), std::cbegin(aListEntries
), std::cend(aListEntries
) );
312 /** creates a PDF compatible control descriptor for the given control
314 std::unique_ptr
<vcl::PDFWriter::AnyWidget
> describePDFControl( const Reference
< XControl
>& _rxControl
,
315 vcl::PDFExtOutDevData
& i_pdfExportData
)
317 std::unique_ptr
<vcl::PDFWriter::AnyWidget
> Descriptor
;
318 OSL_ENSURE( _rxControl
.is(), "describePDFControl: invalid (NULL) control!" );
319 if ( !_rxControl
.is() )
324 Reference
< XPropertySet
> xModelProps( _rxControl
->getModel(), UNO_QUERY
);
325 sal_Int16 nControlType
= classifyFormControl( xModelProps
);
326 Descriptor
= createDefaultWidget( nControlType
);
328 // no PDF widget available for this
331 Reference
< XPropertySetInfo
> xPSI( xModelProps
->getPropertySetInfo() );
332 Reference
< XServiceInfo
> xSI( xModelProps
, UNO_QUERY
);
333 OSL_ENSURE( xSI
.is(), "describePDFControl: no service info!" );
334 // if we survived classifyFormControl, then it's a real form control, and they all have
338 // set the common widget properties
341 // Name, Description, Text
342 if( ! (xModelProps
->getPropertyValue( FM_PROP_NAME
) >>= Descriptor
->Name
) ) {
343 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_NAME
);
345 if( ! (xModelProps
->getPropertyValue( u
"HelpText"_ustr
) >>= Descriptor
->Description
) ) {
346 SAL_INFO("toolkit.helper", "describePDFControl: unable to get property HelpText");
349 static constexpr OUString FM_PROP_TEXT
= u
"Text"_ustr
;
350 static constexpr OUString FM_PROP_LABEL
= u
"Label"_ustr
;
351 static constexpr OUString FM_PROP_VALUE
= u
"Value"_ustr
;
352 if ( xPSI
->hasPropertyByName( FM_PROP_TEXT
) )
353 aText
= xModelProps
->getPropertyValue( FM_PROP_TEXT
);
354 else if ( xPSI
->hasPropertyByName( FM_PROP_LABEL
) )
355 aText
= xModelProps
->getPropertyValue( FM_PROP_LABEL
);
356 else if ( xPSI
->hasPropertyByName( FM_PROP_VALUE
) )
359 if (xModelProps
->getPropertyValue( FM_PROP_VALUE
) >>= aValue
)
360 aText
<<= OUString::number(aValue
);
363 if ( aText
.hasValue() ) {
364 if( ! (aText
>>= Descriptor
->Text
) ) {
365 SAL_WARN("toolkit.helper", "describePDFControl: unable to assign aText to Descriptor->Text");
371 static constexpr OUString FM_PROP_READONLY
= u
"ReadOnly"_ustr
;
372 if ( xPSI
->hasPropertyByName( FM_PROP_READONLY
) )
373 if( ! (xModelProps
->getPropertyValue( FM_PROP_READONLY
) >>= Descriptor
->ReadOnly
) )
374 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_READONLY
);
379 static constexpr OUString FM_PROP_BORDER
= u
"Border"_ustr
;
380 if ( xPSI
->hasPropertyByName( FM_PROP_BORDER
) )
382 sal_Int16 nBorderType
= 0;
383 if( ! (xModelProps
->getPropertyValue( FM_PROP_BORDER
) >>= nBorderType
) )
384 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_BORDER
);
385 Descriptor
->Border
= ( nBorderType
!= 0 );
387 OUString
sBorderColorPropertyName( u
"BorderColor"_ustr
);
388 if ( xPSI
->hasPropertyByName( sBorderColorPropertyName
) )
390 Color nBorderColor
= COL_TRANSPARENT
;
391 if ( xModelProps
->getPropertyValue( sBorderColorPropertyName
) >>= nBorderColor
)
392 Descriptor
->BorderColor
= nBorderColor
;
394 Descriptor
->BorderColor
= COL_BLACK
;
401 static constexpr OUString FM_PROP_BACKGROUNDCOLOR
= u
"BackgroundColor"_ustr
;
402 if ( xPSI
->hasPropertyByName( FM_PROP_BACKGROUNDCOLOR
) )
404 Color nBackColor
= COL_TRANSPARENT
;
405 xModelProps
->getPropertyValue( FM_PROP_BACKGROUNDCOLOR
) >>= nBackColor
;
406 Descriptor
->Background
= true;
407 Descriptor
->BackgroundColor
= nBackColor
;
412 static constexpr OUString FM_PROP_TEXTCOLOR
= u
"TextColor"_ustr
;
413 if ( xPSI
->hasPropertyByName( FM_PROP_TEXTCOLOR
) )
415 Color nTextColor
= COL_TRANSPARENT
;
416 xModelProps
->getPropertyValue( FM_PROP_TEXTCOLOR
) >>= nTextColor
;
417 Descriptor
->TextColor
= nTextColor
;
422 Descriptor
->TextStyle
= DrawTextFlags::NONE
;
424 // multi line and word break
425 // The MultiLine property of the control is mapped to both the "MULTILINE" and
426 // "WORDBREAK" style flags
427 static constexpr OUString FM_PROP_MULTILINE
= u
"MultiLine"_ustr
;
428 if ( xPSI
->hasPropertyByName( FM_PROP_MULTILINE
) )
430 bool bMultiLine
= false;
431 if( ! (xModelProps
->getPropertyValue( FM_PROP_MULTILINE
) >>= bMultiLine
) )
432 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_MULTILINE
);
434 Descriptor
->TextStyle
|= DrawTextFlags::MultiLine
| DrawTextFlags::WordBreak
;
437 // horizontal alignment
438 static constexpr OUString FM_PROP_ALIGN
= u
"Align"_ustr
;
439 if ( xPSI
->hasPropertyByName( FM_PROP_ALIGN
) )
441 sal_Int16 nAlign
= awt::TextAlign::LEFT
;
442 xModelProps
->getPropertyValue( FM_PROP_ALIGN
) >>= nAlign
;
443 // TODO: when the property is VOID - are there situations/UIs where this
444 // means something else than LEFT?
447 case awt::TextAlign::LEFT
: Descriptor
->TextStyle
|= DrawTextFlags::Left
; break;
448 case awt::TextAlign::CENTER
: Descriptor
->TextStyle
|= DrawTextFlags::Center
; break;
449 case awt::TextAlign::RIGHT
: Descriptor
->TextStyle
|= DrawTextFlags::Right
; break;
451 OSL_FAIL( "describePDFControl: invalid text align!" );
455 // vertical alignment
457 OUString
sVertAlignPropertyName( u
"VerticalAlign"_ustr
);
458 if ( xPSI
->hasPropertyByName( sVertAlignPropertyName
) )
460 VerticalAlignment nAlign
= VerticalAlignment_MIDDLE
;
461 xModelProps
->getPropertyValue( sVertAlignPropertyName
) >>= nAlign
;
464 case VerticalAlignment_TOP
: Descriptor
->TextStyle
|= DrawTextFlags::Top
; break;
465 case VerticalAlignment_MIDDLE
: Descriptor
->TextStyle
|= DrawTextFlags::VCenter
; break;
466 case VerticalAlignment_BOTTOM
: Descriptor
->TextStyle
|= DrawTextFlags::Bottom
; break;
468 OSL_FAIL( "describePDFControl: invalid vertical text align!" );
474 static constexpr OUString FM_PROP_FONT
= u
"FontDescriptor"_ustr
;
475 if ( xPSI
->hasPropertyByName( FM_PROP_FONT
) )
477 FontDescriptor aUNOFont
;
478 if( ! (xModelProps
->getPropertyValue( FM_PROP_FONT
) >>= aUNOFont
) )
479 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_FONT
);
480 Descriptor
->TextFont
= CreateFont( aUNOFont
);
484 OUString
aTabIndexString( u
"TabIndex"_ustr
);
485 if ( xPSI
->hasPropertyByName( aTabIndexString
) )
487 sal_Int16 nIndex
= -1;
488 if( ! (xModelProps
->getPropertyValue( aTabIndexString
) >>= nIndex
) )
489 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << aTabIndexString
);
490 Descriptor
->TabOrder
= nIndex
;
494 // special widget properties
497 if ( Descriptor
->getType() == vcl::PDFWriter::Edit
)
499 vcl::PDFWriter::EditWidget
* pEditWidget
= static_cast< vcl::PDFWriter::EditWidget
* >( Descriptor
.get() );
501 // multiline (already flagged in the TextStyle)
502 pEditWidget
->MultiLine
= bool( Descriptor
->TextStyle
& DrawTextFlags::MultiLine
);
505 OUString
sEchoCharPropName( u
"EchoChar"_ustr
);
506 if ( xPSI
->hasPropertyByName( sEchoCharPropName
) )
508 sal_Int16 nEchoChar
= 0;
509 if ( ( xModelProps
->getPropertyValue( sEchoCharPropName
) >>= nEchoChar
) && ( nEchoChar
!= 0 ) )
510 pEditWidget
->Password
= true;
514 if ( xSI
->supportsService( u
"com.sun.star.form.component.FileControl"_ustr
) )
515 pEditWidget
->FileSelect
= true;
517 // maximum text length
518 static constexpr OUString FM_PROP_MAXTEXTLEN
= u
"MaxTextLen"_ustr
;
519 if ( xPSI
->hasPropertyByName( FM_PROP_MAXTEXTLEN
) )
521 sal_Int16 nMaxTextLength
= 0;
522 if( ! (xModelProps
->getPropertyValue( FM_PROP_MAXTEXTLEN
) >>= nMaxTextLength
) )
523 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_MAXTEXTLEN
);
524 if ( nMaxTextLength
<= 0 )
525 // "-1" has a special meaning for database-bound controls
527 pEditWidget
->MaxLen
= nMaxTextLength
;
530 switch ( nControlType
)
532 case FormComponentType::CURRENCYFIELD
:
533 case FormComponentType::NUMERICFIELD
:
536 pEditWidget
->Format
= vcl::PDFWriter::Number
;
538 static constexpr OUString FM_PROP_CURRENCYSYMBOL
= u
"CurrencySymbol"_ustr
;
539 if ( xPSI
->hasPropertyByName( FM_PROP_CURRENCYSYMBOL
) )
541 OUString sCurrencySymbol
;
542 if( ! (xModelProps
->getPropertyValue( FM_PROP_CURRENCYSYMBOL
) >>= sCurrencySymbol
) )
543 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_CURRENCYSYMBOL
);
544 pEditWidget
->CurrencySymbol
= sCurrencySymbol
;
547 static constexpr OUString FM_PROP_DECIMALACCURACY
= u
"DecimalAccuracy"_ustr
;
548 if ( xPSI
->hasPropertyByName( FM_PROP_DECIMALACCURACY
) )
550 sal_Int32 nDecimalAccuracy
= 0;
551 if( ! (xModelProps
->getPropertyValue( FM_PROP_DECIMALACCURACY
) >>= nDecimalAccuracy
) )
552 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_DECIMALACCURACY
);
553 pEditWidget
->DecimalAccuracy
= nDecimalAccuracy
;
556 static constexpr OUString FM_PROP_PREPENDCURRENCYSYMBOL
= u
"PrependCurrencySymbol"_ustr
;
557 if ( xPSI
->hasPropertyByName( FM_PROP_PREPENDCURRENCYSYMBOL
) )
559 bool bPrependCurrencySymbol
= true;
560 if( ! (xModelProps
->getPropertyValue( FM_PROP_PREPENDCURRENCYSYMBOL
) >>= bPrependCurrencySymbol
) )
561 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_PREPENDCURRENCYSYMBOL
);
562 pEditWidget
->PrependCurrencySymbol
= bPrependCurrencySymbol
;
565 case FormComponentType::TIMEFIELD
:
567 pEditWidget
->Format
= vcl::PDFWriter::Time
;
569 static constexpr OUString FM_PROP_TIMEFORMAT
= u
"TimeFormat"_ustr
;
570 if ( xPSI
->hasPropertyByName( FM_PROP_TIMEFORMAT
) )
572 sal_Int32 nTimeFormat
= 0;
573 if( ! (xModelProps
->getPropertyValue( FM_PROP_TIMEFORMAT
) >>= nTimeFormat
) )
574 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_TIMEFORMAT
);
576 switch ( nTimeFormat
)
579 pEditWidget
->TimeFormat
= "HH:MM"; //13:45
582 pEditWidget
->TimeFormat
= "HH:MM:ss"; //13:45:00
585 pEditWidget
->TimeFormat
= "h:MMtt"; //01:45 PM
588 pEditWidget
->TimeFormat
= "h:MM:sstt"; //01:45:00 PM
593 case FormComponentType::DATEFIELD
:
595 pEditWidget
->Format
= vcl::PDFWriter::Date
;
597 static constexpr OUString FM_PROP_DATEFORMAT
= u
"DateFormat"_ustr
;
598 if ( xPSI
->hasPropertyByName( FM_PROP_DATEFORMAT
) )
600 sal_Int32 nDateFormat
= 0;
601 if( ! (xModelProps
->getPropertyValue( FM_PROP_DATEFORMAT
) >>= nDateFormat
) )
602 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_DATEFORMAT
);
604 switch ( nDateFormat
)
608 pEditWidget
->DateFormat
= "mm/dd/yy"; // Standard (short)
612 pEditWidget
->DateFormat
= "mm/dd/yyyy"; // Standard (long)
615 pEditWidget
->DateFormat
= "dd/mm/yy"; // DD/MM/YY
618 pEditWidget
->DateFormat
= "mm/dd/yy"; // MM/DD/YY
621 pEditWidget
->DateFormat
= "yy/mm/dd"; // YY/MM/DD
624 pEditWidget
->DateFormat
= "dd/mm/yyyy"; // DD/MM/YYYY
627 pEditWidget
->DateFormat
= "mm/dd/yyyy"; // MM/DD/YYYY
630 pEditWidget
->DateFormat
= "yyyy/mm/dd"; // YYYY/MM/DD
633 pEditWidget
->DateFormat
= "yy-mm-dd"; // YY-MM-DD
636 pEditWidget
->DateFormat
= "yyyy-mm-dd"; // YYYY-MM-DD
645 if ( Descriptor
->getType() == vcl::PDFWriter::PushButton
)
647 vcl::PDFWriter::PushButtonWidget
* pButtonWidget
= static_cast< vcl::PDFWriter::PushButtonWidget
* >( Descriptor
.get() );
648 FormButtonType eButtonType
= FormButtonType_PUSH
;
649 if( ! (xModelProps
->getPropertyValue(u
"ButtonType"_ustr
) >>= eButtonType
) )
650 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property ButtonType");
651 static constexpr OUString FM_PROP_TARGET_URL
= u
"TargetURL"_ustr
;
652 if ( eButtonType
== FormButtonType_SUBMIT
)
654 // if a button is a submit button, then it uses the URL at its parent form
655 Reference
< XChild
> xChild( xModelProps
, UNO_QUERY
);
656 Reference
< XPropertySet
> xParentProps
;
658 xParentProps
.set(xChild
->getParent(), css::uno::UNO_QUERY
);
659 if ( xParentProps
.is() )
661 Reference
< XServiceInfo
> xParentSI( xParentProps
, UNO_QUERY
);
662 if ( xParentSI
.is() && xParentSI
->supportsService(u
"com.sun.star.form.component.HTMLForm"_ustr
) )
664 if( ! (xParentProps
->getPropertyValue( FM_PROP_TARGET_URL
) >>= pButtonWidget
->URL
) )
665 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_TARGET_URL
);
666 pButtonWidget
->Submit
= true;
667 FormSubmitMethod eMethod
= FormSubmitMethod_POST
;
668 if( ! (xParentProps
->getPropertyValue(u
"SubmitMethod"_ustr
) >>= eMethod
) )
669 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_TARGET_URL
);
670 pButtonWidget
->SubmitGet
= (eMethod
== FormSubmitMethod_GET
);
674 else if ( eButtonType
== FormButtonType_URL
)
677 if( ! (xModelProps
->getPropertyValue( FM_PROP_TARGET_URL
) >>= sURL
) )
678 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_TARGET_URL
);
679 const bool bDocumentLocalTarget
= sURL
.startsWith("#");
680 if ( bDocumentLocalTarget
)
682 // Register the destination for future handling ...
683 pButtonWidget
->Dest
= i_pdfExportData
.RegisterDest();
685 // and put it into the bookmarks, to ensure the future handling really happens
686 ::std::vector
< vcl::PDFExtOutDevBookmarkEntry
>& rBookmarks( i_pdfExportData
.GetBookmarks() );
687 vcl::PDFExtOutDevBookmarkEntry aBookmark
;
688 aBookmark
.nDestId
= pButtonWidget
->Dest
;
689 aBookmark
.aBookmark
= sURL
;
690 rBookmarks
.push_back( aBookmark
);
693 pButtonWidget
->URL
= sURL
;
695 pButtonWidget
->Submit
= false;
699 // In PDF files, buttons are either reset, url or submit buttons. So if we have a simple PUSH button
700 // in a document, then this means that we do not export a SubmitToURL, which means that in PDF,
701 // the button is used as reset button.
702 // Is this desired? If no, we would have to reset Descriptor to NULL here, in case eButtonType
703 // != FormButtonType_SUBMIT && != FormButtonType_RESET
705 // the PDF exporter defaults the text style, if 0. To prevent this, we have to transfer the UNO
706 // defaults to the PDF widget
707 if ( pButtonWidget
->TextStyle
== DrawTextFlags::NONE
)
708 pButtonWidget
->TextStyle
= DrawTextFlags::Center
| DrawTextFlags::VCenter
;
713 static constexpr OUString FM_PROP_STATE
= u
"State"_ustr
;
714 if ( Descriptor
->getType() == vcl::PDFWriter::CheckBox
)
716 vcl::PDFWriter::CheckBoxWidget
* pCheckBoxWidget
= static_cast< vcl::PDFWriter::CheckBoxWidget
* >( Descriptor
.get() );
717 sal_Int16 nState
= 0;
718 if( ! (xModelProps
->getPropertyValue( FM_PROP_STATE
) >>= nState
) )
719 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_STATE
);
720 pCheckBoxWidget
->Checked
= ( nState
!= 0 );
724 xModelProps
->getPropertyValue( u
"RefValue"_ustr
) >>= pCheckBoxWidget
->OnValue
;
732 xModelProps
->getPropertyValue( u
"SecondaryRefValue"_ustr
) >>= pCheckBoxWidget
->OffValue
;
741 if ( Descriptor
->getType() == vcl::PDFWriter::RadioButton
)
743 vcl::PDFWriter::RadioButtonWidget
* pRadioWidget
= static_cast< vcl::PDFWriter::RadioButtonWidget
* >( Descriptor
.get() );
744 sal_Int16 nState
= 0;
745 if( ! (xModelProps
->getPropertyValue( FM_PROP_STATE
) >>= nState
) )
746 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property " << FM_PROP_STATE
);
747 pRadioWidget
->Selected
= ( nState
!= 0 );
748 pRadioWidget
->RadioGroup
= determineRadioGroupId( xModelProps
);
751 xModelProps
->getPropertyValue( u
"RefValue"_ustr
) >>= pRadioWidget
->OnValue
;
759 xModelProps
->getPropertyValue( u
"SecondaryRefValue"_ustr
) >>= pRadioWidget
->OffValue
;
768 if ( Descriptor
->getType() == vcl::PDFWriter::ListBox
)
770 vcl::PDFWriter::ListBoxWidget
* pListWidget
= static_cast< vcl::PDFWriter::ListBoxWidget
* >( Descriptor
.get() );
773 if( ! (xModelProps
->getPropertyValue( u
"Dropdown"_ustr
) >>= pListWidget
->DropDown
) )
774 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property Dropdown");
777 if( ! (xModelProps
->getPropertyValue(u
"MultiSelection"_ustr
) >>= pListWidget
->MultiSelect
) )
778 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property MultiSelection");
781 getStringItemVector( xModelProps
, pListWidget
->Entries
);
783 // get selected items
784 Sequence
< sal_Int16
> aSelectIndices
;
785 if( ! (xModelProps
->getPropertyValue(u
"SelectedItems"_ustr
) >>= aSelectIndices
) )
786 SAL_WARN("toolkit.helper", "describePDFControl: unable to get property SelectedItems");
787 if( aSelectIndices
.hasElements() )
789 pListWidget
->SelectedEntries
.resize( 0 );
790 auto nEntriesSize
= static_cast<sal_Int16
>(pListWidget
->Entries
.size());
791 std::copy_if(std::cbegin(aSelectIndices
), std::cend(aSelectIndices
), std::back_inserter(pListWidget
->SelectedEntries
),
792 [&nEntriesSize
](const sal_Int16 nIndex
) { return nIndex
>= 0 && nIndex
< nEntriesSize
; });
798 if ( Descriptor
->getType() == vcl::PDFWriter::ComboBox
)
800 vcl::PDFWriter::ComboBoxWidget
* pComboWidget
= static_cast< vcl::PDFWriter::ComboBoxWidget
* >( Descriptor
.get() );
803 getStringItemVector( xModelProps
, pComboWidget
->Entries
);
807 // some post-processing
810 // some controls may (always or dependent on other settings) return UNIX line ends
811 Descriptor
->Text
= convertLineEnd(Descriptor
->Text
, LINEEND_CRLF
);
813 catch( const Exception
& )
815 TOOLS_WARN_EXCEPTION( "toolkit", "describePDFControl" );
821 } // namespace toolkitform
824 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */