xref: /trunk/main/toolkit/source/helper/formpdfexport.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_toolkit.hxx"
26 
27 #include <toolkit/helper/formpdfexport.hxx>
28 
29 /** === begin UNO includes === **/
30 #include <com/sun/star/container/XIndexAccess.hpp>
31 #include <com/sun/star/container/XNameAccess.hpp>
32 #include <com/sun/star/container/XNameContainer.hpp>
33 #include <com/sun/star/form/XForm.hpp>
34 #include <com/sun/star/container/XChild.hpp>
35 #include <com/sun/star/lang/XServiceInfo.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/form/FormComponentType.hpp>
38 #include <com/sun/star/awt/TextAlign.hpp>
39 #include <com/sun/star/style/VerticalAlignment.hpp>
40 #include <com/sun/star/form/FormButtonType.hpp>
41 #include <com/sun/star/form/FormSubmitMethod.hpp>
42 /** === end UNO includes === **/
43 
44 #include <toolkit/helper/vclunohelper.hxx>
45 #include <tools/diagnose_ex.h>
46 #include <vcl/pdfextoutdevdata.hxx>
47 #include <vcl/outdev.hxx>
48 
49 #include <functional>
50 #include <algorithm>
51 #include <iterator>
52 
53 //........................................................................
54 namespace toolkitform
55 {
56 //........................................................................
57 
58     using namespace ::com::sun::star;
59     using namespace ::com::sun::star::uno;
60     using namespace ::com::sun::star::awt;
61     using namespace ::com::sun::star::style;
62     using namespace ::com::sun::star::beans;
63     using namespace ::com::sun::star::form;
64     using namespace ::com::sun::star::lang;
65     using namespace ::com::sun::star::container;
66 
67     // used strings
68     static const ::rtl::OUString FM_PROP_CLASSID(RTL_CONSTASCII_USTRINGPARAM("ClassId"));
69     static const ::rtl::OUString FM_PROP_NAME(RTL_CONSTASCII_USTRINGPARAM("Name"));
70     static const ::rtl::OUString FM_PROP_STRINGITEMLIST(RTL_CONSTASCII_USTRINGPARAM("StringItemList"));
71     static const ::rtl::OUString FM_PROP_HELPTEXT(RTL_CONSTASCII_USTRINGPARAM("HelpText"));
72     static const ::rtl::OUString FM_PROP_TEXT(RTL_CONSTASCII_USTRINGPARAM("Text"));
73     static const ::rtl::OUString FM_PROP_LABEL(RTL_CONSTASCII_USTRINGPARAM("Label"));
74     static const ::rtl::OUString FM_PROP_READONLY(RTL_CONSTASCII_USTRINGPARAM("ReadOnly"));
75     static const ::rtl::OUString FM_PROP_BORDER(RTL_CONSTASCII_USTRINGPARAM("Border"));
76     static const ::rtl::OUString FM_PROP_BACKGROUNDCOLOR(RTL_CONSTASCII_USTRINGPARAM("BackgroundColor"));
77     static const ::rtl::OUString FM_PROP_TEXTCOLOR(RTL_CONSTASCII_USTRINGPARAM("TextColor"));
78     static const ::rtl::OUString FM_PROP_MULTILINE(RTL_CONSTASCII_USTRINGPARAM("MultiLine"));
79     static const ::rtl::OUString FM_PROP_ALIGN(RTL_CONSTASCII_USTRINGPARAM("Align"));
80     static const ::rtl::OUString FM_PROP_FONT(RTL_CONSTASCII_USTRINGPARAM("FontDescriptor"));
81     static const ::rtl::OUString FM_PROP_MAXTEXTLEN(RTL_CONSTASCII_USTRINGPARAM("MaxTextLen"));
82     static const ::rtl::OUString FM_PROP_TARGET_URL(RTL_CONSTASCII_USTRINGPARAM("TargetURL"));
83     static const ::rtl::OUString FM_PROP_STATE(RTL_CONSTASCII_USTRINGPARAM("State"));
84     static const ::rtl::OUString FM_PROP_REFVALUE(RTL_CONSTASCII_USTRINGPARAM("RefValue"));
85     static const ::rtl::OUString FM_PROP_DROPDOWN(RTL_CONSTASCII_USTRINGPARAM("Dropdown"));
86     static const ::rtl::OUString FM_SUN_COMPONENT_FILECONTROL(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.form.component.FileControl"));
87 
88     namespace
89     {
90         //--------------------------------------------------------------------
91         /** determines the FormComponentType of a form control
92         */
classifyFormControl(const Reference<XPropertySet> & _rxModel)93         sal_Int16 classifyFormControl( const Reference< XPropertySet >& _rxModel )
94         {
95             sal_Int16 nControlType = FormComponentType::CONTROL;
96 
97             Reference< XPropertySetInfo > xPSI;
98             if ( _rxModel.is() )
99                 xPSI = _rxModel->getPropertySetInfo();
100             if ( xPSI.is() && xPSI->hasPropertyByName( FM_PROP_CLASSID ) )
101             {
102                 OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_CLASSID ) >>= nControlType );
103             }
104 
105             return nControlType;
106         }
107 
108         //--------------------------------------------------------------------
109         /** (default-)creates a PDF widget according to a given FormComponentType
110         */
createDefaultWidget(sal_Int16 _nFormComponentType)111         ::vcl::PDFWriter::AnyWidget* createDefaultWidget( sal_Int16 _nFormComponentType )
112         {
113             switch ( _nFormComponentType )
114             {
115             case FormComponentType::COMMANDBUTTON:
116                 return new ::vcl::PDFWriter::PushButtonWidget;
117             case FormComponentType::CHECKBOX:
118                 return new ::vcl::PDFWriter::CheckBoxWidget;
119             case FormComponentType::RADIOBUTTON:
120                 return new ::vcl::PDFWriter::RadioButtonWidget;
121             case FormComponentType::LISTBOX:
122                 return new ::vcl::PDFWriter::ListBoxWidget;
123             case FormComponentType::COMBOBOX:
124                 return new ::vcl::PDFWriter::ComboBoxWidget;
125 
126             case FormComponentType::TEXTFIELD:
127             case FormComponentType::FILECONTROL:
128             case FormComponentType::DATEFIELD:
129             case FormComponentType::TIMEFIELD:
130             case FormComponentType::NUMERICFIELD:
131             case FormComponentType::CURRENCYFIELD:
132             case FormComponentType::PATTERNFIELD:
133                 return new ::vcl::PDFWriter::EditWidget;
134             }
135             return NULL;
136         }
137 
138         //--------------------------------------------------------------------
139         /** determines a unique number for the radio group which the given radio
140             button model belongs to
141 
142             The number is guaranteed to be
143             <ul><li>unique within the document in which the button lives</li>
144                 <li>the same for subsequent calls with other radio button models,
145                     which live in the same document, and belong to the same group</li>
146             </ul>
147 
148             @precond
149                 the model must be part of the form component hierarchy in a document
150         */
determineRadioGroupId(const Reference<XPropertySet> & _rxRadioModel)151         sal_Int32 determineRadioGroupId( const Reference< XPropertySet >& _rxRadioModel )
152         {
153             OSL_ENSURE( classifyFormControl( _rxRadioModel ) == FormComponentType::RADIOBUTTON,
154                 "determineRadioGroupId: this *is* no radio button model!" );
155             // The fact that radio button groups need to be unique within the complete
156             // host document makes it somewhat difficult ...
157             // Problem is that two form radio buttons belong to the same group if
158             // - they have the same parent
159             // - AND they have the same name
160             // This implies that we need some knowledge about (potentially) *all* radio button
161             // groups in the document.
162 
163             // get the root-level container
164             Reference< XChild > xChild( _rxRadioModel, UNO_QUERY );
165             Reference< XForm > xParentForm( xChild.is() ? xChild->getParent() : Reference< XInterface >(), UNO_QUERY );
166             OSL_ENSURE( xParentForm.is(), "determineRadioGroupId: no parent form -> group id!" );
167             if ( !xParentForm.is() )
168                 return -1;
169 
170             while ( xParentForm.is() )
171             {
172                 xChild = xParentForm.get();
173                 xParentForm = xParentForm.query( xChild->getParent() );
174             }
175             Reference< XIndexAccess > xRoot( xChild->getParent(), UNO_QUERY );
176             OSL_ENSURE( xRoot.is(), "determineRadioGroupId: unable to determine the root of the form component hierarchy!" );
177             if ( !xRoot.is() )
178                 return -1;
179 
180             // count the leafs in the hierarchy, until we encounter radio button
181             ::std::vector< Reference< XIndexAccess > > aAncestors;
182             ::std::vector< sal_Int32 >                 aPath;
183 
184             Reference< XInterface > xNormalizedLookup( _rxRadioModel, UNO_QUERY );
185             ::rtl::OUString sRadioGroupName;
186             OSL_VERIFY( _rxRadioModel->getPropertyValue( FM_PROP_NAME ) >>= sRadioGroupName );
187 
188             Reference< XIndexAccess > xCurrentContainer( xRoot );
189             sal_Int32 nStartWithChild = 0;
190             sal_Int32 nGroupsEncountered = 0;
191             do
192             {
193                 Reference< XNameAccess > xElementNameAccess( xCurrentContainer, UNO_QUERY );
194                 OSL_ENSURE( xElementNameAccess.is(), "determineRadioGroupId: no name container?" );
195                 if ( !xElementNameAccess.is() )
196                     return -1;
197 
198                 if ( nStartWithChild == 0 )
199                 {   // we encounter this container the first time. In particular, we did not
200                     // just step up
201                     nGroupsEncountered += xElementNameAccess->getElementNames().getLength();
202                         // this is way too much: Not all of the elements in the current container
203                         // may form groups, especially if they're forms. But anyway, this number is
204                         // sufficient for our purpose. Finally, the container contains *at most*
205                         // that much groups
206                 }
207 
208                 sal_Int32 nCount = xCurrentContainer->getCount();
209                 sal_Int32 i;
210                 for ( i = nStartWithChild; i < nCount; ++i )
211                 {
212                     Reference< XInterface > xElement( xCurrentContainer->getByIndex( i ), UNO_QUERY );
213                     if ( !xElement.is() )
214                     {
215                         OSL_ENSURE( sal_False, "determineRadioGroupId: very suspicious!" );
216                         continue;
217                     }
218 
219                     Reference< XIndexAccess > xNewContainer( xElement, UNO_QUERY );
220                     if ( xNewContainer.is() )
221                     {
222                         // step down the hierarchy
223                         aAncestors.push_back( xCurrentContainer );
224                         xCurrentContainer = xNewContainer;
225                         aPath.push_back( i );
226                         nStartWithChild = 0;
227                         break;
228                             // out of the inner loop, but continue with the outer loop
229                     }
230 
231                     if ( xElement.get() == xNormalizedLookup.get() )
232                     {
233                         // look up the name of the radio group in the list of all element names
234                         Sequence< ::rtl::OUString > aElementNames( xElementNameAccess->getElementNames() );
235                         const ::rtl::OUString* pElementNames = aElementNames.getConstArray();
236                         const ::rtl::OUString* pElementNamesEnd = pElementNames + aElementNames.getLength();
237                         while ( pElementNames != pElementNamesEnd )
238                         {
239                             if ( *pElementNames == sRadioGroupName )
240                             {
241                                 sal_Int32 nLocalGroupIndex = pElementNames - aElementNames.getConstArray();
242                                 OSL_ENSURE( nLocalGroupIndex < xElementNameAccess->getElementNames().getLength(),
243                                     "determineRadioGroupId: inconsistency!" );
244 
245                                 sal_Int32 nGlobalGroupId = nGroupsEncountered - xElementNameAccess->getElementNames().getLength() + nLocalGroupIndex;
246                                 return nGlobalGroupId;
247                             }
248                             ++pElementNames;
249                         }
250                         OSL_ENSURE( sal_False, "determineRadioGroupId: did not find the radios element name!" );
251                     }
252                 }
253 
254                 if ( !( i < nCount ) )
255                 {
256                     // the loop terminated because there were no more elements
257                     // -> step up, if possible
258                     if ( aAncestors.empty() )
259                         break;
260 
261                     xCurrentContainer = aAncestors.back(); aAncestors.pop_back();
262                     nStartWithChild = aPath.back() + 1; aPath.pop_back();
263                 }
264             }
265             while ( true );
266             return -1;
267         }
268 
269         //--------------------------------------------------------------------
270         /** copies a StringItemList to a PDF widget's list
271         */
getStringItemVector(const Reference<XPropertySet> & _rxModel,::std::vector<::rtl::OUString> & _rVector)272         void getStringItemVector( const Reference< XPropertySet >& _rxModel, ::std::vector< ::rtl::OUString >& _rVector )
273         {
274             Sequence< ::rtl::OUString > aListEntries;
275             OSL_VERIFY( _rxModel->getPropertyValue( FM_PROP_STRINGITEMLIST ) >>= aListEntries );
276             ::std::copy( aListEntries.getConstArray(), aListEntries.getConstArray() + aListEntries.getLength(),
277                 ::std::back_insert_iterator< ::std::vector< ::rtl::OUString > >( _rVector ) );
278         }
279     }
280 
281     //--------------------------------------------------------------------
282     /** creates a PDF compatible control descriptor for the given control
283     */
describePDFControl(const Reference<XControl> & _rxControl,::std::auto_ptr<::vcl::PDFWriter::AnyWidget> & _rpDescriptor,::vcl::PDFExtOutDevData & i_pdfExportData)284     void TOOLKIT_DLLPUBLIC describePDFControl( const Reference< XControl >& _rxControl,
285         ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget >& _rpDescriptor, ::vcl::PDFExtOutDevData& i_pdfExportData ) SAL_THROW(())
286     {
287         _rpDescriptor.reset();
288         OSL_ENSURE( _rxControl.is(), "describePDFControl: invalid (NULL) control!" );
289         if ( !_rxControl.is() )
290             return;
291 
292         try
293         {
294             Reference< XPropertySet > xModelProps( _rxControl->getModel(), UNO_QUERY );
295             sal_Int16 nControlType = classifyFormControl( xModelProps );
296             _rpDescriptor.reset( createDefaultWidget( nControlType ) );
297             if ( !_rpDescriptor.get() )
298                 // no PDF widget available for this
299                 return;
300 
301             Reference< XPropertySetInfo > xPSI( xModelProps->getPropertySetInfo() );
302             Reference< XServiceInfo > xSI( xModelProps, UNO_QUERY );
303             OSL_ENSURE( xSI.is(), "describePDFControl: no service info!" );
304                 // if we survived classifyFormControl, then it's a real form control, and they all have
305                 // service infos
306 
307             // ================================
308             // set the common widget properties
309 
310             // --------------------------------
311             // Name, Description, Text
312             OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_NAME ) >>= _rpDescriptor->Name );
313             OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_HELPTEXT ) >>= _rpDescriptor->Description );
314             Any aText;
315             if ( xPSI->hasPropertyByName( FM_PROP_TEXT ) )
316                 aText = xModelProps->getPropertyValue( FM_PROP_TEXT );
317             else if ( xPSI->hasPropertyByName( FM_PROP_LABEL ) )
318                 aText = xModelProps->getPropertyValue( FM_PROP_LABEL );
319             if ( aText.hasValue() )
320                 OSL_VERIFY( aText >>= _rpDescriptor->Text );
321 
322             // --------------------------------
323             // readonly
324             if ( xPSI->hasPropertyByName( FM_PROP_READONLY ) )
325                 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_READONLY ) >>= _rpDescriptor->ReadOnly );
326 
327             // --------------------------------
328             // border
329             {
330                 if ( xPSI->hasPropertyByName( FM_PROP_BORDER ) )
331                 {
332                     sal_Int16 nBorderType = 0;
333                     OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_BORDER ) >>= nBorderType );
334                     _rpDescriptor->Border = ( nBorderType != 0 );
335 
336                     ::rtl::OUString sBorderColorPropertyName( RTL_CONSTASCII_USTRINGPARAM( "BorderColor" ) );
337                     if ( xPSI->hasPropertyByName( sBorderColorPropertyName ) )
338                     {
339                         sal_Int32 nBoderColor = COL_TRANSPARENT;
340                         if ( xModelProps->getPropertyValue( sBorderColorPropertyName ) >>= nBoderColor )
341                             _rpDescriptor->BorderColor = Color( nBoderColor );
342                         else
343                             _rpDescriptor->BorderColor = Color( COL_BLACK );
344                     }
345                 }
346             }
347 
348             // --------------------------------
349             // background color
350             if ( xPSI->hasPropertyByName( FM_PROP_BACKGROUNDCOLOR ) )
351             {
352                 sal_Int32 nBackColor = COL_TRANSPARENT;
353                 xModelProps->getPropertyValue( FM_PROP_BACKGROUNDCOLOR ) >>= nBackColor;
354                 _rpDescriptor->Background = true;
355                 _rpDescriptor->BackgroundColor = Color( nBackColor );
356             }
357 
358             // --------------------------------
359             // text color
360             if ( xPSI->hasPropertyByName( FM_PROP_TEXTCOLOR ) )
361             {
362                 sal_Int32 nTextColor = COL_TRANSPARENT;
363                 xModelProps->getPropertyValue( FM_PROP_TEXTCOLOR ) >>= nTextColor;
364                 _rpDescriptor->TextColor = Color( nTextColor );
365             }
366 
367             // --------------------------------
368             // text style
369             _rpDescriptor->TextStyle = 0;
370             // ............................
371             // multi line and word break
372             // The MultiLine property of the control is mapped to both the "MULTILINE" and
373             // "WORDBREAK" style flags
374             if ( xPSI->hasPropertyByName( FM_PROP_MULTILINE ) )
375             {
376                 sal_Bool bMultiLine = sal_False;
377                 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_MULTILINE ) >>= bMultiLine );
378                 if ( bMultiLine )
379                     _rpDescriptor->TextStyle |= TEXT_DRAW_MULTILINE | TEXT_DRAW_WORDBREAK;
380             }
381             // ............................
382             // horizontal alignment
383             if ( xPSI->hasPropertyByName( FM_PROP_ALIGN ) )
384             {
385                 sal_Int16 nAlign = awt::TextAlign::LEFT;
386                 xModelProps->getPropertyValue( FM_PROP_ALIGN ) >>= nAlign;
387                 // TODO: when the property is VOID - are there situations/UIs where this
388                 // means something else than LEFT?
389                 switch ( nAlign )
390                 {
391                 case awt::TextAlign::LEFT:  _rpDescriptor->TextStyle |= TEXT_DRAW_LEFT; break;
392                 case awt::TextAlign::CENTER:  _rpDescriptor->TextStyle |= TEXT_DRAW_CENTER; break;
393                 case awt::TextAlign::RIGHT:  _rpDescriptor->TextStyle |= TEXT_DRAW_RIGHT; break;
394                 default:
395                     OSL_ENSURE( sal_False, "describePDFControl: invalid text align!" );
396                 }
397             }
398             // ............................
399             // vertical alignment
400             {
401                 ::rtl::OUString sVertAlignPropertyName( RTL_CONSTASCII_USTRINGPARAM( "VerticalAlign" ) );
402                 if ( xPSI->hasPropertyByName( sVertAlignPropertyName ) )
403                 {
404                     sal_Int16 nAlign = VerticalAlignment_MIDDLE;
405                     xModelProps->getPropertyValue( sVertAlignPropertyName ) >>= nAlign;
406                     switch ( nAlign )
407                     {
408                     case VerticalAlignment_TOP:  _rpDescriptor->TextStyle |= TEXT_DRAW_TOP; break;
409                     case VerticalAlignment_MIDDLE:  _rpDescriptor->TextStyle |= TEXT_DRAW_VCENTER; break;
410                     case VerticalAlignment_BOTTOM:  _rpDescriptor->TextStyle |= TEXT_DRAW_BOTTOM; break;
411                     default:
412                         OSL_ENSURE( sal_False, "describePDFControl: invalid vertical text align!" );
413                     }
414                 }
415             }
416 
417             // font
418             if ( xPSI->hasPropertyByName( FM_PROP_FONT ) )
419             {
420                 FontDescriptor aUNOFont;
421                 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_FONT ) >>= aUNOFont );
422                 _rpDescriptor->TextFont = VCLUnoHelper::CreateFont( aUNOFont, Font() );
423             }
424 
425             // tab order
426             rtl::OUString aTabIndexString( RTL_CONSTASCII_USTRINGPARAM( "TabIndex" ) );
427             if ( xPSI->hasPropertyByName( aTabIndexString ) )
428             {
429                 sal_Int16 nIndex = -1;
430                 OSL_VERIFY( xModelProps->getPropertyValue( aTabIndexString ) >>= nIndex );
431                 _rpDescriptor->TabOrder = nIndex;
432             }
433 
434             // ================================
435             // special widget properties
436             // --------------------------------
437             // edits
438             if ( _rpDescriptor->getType() == ::vcl::PDFWriter::Edit )
439             {
440                 ::vcl::PDFWriter::EditWidget* pEditWidget = static_cast< ::vcl::PDFWriter::EditWidget* >( _rpDescriptor.get() );
441                 // ............................
442                 // multiline (already flagged in the TextStyle)
443                 pEditWidget->MultiLine = ( _rpDescriptor->TextStyle & TEXT_DRAW_MULTILINE ) != 0;
444                 // ............................
445                 // password input
446                 ::rtl::OUString sEchoCharPropName( RTL_CONSTASCII_USTRINGPARAM( "EchoChar" ) );
447                 if ( xPSI->hasPropertyByName( sEchoCharPropName ) )
448                 {
449                     sal_Int16 nEchoChar = 0;
450                     if ( ( xModelProps->getPropertyValue( sEchoCharPropName ) >>= nEchoChar ) && ( nEchoChar != 0 ) )
451                         pEditWidget->Password = true;
452                 }
453                 // ............................
454                 // file select
455                 if ( xSI->supportsService( FM_SUN_COMPONENT_FILECONTROL ) )
456                     pEditWidget->FileSelect = true;
457                 // ............................
458                 // maximum text length
459                 if ( xPSI->hasPropertyByName( FM_PROP_MAXTEXTLEN ) )
460                 {
461                     sal_Int16 nMaxTextLength = 0;
462                     OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_MAXTEXTLEN ) >>= nMaxTextLength );
463                     if ( nMaxTextLength <= 0 )
464                         // "-1" has a special meaning for database-bound controls
465                         nMaxTextLength = 0;
466                     pEditWidget->MaxLen = nMaxTextLength;
467                 }
468             }
469 
470             // --------------------------------
471             // buttons
472             if ( _rpDescriptor->getType() == ::vcl::PDFWriter::PushButton )
473             {
474                 ::vcl::PDFWriter::PushButtonWidget* pButtonWidget = static_cast< ::vcl::PDFWriter::PushButtonWidget* >( _rpDescriptor.get() );
475                 FormButtonType eButtonType = FormButtonType_PUSH;
476                 OSL_VERIFY( xModelProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ButtonType" ) ) ) >>= eButtonType );
477                 if ( eButtonType == FormButtonType_SUBMIT )
478                 {
479                     // if a button is a submit button, then it uses the URL at it's parent form
480                     Reference< XChild > xChild( xModelProps, UNO_QUERY );
481                     Reference < XPropertySet > xParentProps;
482                     if ( xChild.is() )
483                         xParentProps = xParentProps.query( xChild->getParent() );
484                     if ( xParentProps.is() )
485                     {
486                         Reference< XServiceInfo > xParentSI( xParentProps, UNO_QUERY );
487                         if ( xParentSI.is() && xParentSI->supportsService( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.component.HTMLForm" ) ) ) )
488                         {
489                             OSL_VERIFY( xParentProps->getPropertyValue( FM_PROP_TARGET_URL ) >>= pButtonWidget->URL );
490                             pButtonWidget->Submit = true;
491                             FormSubmitMethod eMethod = FormSubmitMethod_POST;
492                             OSL_VERIFY( xParentProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SubmitMethod" ) ) ) >>= eMethod );
493                             pButtonWidget->SubmitGet = (eMethod == FormSubmitMethod_GET);
494                         }
495                     }
496                 }
497                 else if ( eButtonType == FormButtonType_URL )
498                 {
499                     ::rtl::OUString sURL;
500                     OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_TARGET_URL ) >>= sURL );
501                     const bool bDocumentLocalTarget = ( sURL.getLength() > 0 ) && ( sURL.getStr()[0] == '#' );
502                     if ( bDocumentLocalTarget )
503                     {
504                         const ::rtl::OUString sDestinationName( sURL.copy(1) );
505                         // Register the destination for for future handling ...
506                         pButtonWidget->Dest = i_pdfExportData.RegisterDest();
507 
508                         // and put it into the bookmarks, to ensure the future handling really happens
509                         ::std::vector< ::vcl::PDFExtOutDevBookmarkEntry >& rBookmarks( i_pdfExportData.GetBookmarks() );
510                         ::vcl::PDFExtOutDevBookmarkEntry aBookmark;
511                         aBookmark.nDestId = pButtonWidget->Dest;
512                         aBookmark.aBookmark = sURL;
513                         rBookmarks.push_back( aBookmark );
514                     }
515                     else
516                         pButtonWidget->URL = sURL;
517 
518                     pButtonWidget->Submit = false;
519                 }
520 
521                // TODO:
522                 // In PDF files, buttons are either reset, url or submit buttons. So if we have a simple PUSH button
523                 // in a document, then this means that we do not export a SubmitToURL, which means that in PDF,
524                 // the button is used as reset button.
525                 // Is this desired? If no, we would have to reset _rpDescriptor to NULL here, in case eButtonType
526                 // != FormButtonType_SUBMIT && != FormButtonType_RESET
527 
528                 // the PDF exporter defaults the text style, if 0. To prevent this, we have to transfer the UNO
529                 // defaults to the PDF widget
530                 if ( !pButtonWidget->TextStyle )
531                     pButtonWidget->TextStyle = TEXT_DRAW_CENTER | TEXT_DRAW_VCENTER;
532             }
533 
534             // --------------------------------
535             // check boxes
536             if ( _rpDescriptor->getType() == ::vcl::PDFWriter::CheckBox )
537             {
538                 ::vcl::PDFWriter::CheckBoxWidget* pCheckBoxWidget = static_cast< ::vcl::PDFWriter::CheckBoxWidget* >( _rpDescriptor.get() );
539                 sal_Int16 nState = 0;
540                 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_STATE ) >>= nState );
541                 pCheckBoxWidget->Checked = ( nState != 0 );
542             }
543 
544             // --------------------------------
545             // radio buttons
546             if ( _rpDescriptor->getType() == ::vcl::PDFWriter::RadioButton )
547             {
548                 ::vcl::PDFWriter::RadioButtonWidget* pRadioWidget = static_cast< ::vcl::PDFWriter::RadioButtonWidget* >( _rpDescriptor.get() );
549                 sal_Int16 nState = 0;
550                 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_STATE ) >>= nState );
551                 pRadioWidget->Selected = ( nState != 0 );
552                 pRadioWidget->RadioGroup = determineRadioGroupId( xModelProps );
553                 try
554                 {
555                     xModelProps->getPropertyValue( FM_PROP_REFVALUE ) >>= pRadioWidget->OnValue;
556                 }
557                 catch(...)
558                 {
559                     pRadioWidget->OnValue = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "On" ) );
560                 }
561             }
562 
563             // --------------------------------
564             // list boxes
565             if ( _rpDescriptor->getType() == ::vcl::PDFWriter::ListBox )
566             {
567                 ::vcl::PDFWriter::ListBoxWidget* pListWidget = static_cast< ::vcl::PDFWriter::ListBoxWidget* >( _rpDescriptor.get() );
568                 // ............................
569                 // drop down
570                 OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_DROPDOWN ) >>= pListWidget->DropDown );
571                 // ............................
572                 // multi selection
573                 OSL_VERIFY( xModelProps->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MultiSelection" ) ) ) >>= pListWidget->MultiSelect );
574                 // ............................
575                 // entries
576                 getStringItemVector( xModelProps, pListWidget->Entries );
577                 // since we explicitly list the entries in the order in which they appear, they should not be
578                 // resorted by the PDF viewer
579                 pListWidget->Sort = false;
580 
581                 // get selected items
582                 Sequence< sal_Int16 > aSelectIndices;
583                 OSL_VERIFY( xModelProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "SelectedItems" ) ) ) >>= aSelectIndices );
584                 if( aSelectIndices.getLength() > 0 )
585                 {
586                     pListWidget->SelectedEntries.resize( 0 );
587                     for( sal_Int32 i = 0; i < aSelectIndices.getLength(); i++ )
588                     {
589                         sal_Int16 nIndex = aSelectIndices.getConstArray()[i];
590                         if( nIndex >= 0 && nIndex < (sal_Int16)pListWidget->Entries.size() )
591                             pListWidget->SelectedEntries.push_back( nIndex );
592                     }
593                 }
594             }
595 
596             // --------------------------------
597             // combo boxes
598             if ( _rpDescriptor->getType() == ::vcl::PDFWriter::ComboBox )
599             {
600                 ::vcl::PDFWriter::ComboBoxWidget* pComboWidget = static_cast< ::vcl::PDFWriter::ComboBoxWidget* >( _rpDescriptor.get() );
601                 // ............................
602                 // entries
603                 getStringItemVector( xModelProps, pComboWidget->Entries );
604                 // same reasoning as above
605                 pComboWidget->Sort = false;
606             }
607 
608             // ================================
609             // some post-processing
610             // --------------------------------
611             // text line ends
612             // some controls may (always or dependent on other settings) return UNIX line ends
613             String aConverter( _rpDescriptor->Text );
614             _rpDescriptor->Text = aConverter.ConvertLineEnd( LINEEND_CRLF );
615         }
616         catch( const Exception& )
617         {
618             DBG_UNHANDLED_EXCEPTION();
619         }
620     }
621 
622 //........................................................................
623 } // namespace toolkitform
624 //........................................................................
625