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
20 #include <com/sun/star/form/FormSubmitEncoding.hpp>
21 #include <com/sun/star/form/FormSubmitMethod.hpp>
22 #include <com/sun/star/form/FormButtonType.hpp>
23 #include <com/sun/star/frame/XModel.hpp>
24 #include <com/sun/star/script/XEventAttacherManager.hpp>
25 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
26 #include <com/sun/star/form/XFormsSupplier.hpp>
27 #include <com/sun/star/form/XForm.hpp>
28 #include <com/sun/star/form/FormComponentType.hpp>
29 #include <com/sun/star/awt/XTextLayoutConstrains.hpp>
30 #include <com/sun/star/beans/XPropertySet.hpp>
31 #include <hintids.hxx>
32 #include <o3tl/any.hxx>
33 #include <rtl/math.hxx>
34 #include <vcl/svapp.hxx>
35 #include <svl/macitem.hxx>
36 #include <svtools/htmlout.hxx>
37 #include <svtools/htmlkywd.hxx>
38 #include <svl/urihelper.hxx>
39 #include <vcl/unohelp.hxx>
40 #include <svx/svdouno.hxx>
41 #include <editeng/brushitem.hxx>
42 #include <editeng/colritem.hxx>
43 #include <editeng/fhgtitem.hxx>
44 #include <editeng/fontitem.hxx>
45 #include <editeng/wghtitem.hxx>
46 #include <editeng/postitem.hxx>
47 #include <editeng/udlnitem.hxx>
48 #include <editeng/crossedoutitem.hxx>
49 #include <osl/diagnose.h>
50 #include <docsh.hxx>
51 #include <fmtanchr.hxx>
52 #include <viewsh.hxx>
53 #include <pam.hxx>
54 #include <doc.hxx>
55 #include <IDocumentLayoutAccess.hxx>
56 #include <IDocumentDrawModelAccess.hxx>
57 #include "wrthtml.hxx"
58 #include "htmlfly.hxx"
59 #include "htmlform.hxx"
60 #include <frmfmt.hxx>
61 #include <frameformats.hxx>
62 #include <memory>
63
64 using namespace ::com::sun::star;
65
66 const HtmlFrmOpts HTML_FRMOPTS_CONTROL =
67 HtmlFrmOpts::NONE;
68 const HtmlFrmOpts HTML_FRMOPTS_CONTROL_CSS1 =
69 HtmlFrmOpts::SAlign |
70 HtmlFrmOpts::SSize |
71 HtmlFrmOpts::SSpace |
72 HtmlFrmOpts::BrClear;
73 const HtmlFrmOpts HTML_FRMOPTS_IMG_CONTROL =
74 HtmlFrmOpts::Align |
75 HtmlFrmOpts::BrClear;
76 const HtmlFrmOpts HTML_FRMOPTS_IMG_CONTROL_CSS1 =
77 HtmlFrmOpts::SAlign |
78 HtmlFrmOpts::SSpace;
79
lcl_html_outEvents(SvStream & rStrm,const uno::Reference<form::XFormComponent> & rFormComp,bool bCfgStarBasic,rtl_TextEncoding eDestEnc,OUString * pNonConvertableChars)80 static void lcl_html_outEvents( SvStream& rStrm,
81 const uno::Reference< form::XFormComponent >& rFormComp,
82 bool bCfgStarBasic,
83 rtl_TextEncoding eDestEnc,
84 OUString *pNonConvertableChars )
85 {
86 uno::Reference< uno::XInterface > xParentIfc = rFormComp->getParent();
87 OSL_ENSURE( xParentIfc.is(), "lcl_html_outEvents: no parent interface" );
88 if( !xParentIfc.is() )
89 return;
90 uno::Reference< container::XIndexAccess > xIndexAcc( xParentIfc, uno::UNO_QUERY );
91 uno::Reference< script::XEventAttacherManager > xEventManager( xParentIfc,
92 uno::UNO_QUERY );
93 if( !xIndexAcc.is() || !xEventManager.is() )
94 return;
95
96 // and search for the position of the ControlModel within
97 sal_Int32 nCount = xIndexAcc->getCount(), nPos;
98 for( nPos = 0 ; nPos < nCount; nPos++ )
99 {
100 uno::Any aTmp = xIndexAcc->getByIndex(nPos);
101 if( auto x1 = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(aTmp) )
102
103 {
104 if( rFormComp == *x1 )
105 break;
106 }
107 else if( auto x2 = o3tl::tryAccess<uno::Reference<form::XForm>>(aTmp) )
108 {
109 if( rFormComp == *x2 )
110 break;
111 }
112 else
113 {
114 OSL_ENSURE( false, "lcl_html_outEvents: wrong reflection" );
115 }
116 }
117
118 if( nPos == nCount )
119 return;
120
121 const uno::Sequence< script::ScriptEventDescriptor > aDescs =
122 xEventManager->getScriptEvents( nPos );
123 if( !aDescs.hasElements() )
124 return;
125
126 for( const script::ScriptEventDescriptor& rDesc : aDescs )
127 {
128 ScriptType eScriptType = EXTENDED_STYPE;
129 OUString aScriptType( rDesc.ScriptType );
130 if( aScriptType.equalsIgnoreAsciiCase(SVX_MACRO_LANGUAGE_JAVASCRIPT) )
131 eScriptType = JAVASCRIPT;
132 else if( aScriptType.equalsIgnoreAsciiCase(SVX_MACRO_LANGUAGE_STARBASIC ) )
133 eScriptType = STARBASIC;
134 if( JAVASCRIPT != eScriptType && !bCfgStarBasic )
135 continue;
136
137 OUString sListener( rDesc.ListenerType );
138 if (!sListener.isEmpty())
139 {
140 const sal_Int32 nIdx { sListener.lastIndexOf('.')+1 };
141 if (nIdx>0)
142 {
143 if (nIdx<sListener.getLength())
144 {
145 sListener = sListener.copy(nIdx);
146 }
147 else
148 {
149 sListener.clear();
150 }
151 }
152 }
153 OUString sMethod( rDesc.EventMethod );
154
155 const char *pOpt = nullptr;
156 for( int j=0; aEventListenerTable[j]; j++ )
157 {
158 if( sListener.equalsAscii( aEventListenerTable[j] ) &&
159 sMethod.equalsAscii( aEventMethodTable[j] ) )
160 {
161 pOpt = (STARBASIC==eScriptType ? aEventSDOptionTable
162 : aEventOptionTable)[j];
163 break;
164 }
165 }
166
167 OString sOut = " ";
168 if( pOpt && (EXTENDED_STYPE != eScriptType ||
169 rDesc.AddListenerParam.isEmpty()) )
170 sOut += pOpt;
171 else
172 {
173 sOut += OOO_STRING_SVTOOLS_HTML_O_sdevent +
174 OUStringToOString(sListener, RTL_TEXTENCODING_ASCII_US) + "-" +
175 OUStringToOString(sMethod, RTL_TEXTENCODING_ASCII_US);
176 }
177 sOut += "=\"";
178 rStrm.WriteOString( sOut );
179 HTMLOutFuncs::Out_String( rStrm, rDesc.ScriptCode, eDestEnc, pNonConvertableChars );
180 rStrm.WriteChar( '\"' );
181 if( EXTENDED_STYPE == eScriptType &&
182 !rDesc.AddListenerParam.isEmpty() )
183 {
184 sOut = " " OOO_STRING_SVTOOLS_HTML_O_sdaddparam +
185 OUStringToOString(sListener, RTL_TEXTENCODING_ASCII_US) + "-" +
186 OUStringToOString(sMethod, RTL_TEXTENCODING_ASCII_US) + "=\"";
187 rStrm.WriteOString( sOut );
188 HTMLOutFuncs::Out_String( rStrm, rDesc.AddListenerParam,
189 eDestEnc, pNonConvertableChars );
190 rStrm.WriteChar( '\"' );
191 }
192 }
193 }
194
lcl_html_isHTMLControl(sal_Int16 nClassId)195 static bool lcl_html_isHTMLControl( sal_Int16 nClassId )
196 {
197 bool bRet = false;
198
199 switch( nClassId )
200 {
201 case form::FormComponentType::TEXTFIELD:
202 case form::FormComponentType::COMMANDBUTTON:
203 case form::FormComponentType::RADIOBUTTON:
204 case form::FormComponentType::CHECKBOX:
205 case form::FormComponentType::LISTBOX:
206 case form::FormComponentType::IMAGEBUTTON:
207 case form::FormComponentType::FILECONTROL:
208 bRet = true;
209 break;
210 }
211
212 return bRet;
213 }
214
HasControls() const215 bool SwHTMLWriter::HasControls() const
216 {
217 sal_uInt32 nStartIdx = m_pCurrentPam->GetPoint()->nNode.GetIndex();
218 size_t i = 0;
219
220 // Skip all controls in front of the current paragraph
221 while ( i < m_aHTMLControls.size() && m_aHTMLControls[i]->nNdIdx < nStartIdx )
222 ++i;
223
224 return i < m_aHTMLControls.size() && m_aHTMLControls[i]->nNdIdx == nStartIdx;
225 }
226
OutForm(bool bTag_On,const SwStartNode * pStartNd)227 void SwHTMLWriter::OutForm( bool bTag_On, const SwStartNode *pStartNd )
228 {
229 if( m_bPreserveForm ) // we are in a table or an area with form spanned over it
230 return;
231
232 if( !bTag_On )
233 {
234 // end the form when all controls are output
235 if( mxFormComps.is() &&
236 mxFormComps->getCount() == m_nFormCntrlCnt )
237 {
238 OutForm( false, mxFormComps );
239 mxFormComps.clear();
240 }
241 return;
242 }
243
244 uno::Reference< container::XIndexContainer > xNewFormComps;
245 sal_uInt32 nStartIdx = pStartNd ? pStartNd->GetIndex()
246 : m_pCurrentPam->GetPoint()->nNode.GetIndex();
247
248 // skip controls before the interesting area
249 size_t i = 0;
250 while ( i < m_aHTMLControls.size() && m_aHTMLControls[i]->nNdIdx < nStartIdx )
251 ++i;
252
253 if( !pStartNd )
254 {
255 // Check for a single node: there it's only interesting, if there is
256 // a control for the node and to which form it belongs.
257 if( i < m_aHTMLControls.size() &&
258 m_aHTMLControls[i]->nNdIdx == nStartIdx )
259 xNewFormComps = m_aHTMLControls[i]->xFormComps;
260 }
261 else
262 {
263 // we iterate over a table/an area: we're interested in:
264 // - if there are controls with different start nodes
265 // - if there is a form, with controls which aren't all in the table/area
266
267 uno::Reference< container::XIndexContainer > xCurrentFormComps;// current form in table
268 const SwStartNode *pCurrentStNd = nullptr; // and the start node of a Control
269 sal_Int32 nCurrentCtrls = 0; // and the found controls in it
270 sal_uInt32 nEndIdx = pStartNd->EndOfSectionIndex();
271 for( ; i < m_aHTMLControls.size() &&
272 m_aHTMLControls[i]->nNdIdx <= nEndIdx; i++ )
273 {
274 const SwStartNode *pCntrlStNd =
275 m_pDoc->GetNodes()[m_aHTMLControls[i]->nNdIdx]->StartOfSectionNode();
276
277 if( xCurrentFormComps.is() )
278 {
279 // already inside a form ...
280 if( xCurrentFormComps==m_aHTMLControls[i]->xFormComps )
281 {
282 // ... and the control is also inside ...
283 if( pCurrentStNd!=pCntrlStNd )
284 {
285 // ... but it's inside another cell:
286 // Then open a form above the table
287 xNewFormComps = xCurrentFormComps;
288 break;
289 }
290 nCurrentCtrls = nCurrentCtrls + m_aHTMLControls[i]->nCount;
291 }
292 else
293 {
294 // ... but the Control is in another cell:
295 // There we act as if we open a new from and continue searching.
296 xCurrentFormComps = m_aHTMLControls[i]->xFormComps;
297 pCurrentStNd = pCntrlStNd;
298 nCurrentCtrls = m_aHTMLControls[i]->nCount;
299 }
300 }
301 else
302 {
303 // We aren't in a form:
304 // There we act as if we open a form.
305 xCurrentFormComps = m_aHTMLControls[i]->xFormComps;
306 pCurrentStNd = pCntrlStNd;
307 nCurrentCtrls = m_aHTMLControls[i]->nCount;
308 }
309 }
310 if( !xNewFormComps.is() && xCurrentFormComps.is() &&
311 nCurrentCtrls != xCurrentFormComps->getCount() )
312 {
313 // A form should be opened in the table/area which isn't completely
314 // inside the table. Then we must also now open the form.
315 xNewFormComps = xCurrentFormComps;
316 }
317 }
318
319 if( !(xNewFormComps.is() &&
320 (!mxFormComps.is() || xNewFormComps != mxFormComps)) )
321 return;
322
323 // A form should be opened ...
324 if( mxFormComps.is() )
325 {
326 // ... but a form is still open: That is in every case an error,
327 // but we'll close the old form nevertheless.
328 OutForm( false, mxFormComps );
329
330 //!!!nWarn = 1; // Control will be assigned to wrong form
331 }
332
333 mxFormComps = xNewFormComps;
334
335 OutForm( true, mxFormComps );
336 uno::Reference< beans::XPropertySet > xTmp;
337 OutHiddenControls( mxFormComps, xTmp );
338 }
339
OutHiddenForms()340 void SwHTMLWriter::OutHiddenForms()
341 {
342 // Without DrawModel there can't be controls. Then you also can't access the
343 // document via UNO, because otherwise a DrawModel would be created.
344 if( !m_pDoc->getIDocumentDrawModelAccess().GetDrawModel() )
345 return;
346
347 SwDocShell *pDocSh = m_pDoc->GetDocShell();
348 if( !pDocSh )
349 return;
350
351 uno::Reference< drawing::XDrawPageSupplier > xDPSupp( pDocSh->GetBaseModel(),
352 uno::UNO_QUERY );
353 OSL_ENSURE( xDPSupp.is(), "XTextDocument not received from XModel" );
354 uno::Reference< drawing::XDrawPage > xDrawPage = xDPSupp->getDrawPage();
355
356 OSL_ENSURE( xDrawPage.is(), "XDrawPage not received" );
357 if( !xDrawPage.is() )
358 return;
359
360 uno::Reference< form::XFormsSupplier > xFormsSupplier( xDrawPage, uno::UNO_QUERY );
361 OSL_ENSURE( xFormsSupplier.is(),
362 "XFormsSupplier not received from XDrawPage" );
363
364 uno::Reference< container::XNameContainer > xTmp = xFormsSupplier->getForms();
365 OSL_ENSURE( xTmp.is(), "XForms not received" );
366 uno::Reference< container::XIndexContainer > xForms( xTmp, uno::UNO_QUERY );
367 OSL_ENSURE( xForms.is(), "XForms without container::XIndexContainer?" );
368
369 sal_Int32 nCount = xForms->getCount();
370 for( sal_Int32 i=0; i<nCount; i++)
371 {
372 uno::Any aTmp = xForms->getByIndex( i );
373 if( auto x = o3tl::tryAccess<uno::Reference<form::XForm>>(aTmp) )
374 OutHiddenForm( *x );
375 else
376 {
377 OSL_ENSURE( false, "OutHiddenForms: wrong reflection" );
378 }
379 }
380 }
381
OutHiddenForm(const uno::Reference<form::XForm> & rForm)382 void SwHTMLWriter::OutHiddenForm( const uno::Reference< form::XForm > & rForm )
383 {
384 uno::Reference< container::XIndexContainer > xFormComps( rForm, uno::UNO_QUERY );
385 if( !xFormComps.is() )
386 return;
387
388 sal_Int32 nCount = xFormComps->getCount();
389 bool bHiddenOnly = nCount > 0, bHidden = false;
390 for( sal_Int32 i=0; i<nCount; i++ )
391 {
392 uno::Any aTmp = xFormComps->getByIndex( i );
393 auto xFormComp = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(
394 aTmp);
395 OSL_ENSURE( xFormComp, "OutHiddenForm: wrong reflection" );
396 if( !xFormComp )
397 continue;
398
399 uno::Reference< form::XForm > xForm( *xFormComp, uno::UNO_QUERY );
400 if( xForm.is() )
401 OutHiddenForm( xForm );
402
403 if( bHiddenOnly )
404 {
405 uno::Reference< beans::XPropertySet > xPropSet( *xFormComp, uno::UNO_QUERY );
406 OUString sPropName("ClassId");
407 if( xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) )
408 {
409 uno::Any aAny2 = xPropSet->getPropertyValue( sPropName );
410 if( auto n = o3tl::tryAccess<sal_Int16>(aAny2) )
411 {
412 if( form::FormComponentType::HIDDENCONTROL == *n )
413 bHidden = true;
414 else if( lcl_html_isHTMLControl( *n ) )
415 bHiddenOnly = false;
416 }
417 }
418 }
419 }
420
421 if( bHidden && bHiddenOnly )
422 {
423 OutForm( true, xFormComps );
424 uno::Reference< beans::XPropertySet > xTmp;
425 OutHiddenControls( xFormComps, xTmp );
426 OutForm( false, xFormComps );
427 }
428 }
429
OutForm(bool bOn,const uno::Reference<container::XIndexContainer> & rFormComps)430 void SwHTMLWriter::OutForm( bool bOn,
431 const uno::Reference< container::XIndexContainer > & rFormComps )
432 {
433 m_nFormCntrlCnt = 0;
434
435 if( !bOn )
436 {
437 DecIndentLevel(); // indent content of form
438 if( m_bLFPossible )
439 OutNewLine();
440 HTMLOutFuncs::Out_AsciiTag( Strm(), OString(GetNamespace() + OOO_STRING_SVTOOLS_HTML_form), false );
441 m_bLFPossible = true;
442
443 return;
444 }
445
446 // the new form is opened
447 if( m_bLFPossible )
448 OutNewLine();
449 OString sOut = "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_form;
450
451 uno::Reference< beans::XPropertySet > xFormPropSet( rFormComps, uno::UNO_QUERY );
452
453 uno::Any aTmp = xFormPropSet->getPropertyValue( "Name" );
454 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
455 {
456 if( !s->isEmpty() )
457 {
458 sOut += " " OOO_STRING_SVTOOLS_HTML_O_name "=\"";
459 Strm().WriteOString( sOut );
460 HTMLOutFuncs::Out_String( Strm(), *s,
461 m_eDestEnc, &m_aNonConvertableCharacters );
462 sOut = "\"";
463 }
464 }
465
466 aTmp = xFormPropSet->getPropertyValue( "TargetURL" );
467 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
468 {
469 if ( !s->isEmpty() )
470 {
471 sOut += " " OOO_STRING_SVTOOLS_HTML_O_action "=\"";
472 Strm().WriteOString( sOut );
473 OUString aURL
474 = URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), *s);
475 HTMLOutFuncs::Out_String( Strm(), aURL, m_eDestEnc, &m_aNonConvertableCharacters );
476 sOut = "\"";
477 }
478 }
479
480 aTmp = xFormPropSet->getPropertyValue( "SubmitMethod" );
481 if( auto eMethod = o3tl::tryAccess<form::FormSubmitMethod>(aTmp) )
482 {
483 if( form::FormSubmitMethod_POST==*eMethod )
484 {
485 sOut += " " OOO_STRING_SVTOOLS_HTML_O_method "=\""
486 OOO_STRING_SVTOOLS_HTML_METHOD_post "\"";
487 }
488 }
489 aTmp = xFormPropSet->getPropertyValue( "SubmitEncoding" );
490 if( auto eEncType = o3tl::tryAccess<form::FormSubmitEncoding>(aTmp) )
491 {
492 const char *pStr = nullptr;
493 switch( *eEncType )
494 {
495 case form::FormSubmitEncoding_MULTIPART:
496 pStr = OOO_STRING_SVTOOLS_HTML_ET_multipart;
497 break;
498 case form::FormSubmitEncoding_TEXT:
499 pStr = OOO_STRING_SVTOOLS_HTML_ET_text;
500 break;
501 default:
502 ;
503 }
504
505 if( pStr )
506 {
507 sOut += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_enctype "=\"") +
508 pStr + "\"";
509 }
510 }
511
512 aTmp = xFormPropSet->getPropertyValue( "TargetFrame" );
513 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
514 {
515 if (!s->isEmpty() )
516 {
517 sOut += " " OOO_STRING_SVTOOLS_HTML_O_target "=\"";
518 Strm().WriteOString( sOut );
519 HTMLOutFuncs::Out_String( Strm(), *s,
520 m_eDestEnc, &m_aNonConvertableCharacters );
521 sOut = "\"";
522 }
523 }
524
525 Strm().WriteOString( sOut );
526 uno::Reference< form::XFormComponent > xFormComp( rFormComps, uno::UNO_QUERY );
527 lcl_html_outEvents( Strm(), xFormComp, m_bCfgStarBasic, m_eDestEnc, &m_aNonConvertableCharacters );
528 Strm().WriteChar( '>' );
529
530 IncIndentLevel(); // indent content of form
531 m_bLFPossible = true;
532 }
533
OutHiddenControls(const uno::Reference<container::XIndexContainer> & rFormComps,const uno::Reference<beans::XPropertySet> & rPropSet)534 void SwHTMLWriter::OutHiddenControls(
535 const uno::Reference< container::XIndexContainer > & rFormComps,
536 const uno::Reference< beans::XPropertySet > & rPropSet )
537 {
538 sal_Int32 nCount = rFormComps->getCount();
539 sal_Int32 nPos = 0;
540 if( rPropSet.is() )
541 {
542 bool bDone = false;
543
544 uno::Reference< form::XFormComponent > xFC( rPropSet, uno::UNO_QUERY );
545 for( nPos=0; !bDone && nPos < nCount; nPos++ )
546 {
547 uno::Any aTmp = rFormComps->getByIndex( nPos );
548 auto x = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(aTmp);
549 OSL_ENSURE( x,
550 "OutHiddenControls: wrong reflection" );
551 bDone = x && *x == xFC;
552 }
553 }
554
555 for( ; nPos < nCount; nPos++ )
556 {
557 uno::Any aTmp = rFormComps->getByIndex( nPos );
558 auto xFC = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(aTmp);
559 OSL_ENSURE( xFC,
560 "OutHiddenControls: wrong reflection" );
561 if( !xFC )
562 continue;
563 uno::Reference< beans::XPropertySet > xPropSet( *xFC, uno::UNO_QUERY );
564
565 OUString sPropName = "ClassId";
566 if( !xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) )
567 continue;
568
569 aTmp = xPropSet->getPropertyValue( sPropName );
570 auto n = o3tl::tryAccess<sal_Int16>(aTmp);
571 if( !n )
572 continue;
573
574 if( form::FormComponentType::HIDDENCONTROL == *n )
575 {
576 if( m_bLFPossible )
577 OutNewLine( true );
578 OString sOut = "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_input " "
579 OOO_STRING_SVTOOLS_HTML_O_type "=\""
580 OOO_STRING_SVTOOLS_HTML_IT_hidden "\"";
581
582 aTmp = xPropSet->getPropertyValue( "Name" );
583 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
584 {
585 if( !s->isEmpty() )
586 {
587 sOut += " " OOO_STRING_SVTOOLS_HTML_O_name "=\"";
588 Strm().WriteOString( sOut );
589 HTMLOutFuncs::Out_String( Strm(), *s,
590 m_eDestEnc, &m_aNonConvertableCharacters );
591 sOut = "\"";
592 }
593 }
594 aTmp = xPropSet->getPropertyValue( "HiddenValue" );
595 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
596 {
597 if( !s->isEmpty() )
598 {
599 sOut += " " OOO_STRING_SVTOOLS_HTML_O_value "=\"";
600 Strm().WriteOString( sOut );
601 HTMLOutFuncs::Out_String( Strm(), *s,
602 m_eDestEnc, &m_aNonConvertableCharacters );
603 sOut = "\"";
604 }
605 }
606 sOut += ">";
607 Strm().WriteOString( sOut );
608
609 m_nFormCntrlCnt++;
610 }
611 else if( lcl_html_isHTMLControl( *n ) )
612 {
613 break;
614 }
615 }
616 }
617
618 // here are the output routines, thus the form::Forms are bundled:
619
GetHTMLControl(const SwDrawFrameFormat & rFormat)620 const SdrObject *SwHTMLWriter::GetHTMLControl( const SwDrawFrameFormat& rFormat )
621 {
622 // it must be a Draw-Format
623 OSL_ENSURE( RES_DRAWFRMFMT == rFormat.Which(),
624 "GetHTMLControl only allow for Draw-Formats" );
625
626 // Look if a SdrObject exists for it
627 const SdrObject *pObj = rFormat.FindSdrObject();
628 if( !pObj || SdrInventor::FmForm != pObj->GetObjInventor() )
629 return nullptr;
630
631 const SdrUnoObj& rFormObj = dynamic_cast<const SdrUnoObj&>(*pObj);
632 const uno::Reference< awt::XControlModel >& xControlModel =
633 rFormObj.GetUnoControlModel();
634
635 OSL_ENSURE( xControlModel.is(), "UNO-Control without model" );
636 if( !xControlModel.is() )
637 return nullptr;
638
639 uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
640
641 OUString sPropName("ClassId");
642 if( !xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) )
643 return nullptr;
644
645 uno::Any aTmp = xPropSet->getPropertyValue( sPropName );
646 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
647 {
648 if( lcl_html_isHTMLControl( *n ) )
649 {
650 return pObj;
651 }
652 }
653
654 return nullptr;
655 }
656
GetControlSize(const SdrUnoObj & rFormObj,Size & rSz,SwDoc * pDoc)657 static void GetControlSize(const SdrUnoObj& rFormObj, Size& rSz, SwDoc *pDoc)
658 {
659 SwViewShell *pVSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
660 if( !pVSh )
661 return;
662
663 uno::Reference< awt::XControl > xControl;
664 SdrView* pDrawView = pVSh->GetDrawView();
665 OSL_ENSURE( pDrawView && pVSh->GetWin(), "no DrawView or window!" );
666 if ( pDrawView && pVSh->GetWin() )
667 xControl = rFormObj.GetUnoControl( *pDrawView, *pVSh->GetWin()->GetOutDev() );
668 uno::Reference< awt::XTextLayoutConstrains > xLC( xControl, uno::UNO_QUERY );
669 OSL_ENSURE( xLC.is(), "no XTextLayoutConstrains" );
670 if( !xLC.is() )
671 return;
672
673 sal_Int16 nCols=0, nLines=0;
674 xLC->getColumnsAndLines( nCols, nLines );
675 rSz.setWidth( nCols );
676 rSz.setHeight( nLines );
677 }
678
OutHTML_DrawFrameFormatAsControl(Writer & rWrt,const SwDrawFrameFormat & rFormat,const SdrUnoObj & rFormObj,bool bInCntnr)679 Writer& OutHTML_DrawFrameFormatAsControl( Writer& rWrt,
680 const SwDrawFrameFormat& rFormat,
681 const SdrUnoObj& rFormObj,
682 bool bInCntnr )
683 {
684 const uno::Reference< awt::XControlModel >& xControlModel =
685 rFormObj.GetUnoControlModel();
686
687 OSL_ENSURE( xControlModel.is(), "UNO-Control without model" );
688 if( !xControlModel.is() )
689 return rWrt;
690
691 uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
692 uno::Reference< beans::XPropertySetInfo > xPropSetInfo =
693 xPropSet->getPropertySetInfo();
694
695 SwHTMLWriter & rHTMLWrt = static_cast<SwHTMLWriter&>(rWrt);
696 rHTMLWrt.m_nFormCntrlCnt++;
697
698 enum Tag { TAG_INPUT, TAG_SELECT, TAG_TEXTAREA, TAG_NONE };
699 static char const * const TagNames[] = {
700 OOO_STRING_SVTOOLS_HTML_input, OOO_STRING_SVTOOLS_HTML_select,
701 OOO_STRING_SVTOOLS_HTML_textarea };
702 Tag eTag = TAG_INPUT;
703 enum Type {
704 TYPE_TEXT, TYPE_PASSWORD, TYPE_CHECKBOX, TYPE_RADIO, TYPE_FILE,
705 TYPE_SUBMIT, TYPE_IMAGE, TYPE_RESET, TYPE_BUTTON, TYPE_NONE };
706 static char const * const TypeNames[] = {
707 OOO_STRING_SVTOOLS_HTML_IT_text, OOO_STRING_SVTOOLS_HTML_IT_password,
708 OOO_STRING_SVTOOLS_HTML_IT_checkbox, OOO_STRING_SVTOOLS_HTML_IT_radio,
709 OOO_STRING_SVTOOLS_HTML_IT_file, OOO_STRING_SVTOOLS_HTML_IT_submit,
710 OOO_STRING_SVTOOLS_HTML_IT_image, OOO_STRING_SVTOOLS_HTML_IT_reset,
711 OOO_STRING_SVTOOLS_HTML_IT_button };
712 Type eType = TYPE_NONE;
713 OUString sValue;
714 OString sOptions;
715 bool bEmptyValue = false;
716 uno::Any aTmp = xPropSet->getPropertyValue( "ClassId" );
717 sal_Int16 nClassId = *o3tl::doAccess<sal_Int16>(aTmp);
718 HtmlFrmOpts nFrameOpts = HTML_FRMOPTS_CONTROL;
719 switch( nClassId )
720 {
721 case form::FormComponentType::CHECKBOX:
722 case form::FormComponentType::RADIOBUTTON:
723 eType = (form::FormComponentType::CHECKBOX == nClassId
724 ? TYPE_CHECKBOX : TYPE_RADIO);
725 aTmp = xPropSet->getPropertyValue( "DefaultState" );
726 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
727 {
728 if ( TRISTATE_FALSE != *n )
729 {
730 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_checked "=\""
731 OOO_STRING_SVTOOLS_HTML_O_checked
732 "\"";
733 }
734 }
735
736 aTmp = xPropSet->getPropertyValue( "RefValue" );
737 if( auto rVal = o3tl::tryAccess<OUString>(aTmp) )
738
739 {
740 if( rVal->isEmpty() )
741 bEmptyValue = true;
742 else if( *rVal != OOO_STRING_SVTOOLS_HTML_on )
743 sValue = *rVal;
744 }
745 break;
746
747 case form::FormComponentType::COMMANDBUTTON:
748 {
749 form::FormButtonType eButtonType = form::FormButtonType_PUSH;
750 aTmp = xPropSet->getPropertyValue( "ButtonType" );
751 if( auto t = o3tl::tryAccess<form::FormButtonType>(aTmp) )
752 eButtonType = *t;
753
754 switch( eButtonType )
755 {
756 case form::FormButtonType_RESET:
757 eType = TYPE_RESET;
758 break;
759 case form::FormButtonType_SUBMIT:
760 eType = TYPE_SUBMIT;
761 break;
762 case form::FormButtonType_PUSH:
763 default:
764 eType = TYPE_BUTTON;
765 }
766
767 aTmp = xPropSet->getPropertyValue( "Label" );
768 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
769 {
770 if( !s->isEmpty() )
771 {
772 sValue = *s;
773 }
774 }
775 }
776 break;
777
778 case form::FormComponentType::LISTBOX:
779 if( rHTMLWrt.m_bLFPossible )
780 rHTMLWrt.OutNewLine( true );
781 eTag = TAG_SELECT;
782 aTmp = xPropSet->getPropertyValue( "Dropdown" );
783 if( auto b1 = o3tl::tryAccess<bool>(aTmp) )
784 {
785 if( !*b1 )
786 {
787 Size aSz( 0, 0 );
788 GetControlSize( rFormObj, aSz, rWrt.m_pDoc );
789
790 // How many are visible ??
791 if( aSz.Height() )
792 {
793 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_size "=\"" +
794 OString::number(static_cast<sal_Int32>(aSz.Height())) + "\"";
795 }
796
797 auto aTmp2 = xPropSet->getPropertyValue( "MultiSelection" );
798 if( auto b2 = o3tl::tryAccess<bool>(aTmp2) )
799 {
800 if ( *b2 )
801 {
802 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_multiple;
803 }
804 }
805 }
806 }
807 break;
808
809 case form::FormComponentType::TEXTFIELD:
810 {
811 Size aSz( 0, 0 );
812 GetControlSize( rFormObj, aSz, rWrt.m_pDoc );
813
814 bool bMultiLine = false;
815 OUString sMultiLine("MultiLine");
816 if( xPropSetInfo->hasPropertyByName( sMultiLine ) )
817 {
818 aTmp = xPropSet->getPropertyValue( sMultiLine );
819 auto b = o3tl::tryAccess<bool>(aTmp);
820 bMultiLine = b && *b;
821 }
822
823 if( bMultiLine )
824 {
825 if( rHTMLWrt.m_bLFPossible )
826 rHTMLWrt.OutNewLine( true );
827 eTag = TAG_TEXTAREA;
828
829 if( aSz.Height() )
830 {
831 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_rows "=\"" +
832 OString::number(static_cast<sal_Int32>(aSz.Height())) + "\"";
833 }
834 if( aSz.Width() )
835 {
836 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_cols "=\"" +
837 OString::number(static_cast<sal_Int32>(aSz.Width())) + "\"";
838 }
839
840 aTmp = xPropSet->getPropertyValue( "HScroll" );
841 if( aTmp.getValueType() == cppu::UnoType<void>::get() ||
842 (aTmp.getValueType() == cppu::UnoType<bool>::get() &&
843 !*o3tl::forceAccess<bool>(aTmp)) )
844 {
845 const char *pWrapStr = nullptr;
846 auto aTmp2 = xPropSet->getPropertyValue( "HardLineBreaks" );
847 auto b = o3tl::tryAccess<bool>(aTmp2);
848 pWrapStr = (b && *b) ? OOO_STRING_SVTOOLS_HTML_WW_hard
849 : OOO_STRING_SVTOOLS_HTML_WW_soft;
850 sOptions += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_wrap "=\"") +
851 pWrapStr + "\"";
852 }
853 }
854 else
855 {
856 eType = TYPE_TEXT;
857 OUString sEchoChar("EchoChar");
858 if( xPropSetInfo->hasPropertyByName( sEchoChar ) )
859 {
860 aTmp = xPropSet->getPropertyValue( sEchoChar );
861 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
862 {
863 if( *n != 0 )
864 eType = TYPE_PASSWORD;
865 }
866 }
867
868 if( aSz.Width() )
869 {
870 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_size "=\"" +
871 OString::number(static_cast<sal_Int32>(aSz.Width())) + "\"";
872 }
873
874 aTmp = xPropSet->getPropertyValue( "MaxTextLen" );
875 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
876 {
877 if( *n != 0 )
878 {
879 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_maxlength "=\"" +
880 OString::number(static_cast<sal_Int32>(*n)) + "\"";
881 }
882 }
883
884 if( xPropSetInfo->hasPropertyByName( "DefaultText" ) )
885 {
886 aTmp = xPropSet->getPropertyValue( "DefaultText" );
887 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
888 {
889 if( !s->isEmpty() )
890 {
891 sValue = *s;
892 }
893 }
894 }
895 }
896 }
897 break;
898
899 case form::FormComponentType::FILECONTROL:
900 {
901 Size aSz( 0, 0 );
902 GetControlSize( rFormObj, aSz, rWrt.m_pDoc );
903 eType = TYPE_FILE;
904
905 if( aSz.Width() )
906 {
907 sOptions += " " OOO_STRING_SVTOOLS_HTML_O_size "=\"" +
908 OString::number(static_cast<sal_Int32>(aSz.Width())) + "\"";
909 }
910
911 // VALUE vim form: don't export because of security reasons
912 }
913 break;
914
915 case form::FormComponentType::IMAGEBUTTON:
916 eType = TYPE_IMAGE;
917 nFrameOpts = HTML_FRMOPTS_IMG_CONTROL;
918 break;
919
920 default: // doesn't know HTML
921 eTag = TAG_NONE; // therefore skip it
922 break;
923 }
924
925 if( eTag == TAG_NONE )
926 return rWrt;
927
928 OString sOut = OString::Concat("<") + TagNames[eTag];
929 if( eType != TYPE_NONE )
930 {
931 sOut += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_type "=\"") +
932 TypeNames[eType] + "\"";
933 }
934
935 aTmp = xPropSet->getPropertyValue("Name");
936 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
937 {
938 if( !s->isEmpty() )
939 {
940 sOut += " " OOO_STRING_SVTOOLS_HTML_O_name "=\"";
941 rWrt.Strm().WriteOString( sOut );
942 HTMLOutFuncs::Out_String( rWrt.Strm(), *s,
943 rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
944 sOut = "\"";
945 }
946 }
947
948 aTmp = xPropSet->getPropertyValue("Enabled");
949 if( auto b = o3tl::tryAccess<bool>(aTmp) )
950 {
951 if( !*b )
952 {
953 sOut += " " OOO_STRING_SVTOOLS_HTML_O_disabled;
954 }
955 }
956
957 if( !sValue.isEmpty() || bEmptyValue )
958 {
959 sOut += " " OOO_STRING_SVTOOLS_HTML_O_value "=\"";
960 rWrt.Strm().WriteOString( sOut );
961 HTMLOutFuncs::Out_String( rWrt.Strm(), sValue, rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
962 sOut = "\"";
963 }
964
965 sOut += " " + sOptions;
966
967 if( TYPE_IMAGE == eType )
968 {
969 aTmp = xPropSet->getPropertyValue( "ImageURL" );
970 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
971 {
972 if( !s->isEmpty() )
973 {
974 sOut += " " OOO_STRING_SVTOOLS_HTML_O_src "=\"";
975 rWrt.Strm().WriteOString( sOut );
976
977 HTMLOutFuncs::Out_String( rWrt.Strm(),
978 URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), *s),
979 rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
980 sOut = "\"";
981 }
982 }
983
984 Size aTwipSz( rFormObj.GetLogicRect().GetSize() );
985 Size aPixelSz( 0, 0 );
986 if( (aTwipSz.Width() || aTwipSz.Height()) &&
987 Application::GetDefaultDevice() )
988 {
989 aPixelSz =
990 Application::GetDefaultDevice()->LogicToPixel( aTwipSz,
991 MapMode(MapUnit::MapTwip) );
992 if( !aPixelSz.Width() && aTwipSz.Width() )
993 aPixelSz.setWidth( 1 );
994 if( !aPixelSz.Height() && aTwipSz.Height() )
995 aPixelSz.setHeight( 1 );
996 }
997
998 if( aPixelSz.Width() )
999 {
1000 sOut += " " OOO_STRING_SVTOOLS_HTML_O_width "=\"" +
1001 OString::number(static_cast<sal_Int32>(aPixelSz.Width())) + "\"";
1002 }
1003
1004 if( aPixelSz.Height() )
1005 {
1006 sOut += " " OOO_STRING_SVTOOLS_HTML_O_height "=\"" +
1007 OString::number(static_cast<sal_Int32>(aPixelSz.Height())) + "\"";
1008 }
1009 }
1010
1011 aTmp = xPropSet->getPropertyValue( "TabIndex" );
1012 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
1013 {
1014 sal_Int16 nTabIndex = *n;
1015 if( nTabIndex > 0 )
1016 {
1017 if( nTabIndex >= 32767 )
1018 nTabIndex = 32767;
1019
1020 sOut += " " OOO_STRING_SVTOOLS_HTML_O_tabindex "=\"" +
1021 OString::number(static_cast<sal_Int32>(nTabIndex)) + "\"";
1022 }
1023 }
1024
1025 if( !sOut.isEmpty() )
1026 rWrt.Strm().WriteOString( sOut );
1027
1028 OSL_ENSURE( !bInCntnr, "Container is not supported for Controls" );
1029 if( rHTMLWrt.IsHTMLMode( HTMLMODE_ABS_POS_DRAW ) && !bInCntnr )
1030 {
1031 // If Character-Objects can't be positioned absolutely,
1032 // then delete the corresponding flag.
1033 nFrameOpts |= (TYPE_IMAGE == eType
1034 ? HTML_FRMOPTS_IMG_CONTROL_CSS1
1035 : HTML_FRMOPTS_CONTROL_CSS1);
1036 }
1037 OString aEndTags;
1038 if( nFrameOpts != HtmlFrmOpts::NONE )
1039 aEndTags = rHTMLWrt.OutFrameFormatOptions(rFormat, OUString(), nFrameOpts);
1040
1041 if( rHTMLWrt.m_bCfgOutStyles )
1042 {
1043 bool bEdit = TAG_TEXTAREA == eTag || TYPE_FILE == eType ||
1044 TYPE_TEXT == eType;
1045
1046 SfxItemSet aItemSet( rHTMLWrt.m_pDoc->GetAttrPool(), svl::Items<RES_CHRATR_BEGIN,
1047 RES_CHRATR_END>{} );
1048 if( xPropSetInfo->hasPropertyByName( "BackgroundColor" ) )
1049 {
1050 aTmp = xPropSet->getPropertyValue( "BackgroundColor" );
1051 if( auto n = o3tl::tryAccess<sal_Int32>(aTmp) )
1052 {
1053 Color aCol(ColorTransparency, *n);
1054 aItemSet.Put( SvxBrushItem( aCol, RES_CHRATR_BACKGROUND ) );
1055 }
1056 }
1057 if( xPropSetInfo->hasPropertyByName( "TextColor" ) )
1058 {
1059 aTmp = xPropSet->getPropertyValue( "TextColor" );
1060 if( auto n = o3tl::tryAccess<sal_Int32>(aTmp) )
1061 {
1062 Color aColor( ColorTransparency, *n );
1063 aItemSet.Put( SvxColorItem( aColor, RES_CHRATR_COLOR ) );
1064 }
1065 }
1066 if( xPropSetInfo->hasPropertyByName( "FontHeight" ) )
1067 {
1068 aTmp = xPropSet->getPropertyValue( "FontHeight" );
1069 if( auto nHeight = o3tl::tryAccess<float>(aTmp) )
1070
1071 {
1072 if( *nHeight > 0 && (!bEdit || !rtl::math::approxEqual(*nHeight, 10.0)) )
1073 aItemSet.Put( SvxFontHeightItem( sal_Int16(*nHeight * 20.), 100, RES_CHRATR_FONTSIZE ) );
1074 }
1075 }
1076 if( xPropSetInfo->hasPropertyByName( "FontName" ) )
1077 {
1078 aTmp = xPropSet->getPropertyValue( "FontName" );
1079 if( auto aFName = o3tl::tryAccess<OUString>(aTmp) )
1080 {
1081 if( !aFName->isEmpty() )
1082 {
1083 vcl::Font aFixedFont( OutputDevice::GetDefaultFont(
1084 DefaultFontType::FIXED, LANGUAGE_ENGLISH_US,
1085 GetDefaultFontFlags::OnlyOne ) );
1086 if( !bEdit || *aFName != aFixedFont.GetFamilyName() )
1087 {
1088 FontFamily eFamily = FAMILY_DONTKNOW;
1089 if( xPropSetInfo->hasPropertyByName( "FontFamily" ) )
1090 {
1091 auto aTmp2 = xPropSet->getPropertyValue( "FontFamily" );
1092 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp2) )
1093 eFamily = static_cast<FontFamily>(*n);
1094 }
1095 SvxFontItem aItem(eFamily, *aFName, OUString(), PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, RES_CHRATR_FONT);
1096 aItemSet.Put( aItem );
1097 }
1098 }
1099 }
1100 }
1101 if( xPropSetInfo->hasPropertyByName( "FontWeight" ) )
1102 {
1103 aTmp = xPropSet->getPropertyValue( "FontWeight" );
1104 if( auto x = o3tl::tryAccess<float>(aTmp) )
1105 {
1106 FontWeight eWeight =
1107 vcl::unohelper::ConvertFontWeight( *x );
1108 if( eWeight != WEIGHT_DONTKNOW && eWeight != WEIGHT_NORMAL )
1109 aItemSet.Put( SvxWeightItem( eWeight, RES_CHRATR_WEIGHT ) );
1110 }
1111 }
1112 if( xPropSetInfo->hasPropertyByName( "FontSlant" ) )
1113 {
1114 aTmp = xPropSet->getPropertyValue( "FontSlant" );
1115 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
1116 {
1117 FontItalic eItalic = static_cast<FontItalic>(*n);
1118 if( eItalic != ITALIC_DONTKNOW && eItalic != ITALIC_NONE )
1119 aItemSet.Put( SvxPostureItem( eItalic, RES_CHRATR_POSTURE ) );
1120 }
1121 }
1122 if( xPropSetInfo->hasPropertyByName( "FontLineStyle" ) )
1123 {
1124 aTmp = xPropSet->getPropertyValue( "FontLineStyle" );
1125 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
1126 {
1127 FontLineStyle eUnderline = static_cast<FontLineStyle>(*n);
1128 if( eUnderline != LINESTYLE_DONTKNOW &&
1129 eUnderline != LINESTYLE_NONE )
1130 aItemSet.Put( SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ) );
1131 }
1132 }
1133 if( xPropSetInfo->hasPropertyByName( "FontStrikeout" ) )
1134 {
1135 aTmp = xPropSet->getPropertyValue( "FontStrikeout" );
1136 if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) )
1137 {
1138 FontStrikeout eStrikeout = static_cast<FontStrikeout>(*n);
1139 if( eStrikeout != STRIKEOUT_DONTKNOW &&
1140 eStrikeout != STRIKEOUT_NONE )
1141 aItemSet.Put( SvxCrossedOutItem( eStrikeout, RES_CHRATR_CROSSEDOUT ) );
1142 }
1143 }
1144
1145 rHTMLWrt.OutCSS1_FrameFormatOptions( rFormat, nFrameOpts, &rFormObj,
1146 &aItemSet );
1147 }
1148
1149 uno::Reference< form::XFormComponent > xFormComp( xControlModel, uno::UNO_QUERY );
1150 lcl_html_outEvents( rWrt.Strm(), xFormComp, rHTMLWrt.m_bCfgStarBasic,
1151 rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1152
1153 rWrt.Strm().WriteChar( '>' );
1154
1155 if( TAG_SELECT == eTag )
1156 {
1157 aTmp = xPropSet->getPropertyValue( "StringItemList" );
1158 if( auto aList = o3tl::tryAccess<uno::Sequence<OUString>>(aTmp) )
1159 {
1160 rHTMLWrt.IncIndentLevel(); // the content of Select can be indented
1161 sal_Int32 nCnt = aList->getLength();
1162 const OUString *pStrings = aList->getConstArray();
1163
1164 const OUString *pValues = nullptr;
1165 sal_Int32 nValCnt = 0;
1166 auto aTmp2 = xPropSet->getPropertyValue( "ListSource" );
1167 uno::Sequence<OUString> aValList;
1168 if( auto s = o3tl::tryAccess<uno::Sequence<OUString>>(aTmp2) )
1169 {
1170 aValList = *s;
1171 nValCnt = aValList.getLength();
1172 pValues = aValList.getConstArray();
1173 }
1174
1175 uno::Any aSelTmp = xPropSet->getPropertyValue( "DefaultSelection" );
1176 const sal_Int16 *pSels = nullptr;
1177 sal_Int32 nSel = 0;
1178 sal_Int32 nSelCnt = 0;
1179 uno::Sequence<sal_Int16> aSelList;
1180 if( auto s = o3tl::tryAccess<uno::Sequence<sal_Int16>>(aSelTmp) )
1181 {
1182 aSelList = *s;
1183 nSelCnt = aSelList.getLength();
1184 pSels = aSelList.getConstArray();
1185 }
1186
1187 for( sal_Int32 i = 0; i < nCnt; i++ )
1188 {
1189 OUString sVal;
1190 bool bSelected = false, bEmptyVal = false;
1191 if( i < nValCnt )
1192 {
1193 const OUString& rVal = pValues[i];
1194 if( rVal == "$$$empty$$$" )
1195 bEmptyVal = true;
1196 else
1197 sVal = rVal;
1198 }
1199
1200 bSelected = (nSel < nSelCnt) && pSels[nSel] == i;
1201 if( bSelected )
1202 nSel++;
1203
1204 rHTMLWrt.OutNewLine(); // every Option gets its own line
1205 sOut = "<" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_option;
1206 if( !sVal.isEmpty() || bEmptyVal )
1207 {
1208 sOut += " " OOO_STRING_SVTOOLS_HTML_O_value "=\"";
1209 rWrt.Strm().WriteOString( sOut );
1210 HTMLOutFuncs::Out_String( rWrt.Strm(), sVal,
1211 rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1212 sOut = "\"";
1213 }
1214 if( bSelected )
1215 sOut += " " OOO_STRING_SVTOOLS_HTML_O_selected;
1216
1217 sOut += ">";
1218 rWrt.Strm().WriteOString( sOut );
1219
1220 HTMLOutFuncs::Out_String( rWrt.Strm(), pStrings[i],
1221 rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1222 }
1223 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_option), false );
1224
1225 rHTMLWrt.DecIndentLevel();
1226 rHTMLWrt.OutNewLine();// the </SELECT> gets its own line
1227 }
1228 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_select), false );
1229 }
1230 else if( TAG_TEXTAREA == eTag )
1231 {
1232 // In TextAreas no additional spaces or LF may be exported!
1233 OUString sVal;
1234 aTmp = xPropSet->getPropertyValue( "DefaultText" );
1235 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
1236 {
1237 if( !s->isEmpty() )
1238 {
1239 sVal = *s;
1240 }
1241 }
1242 if( !sVal.isEmpty() )
1243 {
1244 sVal = convertLineEnd(sVal, LINEEND_LF);
1245 sal_Int32 nPos = 0;
1246 while ( nPos != -1 )
1247 {
1248 if( nPos )
1249 rWrt.Strm().WriteCharPtr( SAL_NEWLINE_STRING );
1250 OUString aLine = sVal.getToken( 0, 0x0A, nPos );
1251 HTMLOutFuncs::Out_String( rWrt.Strm(), aLine,
1252 rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters );
1253 }
1254 }
1255 HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), OString(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_textarea), false );
1256 }
1257 else if( TYPE_CHECKBOX == eType || TYPE_RADIO == eType )
1258 {
1259 aTmp = xPropSet->getPropertyValue("Label");
1260 if( auto s = o3tl::tryAccess<OUString>(aTmp) )
1261 {
1262 if( !s->isEmpty() )
1263 {
1264 HTMLOutFuncs::Out_String( rWrt.Strm(), *s,
1265 rHTMLWrt.m_eDestEnc, &rHTMLWrt.m_aNonConvertableCharacters ).WriteChar( ' ' );
1266 }
1267 }
1268 }
1269
1270 if( !aEndTags.isEmpty() )
1271 rWrt.Strm().WriteOString( aEndTags );
1272
1273 // Controls aren't bound to a paragraph, therefore don't output LF anymore!
1274 rHTMLWrt.m_bLFPossible = false;
1275
1276 if( rHTMLWrt.mxFormComps.is() )
1277 rHTMLWrt.OutHiddenControls( rHTMLWrt.mxFormComps, xPropSet );
1278 return rWrt;
1279 }
1280
1281 /**
1282 * Find out if a format belongs to a control and if yes return its form.
1283 */
AddControl(HTMLControls & rControls,const SdrUnoObj & rFormObj,sal_uInt32 nNodeIdx)1284 static void AddControl( HTMLControls& rControls,
1285 const SdrUnoObj& rFormObj,
1286 sal_uInt32 nNodeIdx )
1287 {
1288 const uno::Reference< awt::XControlModel >& xControlModel =
1289 rFormObj.GetUnoControlModel();
1290 if( !xControlModel.is() )
1291 return;
1292
1293 uno::Reference< form::XFormComponent > xFormComp( xControlModel, uno::UNO_QUERY );
1294 uno::Reference< uno::XInterface > xIfc = xFormComp->getParent();
1295 uno::Reference< form::XForm > xForm(xIfc, uno::UNO_QUERY);
1296
1297 OSL_ENSURE( xForm.is(), "Where is the form?" );
1298 if( xForm.is() )
1299 {
1300 uno::Reference< container::XIndexContainer > xFormComps( xForm, uno::UNO_QUERY );
1301 std::unique_ptr<HTMLControl> pHCntrl(new HTMLControl( xFormComps, nNodeIdx ));
1302 auto itPair = rControls.insert( std::move(pHCntrl) );
1303 if (!itPair.second )
1304 {
1305 if( (*itPair.first)->xFormComps==xFormComps )
1306 (*itPair.first)->nCount++;
1307 }
1308 }
1309 }
1310
GetControls()1311 void SwHTMLWriter::GetControls()
1312 {
1313 // Idea: first off collect the paragraph- and character-bound controls.
1314 // In the process for every control the paragraph position and VCForm are
1315 // saved in an array.
1316 // With that array it's possible to find out where form::Forms must be
1317 // opened and closed.
1318
1319 if( m_pHTMLPosFlyFrames )
1320 {
1321 // collect the paragraph-bound controls
1322 for( size_t i=0; i<m_pHTMLPosFlyFrames->size(); i++ )
1323 {
1324 const SwHTMLPosFlyFrame* pPosFlyFrame = (*m_pHTMLPosFlyFrames)[ i ].get();
1325 if( HtmlOut::Control != pPosFlyFrame->GetOutFn() )
1326 continue;
1327
1328 const SdrObject *pSdrObj = pPosFlyFrame->GetSdrObject();
1329 OSL_ENSURE( pSdrObj, "Where is the SdrObject?" );
1330 if( !pSdrObj )
1331 continue;
1332
1333 AddControl( m_aHTMLControls, dynamic_cast<const SdrUnoObj&>(*pSdrObj),
1334 pPosFlyFrame->GetNdIndex().GetIndex() );
1335 }
1336 }
1337
1338 // and now the ones in a character-bound frame
1339 const SwFrameFormats* pSpzFrameFormats = m_pDoc->GetSpzFrameFormats();
1340 for( size_t i=0; i<pSpzFrameFormats->size(); i++ )
1341 {
1342 const SwFrameFormat *pFrameFormat = (*pSpzFrameFormats)[i];
1343 if( RES_DRAWFRMFMT != pFrameFormat->Which() )
1344 continue;
1345
1346 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
1347 const SwPosition *pPos = rAnchor.GetContentAnchor();
1348 if ((RndStdIds::FLY_AS_CHAR != rAnchor.GetAnchorId()) || !pPos)
1349 continue;
1350
1351 const SdrObject *pSdrObj =
1352 SwHTMLWriter::GetHTMLControl( *static_cast<const SwDrawFrameFormat*>(pFrameFormat) );
1353 if( !pSdrObj )
1354 continue;
1355
1356 AddControl( m_aHTMLControls, dynamic_cast<const SdrUnoObj&>(*pSdrObj), pPos->nNode.GetIndex() );
1357 }
1358 }
1359
HTMLControl(const uno::Reference<container::XIndexContainer> & rFormComps,sal_uInt32 nIdx)1360 HTMLControl::HTMLControl(
1361 const uno::Reference< container::XIndexContainer > & rFormComps,
1362 sal_uInt32 nIdx ) :
1363 xFormComps( rFormComps ), nNdIdx( nIdx ), nCount( 1 )
1364 {}
1365
~HTMLControl()1366 HTMLControl::~HTMLControl()
1367 {}
1368
1369 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1370