diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/filter/html/htmlforw.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/filter/html/htmlforw.cxx')
-rw-r--r-- | sw/source/filter/html/htmlforw.cxx | 1337 |
1 files changed, 1337 insertions, 0 deletions
diff --git a/sw/source/filter/html/htmlforw.cxx b/sw/source/filter/html/htmlforw.cxx new file mode 100644 index 0000000000..98423fc96a --- /dev/null +++ b/sw/source/filter/html/htmlforw.cxx @@ -0,0 +1,1337 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/form/FormSubmitEncoding.hpp> +#include <com/sun/star/form/FormSubmitMethod.hpp> +#include <com/sun/star/form/FormButtonType.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/script/XEventAttacherManager.hpp> +#include <com/sun/star/drawing/XDrawPageSupplier.hpp> +#include <com/sun/star/form/XFormsSupplier.hpp> +#include <com/sun/star/form/XForm.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/awt/XTextLayoutConstrains.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <hintids.hxx> +#include <o3tl/any.hxx> +#include <rtl/math.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <svl/macitem.hxx> +#include <svtools/htmlout.hxx> +#include <svtools/htmlkywd.hxx> +#include <svl/urihelper.hxx> +#include <vcl/unohelp.hxx> +#include <svx/svdouno.hxx> +#include <editeng/brushitem.hxx> +#include <editeng/colritem.hxx> +#include <editeng/fhgtitem.hxx> +#include <editeng/fontitem.hxx> +#include <editeng/wghtitem.hxx> +#include <editeng/postitem.hxx> +#include <editeng/udlnitem.hxx> +#include <editeng/crossedoutitem.hxx> +#include <osl/diagnose.h> +#include <docsh.hxx> +#include <fmtanchr.hxx> +#include <viewsh.hxx> +#include <pam.hxx> +#include <doc.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include "wrthtml.hxx" +#include "htmlfly.hxx" +#include "htmlform.hxx" +#include <frmfmt.hxx> +#include <frameformats.hxx> +#include <memory> + +using namespace ::com::sun::star; + +const HtmlFrmOpts HTML_FRMOPTS_CONTROL = + HtmlFrmOpts::NONE; +const HtmlFrmOpts HTML_FRMOPTS_CONTROL_CSS1 = + HtmlFrmOpts::SAlign | + HtmlFrmOpts::SSize | + HtmlFrmOpts::SSpace | + HtmlFrmOpts::BrClear; +const HtmlFrmOpts HTML_FRMOPTS_IMG_CONTROL = + HtmlFrmOpts::Align | + HtmlFrmOpts::BrClear; +const HtmlFrmOpts HTML_FRMOPTS_IMG_CONTROL_CSS1 = + HtmlFrmOpts::SAlign | + HtmlFrmOpts::SSpace; + +static void lcl_html_outEvents( SvStream& rStrm, + const uno::Reference< form::XFormComponent >& rFormComp, + bool bCfgStarBasic ) +{ + uno::Reference< uno::XInterface > xParentIfc = rFormComp->getParent(); + OSL_ENSURE( xParentIfc.is(), "lcl_html_outEvents: no parent interface" ); + if( !xParentIfc.is() ) + return; + uno::Reference< container::XIndexAccess > xIndexAcc( xParentIfc, uno::UNO_QUERY ); + uno::Reference< script::XEventAttacherManager > xEventManager( xParentIfc, + uno::UNO_QUERY ); + if( !xIndexAcc.is() || !xEventManager.is() ) + return; + + // and search for the position of the ControlModel within + sal_Int32 nCount = xIndexAcc->getCount(), nPos; + for( nPos = 0 ; nPos < nCount; nPos++ ) + { + uno::Any aTmp = xIndexAcc->getByIndex(nPos); + if( auto x1 = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(aTmp) ) + + { + if( rFormComp == *x1 ) + break; + } + else if( auto x2 = o3tl::tryAccess<uno::Reference<form::XForm>>(aTmp) ) + { + if( rFormComp == *x2 ) + break; + } + else + { + OSL_ENSURE( false, "lcl_html_outEvents: wrong reflection" ); + } + } + + if( nPos == nCount ) + return; + + const uno::Sequence< script::ScriptEventDescriptor > aDescs = + xEventManager->getScriptEvents( nPos ); + if( !aDescs.hasElements() ) + return; + + for( const script::ScriptEventDescriptor& rDesc : aDescs ) + { + ScriptType eScriptType = EXTENDED_STYPE; + OUString aScriptType( rDesc.ScriptType ); + if( aScriptType.equalsIgnoreAsciiCase(SVX_MACRO_LANGUAGE_JAVASCRIPT) ) + eScriptType = JAVASCRIPT; + else if( aScriptType.equalsIgnoreAsciiCase(SVX_MACRO_LANGUAGE_STARBASIC ) ) + eScriptType = STARBASIC; + if( JAVASCRIPT != eScriptType && !bCfgStarBasic ) + continue; + + OUString sListener( rDesc.ListenerType ); + if (!sListener.isEmpty()) + { + const sal_Int32 nIdx { sListener.lastIndexOf('.')+1 }; + if (nIdx>0) + { + if (nIdx<sListener.getLength()) + { + sListener = sListener.copy(nIdx); + } + else + { + sListener.clear(); + } + } + } + OUString sMethod( rDesc.EventMethod ); + + const char *pOpt = nullptr; + for( int j=0; aEventListenerTable[j]; j++ ) + { + if( sListener.equalsAscii( aEventListenerTable[j] ) && + sMethod.equalsAscii( aEventMethodTable[j] ) ) + { + pOpt = (STARBASIC==eScriptType ? aEventSDOptionTable + : aEventOptionTable)[j]; + break; + } + } + + OString sOut = " "_ostr; + if( pOpt && (EXTENDED_STYPE != eScriptType || + rDesc.AddListenerParam.isEmpty()) ) + sOut += pOpt; + else + { + sOut += OOO_STRING_SVTOOLS_HTML_O_sdevent + + OUStringToOString(sListener, RTL_TEXTENCODING_ASCII_US) + "-" + + OUStringToOString(sMethod, RTL_TEXTENCODING_ASCII_US); + } + sOut += "=\""; + rStrm.WriteOString( sOut ); + HTMLOutFuncs::Out_String( rStrm, rDesc.ScriptCode ); + rStrm.WriteChar( '\"' ); + if( EXTENDED_STYPE == eScriptType && + !rDesc.AddListenerParam.isEmpty() ) + { + sOut = " " OOO_STRING_SVTOOLS_HTML_O_sdaddparam + + OUStringToOString(sListener, RTL_TEXTENCODING_ASCII_US) + "-" + + OUStringToOString(sMethod, RTL_TEXTENCODING_ASCII_US) + "=\""; + rStrm.WriteOString( sOut ); + HTMLOutFuncs::Out_String( rStrm, rDesc.AddListenerParam ); + rStrm.WriteChar( '\"' ); + } + } +} + +static bool lcl_html_isHTMLControl( sal_Int16 nClassId ) +{ + bool bRet = false; + + switch( nClassId ) + { + case form::FormComponentType::TEXTFIELD: + case form::FormComponentType::COMMANDBUTTON: + case form::FormComponentType::RADIOBUTTON: + case form::FormComponentType::CHECKBOX: + case form::FormComponentType::LISTBOX: + case form::FormComponentType::IMAGEBUTTON: + case form::FormComponentType::FILECONTROL: + bRet = true; + break; + } + + return bRet; +} + +bool SwHTMLWriter::HasControls() const +{ + SwNodeOffset nStartIdx = m_pCurrentPam->GetPoint()->GetNodeIndex(); + size_t i = 0; + + // Skip all controls in front of the current paragraph + while ( i < m_aHTMLControls.size() && m_aHTMLControls[i]->nNdIdx < nStartIdx ) + ++i; + + return i < m_aHTMLControls.size() && m_aHTMLControls[i]->nNdIdx == nStartIdx; +} + +void SwHTMLWriter::OutForm( bool bTag_On, const SwStartNode *pStartNd ) +{ + if( m_bPreserveForm ) // we are in a table or an area with form spanned over it + return; + + if( !bTag_On ) + { + // end the form when all controls are output + if( mxFormComps.is() && + mxFormComps->getCount() == m_nFormCntrlCnt ) + { + OutForm( false, mxFormComps ); + mxFormComps.clear(); + } + return; + } + + uno::Reference< container::XIndexContainer > xNewFormComps; + SwNodeOffset nStartIdx = pStartNd ? pStartNd->GetIndex() + : m_pCurrentPam->GetPoint()->GetNodeIndex(); + + // skip controls before the interesting area + size_t i = 0; + while ( i < m_aHTMLControls.size() && m_aHTMLControls[i]->nNdIdx < nStartIdx ) + ++i; + + if( !pStartNd ) + { + // Check for a single node: there it's only interesting, if there is + // a control for the node and to which form it belongs. + if( i < m_aHTMLControls.size() && + m_aHTMLControls[i]->nNdIdx == nStartIdx ) + xNewFormComps = m_aHTMLControls[i]->xFormComps; + } + else + { + // we iterate over a table/an area: we're interested in: + // - if there are controls with different start nodes + // - if there is a form, with controls which aren't all in the table/area + + uno::Reference< container::XIndexContainer > xCurrentFormComps;// current form in table + const SwStartNode *pCurrentStNd = nullptr; // and the start node of a Control + sal_Int32 nCurrentCtrls = 0; // and the found controls in it + SwNodeOffset nEndIdx = pStartNd->EndOfSectionIndex(); + for( ; i < m_aHTMLControls.size() && + m_aHTMLControls[i]->nNdIdx <= nEndIdx; i++ ) + { + const SwStartNode *pCntrlStNd = + m_pDoc->GetNodes()[m_aHTMLControls[i]->nNdIdx]->StartOfSectionNode(); + + if( xCurrentFormComps.is() ) + { + // already inside a form ... + if( xCurrentFormComps==m_aHTMLControls[i]->xFormComps ) + { + // ... and the control is also inside ... + if( pCurrentStNd!=pCntrlStNd ) + { + // ... but it's inside another cell: + // Then open a form above the table + xNewFormComps = xCurrentFormComps; + break; + } + nCurrentCtrls = nCurrentCtrls + m_aHTMLControls[i]->nCount; + } + else + { + // ... but the Control is in another cell: + // There we act as if we open a new from and continue searching. + xCurrentFormComps = m_aHTMLControls[i]->xFormComps; + pCurrentStNd = pCntrlStNd; + nCurrentCtrls = m_aHTMLControls[i]->nCount; + } + } + else + { + // We aren't in a form: + // There we act as if we open a form. + xCurrentFormComps = m_aHTMLControls[i]->xFormComps; + pCurrentStNd = pCntrlStNd; + nCurrentCtrls = m_aHTMLControls[i]->nCount; + } + } + if( !xNewFormComps.is() && xCurrentFormComps.is() && + nCurrentCtrls != xCurrentFormComps->getCount() ) + { + // A form should be opened in the table/area which isn't completely + // inside the table. Then we must also now open the form. + xNewFormComps = xCurrentFormComps; + } + } + + if( !(xNewFormComps.is() && + (!mxFormComps.is() || xNewFormComps != mxFormComps)) ) + return; + + // A form should be opened ... + if( mxFormComps.is() ) + { + // ... but a form is still open: That is in every case an error, + // but we'll close the old form nevertheless. + OutForm( false, mxFormComps ); + + //!!!nWarn = 1; // Control will be assigned to wrong form + } + + mxFormComps = xNewFormComps; + + OutForm( true, mxFormComps ); + uno::Reference< beans::XPropertySet > xTmp; + OutHiddenControls( mxFormComps, xTmp ); +} + +void SwHTMLWriter::OutHiddenForms() +{ + // Without DrawModel there can't be controls. Then you also can't access the + // document via UNO, because otherwise a DrawModel would be created. + if( !m_pDoc->getIDocumentDrawModelAccess().GetDrawModel() ) + return; + + SwDocShell *pDocSh = m_pDoc->GetDocShell(); + if( !pDocSh ) + return; + + uno::Reference< drawing::XDrawPageSupplier > xDPSupp( pDocSh->GetBaseModel(), + uno::UNO_QUERY ); + OSL_ENSURE( xDPSupp.is(), "XTextDocument not received from XModel" ); + uno::Reference< drawing::XDrawPage > xDrawPage = xDPSupp->getDrawPage(); + + OSL_ENSURE( xDrawPage.is(), "XDrawPage not received" ); + if( !xDrawPage.is() ) + return; + + uno::Reference< form::XFormsSupplier > xFormsSupplier( xDrawPage, uno::UNO_QUERY ); + OSL_ENSURE( xFormsSupplier.is(), + "XFormsSupplier not received from XDrawPage" ); + + uno::Reference< container::XNameContainer > xTmp = xFormsSupplier->getForms(); + OSL_ENSURE( xTmp.is(), "XForms not received" ); + uno::Reference< container::XIndexContainer > xForms( xTmp, uno::UNO_QUERY ); + OSL_ENSURE( xForms.is(), "XForms without container::XIndexContainer?" ); + + sal_Int32 nCount = xForms->getCount(); + for( sal_Int32 i=0; i<nCount; i++) + { + uno::Any aTmp = xForms->getByIndex( i ); + if( auto x = o3tl::tryAccess<uno::Reference<form::XForm>>(aTmp) ) + OutHiddenForm( *x ); + else + { + OSL_ENSURE( false, "OutHiddenForms: wrong reflection" ); + } + } +} + +void SwHTMLWriter::OutHiddenForm( const uno::Reference< form::XForm > & rForm ) +{ + uno::Reference< container::XIndexContainer > xFormComps( rForm, uno::UNO_QUERY ); + if( !xFormComps.is() ) + return; + + sal_Int32 nCount = xFormComps->getCount(); + bool bHiddenOnly = nCount > 0, bHidden = false; + for( sal_Int32 i=0; i<nCount; i++ ) + { + uno::Any aTmp = xFormComps->getByIndex( i ); + auto xFormComp = o3tl::tryAccess<uno::Reference<form::XFormComponent>>( + aTmp); + OSL_ENSURE( xFormComp, "OutHiddenForm: wrong reflection" ); + if( !xFormComp ) + continue; + + uno::Reference< form::XForm > xForm( *xFormComp, uno::UNO_QUERY ); + if( xForm.is() ) + OutHiddenForm( xForm ); + + if( bHiddenOnly ) + { + uno::Reference< beans::XPropertySet > xPropSet( *xFormComp, uno::UNO_QUERY ); + OUString sPropName("ClassId"); + if( xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) ) + { + uno::Any aAny2 = xPropSet->getPropertyValue( sPropName ); + if( auto n = o3tl::tryAccess<sal_Int16>(aAny2) ) + { + if( form::FormComponentType::HIDDENCONTROL == *n ) + bHidden = true; + else if( lcl_html_isHTMLControl( *n ) ) + bHiddenOnly = false; + } + } + } + } + + if( bHidden && bHiddenOnly ) + { + OutForm( true, xFormComps ); + uno::Reference< beans::XPropertySet > xTmp; + OutHiddenControls( xFormComps, xTmp ); + OutForm( false, xFormComps ); + } +} + +void SwHTMLWriter::OutForm( bool bOn, + const uno::Reference< container::XIndexContainer > & rFormComps ) +{ + m_nFormCntrlCnt = 0; + + if( !bOn ) + { + DecIndentLevel(); // indent content of form + if (IsLFPossible()) + OutNewLine(); + HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_form), false ); + SetLFPossible(true); + + return; + } + + // the new form is opened + if (IsLFPossible()) + OutNewLine(); + OString sOut = "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_form; + + uno::Reference< beans::XPropertySet > xFormPropSet( rFormComps, uno::UNO_QUERY ); + + uno::Any aTmp = xFormPropSet->getPropertyValue( "Name" ); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !s->isEmpty() ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_name "=\""; + Strm().WriteOString( sOut ); + HTMLOutFuncs::Out_String( Strm(), *s ); + sOut = "\""_ostr; + } + } + + aTmp = xFormPropSet->getPropertyValue( "TargetURL" ); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if ( !s->isEmpty() ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_action "=\""; + Strm().WriteOString( sOut ); + OUString aURL + = URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), *s); + HTMLOutFuncs::Out_String( Strm(), aURL ); + sOut = "\""_ostr; + } + } + + aTmp = xFormPropSet->getPropertyValue( "SubmitMethod" ); + if( auto eMethod = o3tl::tryAccess<form::FormSubmitMethod>(aTmp) ) + { + if( form::FormSubmitMethod_POST==*eMethod ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_method "=\"" + OOO_STRING_SVTOOLS_HTML_METHOD_post "\""; + } + } + aTmp = xFormPropSet->getPropertyValue( "SubmitEncoding" ); + if( auto eEncType = o3tl::tryAccess<form::FormSubmitEncoding>(aTmp) ) + { + const char *pStr = nullptr; + switch( *eEncType ) + { + case form::FormSubmitEncoding_MULTIPART: + pStr = OOO_STRING_SVTOOLS_HTML_ET_multipart; + break; + case form::FormSubmitEncoding_TEXT: + pStr = OOO_STRING_SVTOOLS_HTML_ET_text; + break; + default: + ; + } + + if( pStr ) + { + sOut += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_enctype "=\"") + + pStr + "\""; + } + } + + aTmp = xFormPropSet->getPropertyValue( "TargetFrame" ); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if (!s->isEmpty() ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_target "=\""; + Strm().WriteOString( sOut ); + HTMLOutFuncs::Out_String( Strm(), *s ); + sOut = "\""_ostr; + } + } + + Strm().WriteOString( sOut ); + uno::Reference< form::XFormComponent > xFormComp( rFormComps, uno::UNO_QUERY ); + lcl_html_outEvents( Strm(), xFormComp, m_bCfgStarBasic ); + Strm().WriteChar( '>' ); + + IncIndentLevel(); // indent content of form + SetLFPossible(true); +} + +void SwHTMLWriter::OutHiddenControls( + const uno::Reference< container::XIndexContainer > & rFormComps, + const uno::Reference< beans::XPropertySet > & rPropSet ) +{ + sal_Int32 nCount = rFormComps->getCount(); + sal_Int32 nPos = 0; + if( rPropSet.is() ) + { + bool bDone = false; + + uno::Reference< form::XFormComponent > xFC( rPropSet, uno::UNO_QUERY ); + for( nPos=0; !bDone && nPos < nCount; nPos++ ) + { + uno::Any aTmp = rFormComps->getByIndex( nPos ); + auto x = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(aTmp); + OSL_ENSURE( x, + "OutHiddenControls: wrong reflection" ); + bDone = x && *x == xFC; + } + } + + for( ; nPos < nCount; nPos++ ) + { + uno::Any aTmp = rFormComps->getByIndex( nPos ); + auto xFC = o3tl::tryAccess<uno::Reference<form::XFormComponent>>(aTmp); + OSL_ENSURE( xFC, + "OutHiddenControls: wrong reflection" ); + if( !xFC ) + continue; + uno::Reference< beans::XPropertySet > xPropSet( *xFC, uno::UNO_QUERY ); + + OUString sPropName = "ClassId"; + if( !xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) ) + continue; + + aTmp = xPropSet->getPropertyValue( sPropName ); + auto n = o3tl::tryAccess<sal_Int16>(aTmp); + if( !n ) + continue; + + if( form::FormComponentType::HIDDENCONTROL == *n ) + { + if (IsLFPossible()) + OutNewLine( true ); + OString sOut = "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_input " " + OOO_STRING_SVTOOLS_HTML_O_type "=\"" + OOO_STRING_SVTOOLS_HTML_IT_hidden "\""; + + aTmp = xPropSet->getPropertyValue( "Name" ); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !s->isEmpty() ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_name "=\""; + Strm().WriteOString( sOut ); + HTMLOutFuncs::Out_String( Strm(), *s ); + sOut = "\""_ostr; + } + } + aTmp = xPropSet->getPropertyValue( "HiddenValue" ); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !s->isEmpty() ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_value "=\""; + Strm().WriteOString( sOut ); + HTMLOutFuncs::Out_String( Strm(), *s ); + sOut = "\""_ostr; + } + } + sOut += ">"; + Strm().WriteOString( sOut ); + + m_nFormCntrlCnt++; + } + else if( lcl_html_isHTMLControl( *n ) ) + { + break; + } + } +} + +// here are the output routines, thus the form::Forms are bundled: + +const SdrObject *SwHTMLWriter::GetHTMLControl( const SwDrawFrameFormat& rFormat ) +{ + // it must be a Draw-Format + OSL_ENSURE( RES_DRAWFRMFMT == rFormat.Which(), + "GetHTMLControl only allow for Draw-Formats" ); + + // Look if a SdrObject exists for it + const SdrObject *pObj = rFormat.FindSdrObject(); + if( !pObj || SdrInventor::FmForm != pObj->GetObjInventor() ) + return nullptr; + + const SdrUnoObj& rFormObj = dynamic_cast<const SdrUnoObj&>(*pObj); + const uno::Reference< awt::XControlModel >& xControlModel = + rFormObj.GetUnoControlModel(); + + OSL_ENSURE( xControlModel.is(), "UNO-Control without model" ); + if( !xControlModel.is() ) + return nullptr; + + uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY ); + + OUString sPropName("ClassId"); + if( !xPropSet->getPropertySetInfo()->hasPropertyByName( sPropName ) ) + return nullptr; + + uno::Any aTmp = xPropSet->getPropertyValue( sPropName ); + if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) ) + { + if( lcl_html_isHTMLControl( *n ) ) + { + return pObj; + } + } + + return nullptr; +} + +static void GetControlSize(const SdrUnoObj& rFormObj, Size& rSz, SwDoc *pDoc) +{ + SwViewShell *pVSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell(); + if( !pVSh ) + return; + + uno::Reference< awt::XControl > xControl; + SdrView* pDrawView = pVSh->GetDrawView(); + OSL_ENSURE( pDrawView && pVSh->GetWin(), "no DrawView or window!" ); + if ( pDrawView && pVSh->GetWin() ) + xControl = rFormObj.GetUnoControl( *pDrawView, *pVSh->GetWin()->GetOutDev() ); + uno::Reference< awt::XTextLayoutConstrains > xLC( xControl, uno::UNO_QUERY ); + OSL_ENSURE( xLC.is(), "no XTextLayoutConstrains" ); + if( !xLC.is() ) + return; + + sal_Int16 nCols=0, nLines=0; + xLC->getColumnsAndLines( nCols, nLines ); + rSz.setWidth( nCols ); + rSz.setHeight( nLines ); +} + +SwHTMLWriter& OutHTML_DrawFrameFormatAsControl( SwHTMLWriter& rWrt, + const SwDrawFrameFormat& rFormat, + const SdrUnoObj& rFormObj, + bool bInCntnr ) +{ + const uno::Reference< awt::XControlModel >& xControlModel = + rFormObj.GetUnoControlModel(); + + OSL_ENSURE( xControlModel.is(), "UNO-Control without model" ); + if( !xControlModel.is() ) + return rWrt; + + uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + + rWrt.m_nFormCntrlCnt++; + + enum Tag { TAG_INPUT, TAG_SELECT, TAG_TEXTAREA, TAG_NONE }; + static char const * const TagNames[] = { + OOO_STRING_SVTOOLS_HTML_input, OOO_STRING_SVTOOLS_HTML_select, + OOO_STRING_SVTOOLS_HTML_textarea }; + Tag eTag = TAG_INPUT; + enum Type { + TYPE_TEXT, TYPE_PASSWORD, TYPE_CHECKBOX, TYPE_RADIO, TYPE_FILE, + TYPE_SUBMIT, TYPE_IMAGE, TYPE_RESET, TYPE_BUTTON, TYPE_NONE }; + static char const * const TypeNames[] = { + OOO_STRING_SVTOOLS_HTML_IT_text, OOO_STRING_SVTOOLS_HTML_IT_password, + OOO_STRING_SVTOOLS_HTML_IT_checkbox, OOO_STRING_SVTOOLS_HTML_IT_radio, + OOO_STRING_SVTOOLS_HTML_IT_file, OOO_STRING_SVTOOLS_HTML_IT_submit, + OOO_STRING_SVTOOLS_HTML_IT_image, OOO_STRING_SVTOOLS_HTML_IT_reset, + OOO_STRING_SVTOOLS_HTML_IT_button }; + Type eType = TYPE_NONE; + OUString sValue; + OString sOptions; + bool bEmptyValue = false; + uno::Any aTmp = xPropSet->getPropertyValue( "ClassId" ); + sal_Int16 nClassId = *o3tl::doAccess<sal_Int16>(aTmp); + HtmlFrmOpts nFrameOpts = HTML_FRMOPTS_CONTROL; + switch( nClassId ) + { + case form::FormComponentType::CHECKBOX: + case form::FormComponentType::RADIOBUTTON: + eType = (form::FormComponentType::CHECKBOX == nClassId + ? TYPE_CHECKBOX : TYPE_RADIO); + aTmp = xPropSet->getPropertyValue( "DefaultState" ); + if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) ) + { + if ( TRISTATE_FALSE != *n ) + { + sOptions += " " OOO_STRING_SVTOOLS_HTML_O_checked "=\"" + OOO_STRING_SVTOOLS_HTML_O_checked + "\""; + } + } + + aTmp = xPropSet->getPropertyValue( "RefValue" ); + if( auto rVal = o3tl::tryAccess<OUString>(aTmp) ) + + { + if( rVal->isEmpty() ) + bEmptyValue = true; + else if( *rVal != OOO_STRING_SVTOOLS_HTML_on ) + sValue = *rVal; + } + break; + + case form::FormComponentType::COMMANDBUTTON: + { + form::FormButtonType eButtonType = form::FormButtonType_PUSH; + aTmp = xPropSet->getPropertyValue( "ButtonType" ); + if( auto t = o3tl::tryAccess<form::FormButtonType>(aTmp) ) + eButtonType = *t; + + switch( eButtonType ) + { + case form::FormButtonType_RESET: + eType = TYPE_RESET; + break; + case form::FormButtonType_SUBMIT: + eType = TYPE_SUBMIT; + break; + case form::FormButtonType_PUSH: + default: + eType = TYPE_BUTTON; + } + + aTmp = xPropSet->getPropertyValue( "Label" ); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !s->isEmpty() ) + { + sValue = *s; + } + } + } + break; + + case form::FormComponentType::LISTBOX: + if (rWrt.IsLFPossible()) + rWrt.OutNewLine( true ); + eTag = TAG_SELECT; + aTmp = xPropSet->getPropertyValue( "Dropdown" ); + if( auto b1 = o3tl::tryAccess<bool>(aTmp) ) + { + if( !*b1 ) + { + Size aSz( 0, 0 ); + GetControlSize( rFormObj, aSz, rWrt.m_pDoc ); + + // How many are visible ?? + if( aSz.Height() ) + { + sOptions += " " OOO_STRING_SVTOOLS_HTML_O_size "=\"" + + OString::number(static_cast<sal_Int32>(aSz.Height())) + "\""; + } + + auto aTmp2 = xPropSet->getPropertyValue( "MultiSelection" ); + if( auto b2 = o3tl::tryAccess<bool>(aTmp2) ) + { + if ( *b2 ) + { + sOptions += " " OOO_STRING_SVTOOLS_HTML_O_multiple; + } + } + } + } + break; + + case form::FormComponentType::TEXTFIELD: + { + Size aSz( 0, 0 ); + GetControlSize( rFormObj, aSz, rWrt.m_pDoc ); + + bool bMultiLine = false; + OUString sMultiLine("MultiLine"); + if( xPropSetInfo->hasPropertyByName( sMultiLine ) ) + { + aTmp = xPropSet->getPropertyValue( sMultiLine ); + std::optional<const bool> b = o3tl::tryAccess<bool>(aTmp); + bMultiLine = b.has_value() && *b; + } + + if( bMultiLine ) + { + if (rWrt.IsLFPossible()) + rWrt.OutNewLine( true ); + eTag = TAG_TEXTAREA; + + if( aSz.Height() ) + { + sOptions += " " OOO_STRING_SVTOOLS_HTML_O_rows "=\"" + + OString::number(static_cast<sal_Int32>(aSz.Height())) + "\""; + } + if( aSz.Width() ) + { + sOptions += " " OOO_STRING_SVTOOLS_HTML_O_cols "=\"" + + OString::number(static_cast<sal_Int32>(aSz.Width())) + "\""; + } + + aTmp = xPropSet->getPropertyValue( "HScroll" ); + if( aTmp.getValueType() == cppu::UnoType<void>::get() || + (aTmp.getValueType() == cppu::UnoType<bool>::get() && + !*o3tl::forceAccess<bool>(aTmp)) ) + { + const char *pWrapStr = nullptr; + auto aTmp2 = xPropSet->getPropertyValue( "HardLineBreaks" ); + std::optional<const bool> b = o3tl::tryAccess<bool>(aTmp2); + pWrapStr = (b.has_value() && *b) ? OOO_STRING_SVTOOLS_HTML_WW_hard + : OOO_STRING_SVTOOLS_HTML_WW_soft; + sOptions += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_wrap "=\"") + + pWrapStr + "\""; + } + } + else + { + eType = TYPE_TEXT; + OUString sEchoChar("EchoChar"); + if( xPropSetInfo->hasPropertyByName( sEchoChar ) ) + { + aTmp = xPropSet->getPropertyValue( sEchoChar ); + if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) ) + { + if( *n != 0 ) + eType = TYPE_PASSWORD; + } + } + + if( aSz.Width() ) + { + sOptions += " " OOO_STRING_SVTOOLS_HTML_O_size "=\"" + + OString::number(static_cast<sal_Int32>(aSz.Width())) + "\""; + } + + aTmp = xPropSet->getPropertyValue( "MaxTextLen" ); + if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) ) + { + if( *n != 0 ) + { + sOptions += " " OOO_STRING_SVTOOLS_HTML_O_maxlength "=\"" + + OString::number(static_cast<sal_Int32>(*n)) + "\""; + } + } + + if( xPropSetInfo->hasPropertyByName( "DefaultText" ) ) + { + aTmp = xPropSet->getPropertyValue( "DefaultText" ); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !s->isEmpty() ) + { + sValue = *s; + } + } + } + } + } + break; + + case form::FormComponentType::FILECONTROL: + { + Size aSz( 0, 0 ); + GetControlSize( rFormObj, aSz, rWrt.m_pDoc ); + eType = TYPE_FILE; + + if( aSz.Width() ) + { + sOptions += " " OOO_STRING_SVTOOLS_HTML_O_size "=\"" + + OString::number(static_cast<sal_Int32>(aSz.Width())) + "\""; + } + + // VALUE vim form: don't export because of security reasons + } + break; + + case form::FormComponentType::IMAGEBUTTON: + eType = TYPE_IMAGE; + nFrameOpts = HTML_FRMOPTS_IMG_CONTROL; + break; + + default: // doesn't know HTML + eTag = TAG_NONE; // therefore skip it + break; + } + + if( eTag == TAG_NONE ) + return rWrt; + + OString sOut = OString::Concat("<") + TagNames[eTag]; + if( eType != TYPE_NONE ) + { + sOut += OString::Concat(" " OOO_STRING_SVTOOLS_HTML_O_type "=\"") + + TypeNames[eType] + "\""; + } + + aTmp = xPropSet->getPropertyValue("Name"); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !s->isEmpty() ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_name "=\""; + rWrt.Strm().WriteOString( sOut ); + HTMLOutFuncs::Out_String( rWrt.Strm(), *s ); + sOut = "\""_ostr; + } + } + + aTmp = xPropSet->getPropertyValue("Enabled"); + if( auto b = o3tl::tryAccess<bool>(aTmp) ) + { + if( !*b ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_disabled; + } + } + + if( !sValue.isEmpty() || bEmptyValue ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_value "=\""; + rWrt.Strm().WriteOString( sOut ); + HTMLOutFuncs::Out_String( rWrt.Strm(), sValue ); + sOut = "\""_ostr; + } + + sOut += " " + sOptions; + + if( TYPE_IMAGE == eType ) + { + aTmp = xPropSet->getPropertyValue( "ImageURL" ); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !s->isEmpty() ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_src "=\""; + rWrt.Strm().WriteOString( sOut ); + + HTMLOutFuncs::Out_String( rWrt.Strm(), + URIHelper::simpleNormalizedMakeRelative( rWrt.GetBaseURL(), *s) ); + sOut = "\""_ostr; + } + } + + Size aPixelSz(SwHTMLWriter::ToPixel(rFormObj.GetLogicRect().GetSize())); + + if( aPixelSz.Width() ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_width "=\"" + + OString::number(static_cast<sal_Int32>(aPixelSz.Width())) + "\""; + } + + if( aPixelSz.Height() ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_height "=\"" + + OString::number(static_cast<sal_Int32>(aPixelSz.Height())) + "\""; + } + } + + aTmp = xPropSet->getPropertyValue( "TabIndex" ); + if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) ) + { + sal_Int16 nTabIndex = *n; + if( nTabIndex > 0 ) + { + if( nTabIndex >= 32767 ) + nTabIndex = 32767; + + sOut += " " OOO_STRING_SVTOOLS_HTML_O_tabindex "=\"" + + OString::number(static_cast<sal_Int32>(nTabIndex)) + "\""; + } + } + + if( !sOut.isEmpty() ) + rWrt.Strm().WriteOString( sOut ); + + OSL_ENSURE( !bInCntnr, "Container is not supported for Controls" ); + if( rWrt.IsHTMLMode( HTMLMODE_ABS_POS_DRAW ) && !bInCntnr ) + { + // If Character-Objects can't be positioned absolutely, + // then delete the corresponding flag. + nFrameOpts |= (TYPE_IMAGE == eType + ? HTML_FRMOPTS_IMG_CONTROL_CSS1 + : HTML_FRMOPTS_CONTROL_CSS1); + } + OString aEndTags; + if( nFrameOpts != HtmlFrmOpts::NONE ) + aEndTags = rWrt.OutFrameFormatOptions(rFormat, OUString(), nFrameOpts); + + if( rWrt.m_bCfgOutStyles ) + { + bool bEdit = TAG_TEXTAREA == eTag || TYPE_FILE == eType || + TYPE_TEXT == eType; + + SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END> aItemSet( rWrt.m_pDoc->GetAttrPool() ); + if( xPropSetInfo->hasPropertyByName( "BackgroundColor" ) ) + { + aTmp = xPropSet->getPropertyValue( "BackgroundColor" ); + if( auto n = o3tl::tryAccess<sal_Int32>(aTmp) ) + { + Color aCol(ColorTransparency, *n); + aItemSet.Put( SvxBrushItem( aCol, RES_CHRATR_BACKGROUND ) ); + } + } + if( xPropSetInfo->hasPropertyByName( "TextColor" ) ) + { + aTmp = xPropSet->getPropertyValue( "TextColor" ); + if( auto n = o3tl::tryAccess<sal_Int32>(aTmp) ) + { + Color aColor( ColorTransparency, *n ); + aItemSet.Put( SvxColorItem( aColor, RES_CHRATR_COLOR ) ); + } + } + if( xPropSetInfo->hasPropertyByName( "FontHeight" ) ) + { + aTmp = xPropSet->getPropertyValue( "FontHeight" ); + if( auto nHeight = o3tl::tryAccess<float>(aTmp) ) + + { + if( *nHeight > 0 && (!bEdit || !rtl::math::approxEqual(*nHeight, 10.0)) ) + aItemSet.Put( SvxFontHeightItem( sal_Int16(*nHeight * 20.), 100, RES_CHRATR_FONTSIZE ) ); + } + } + if( xPropSetInfo->hasPropertyByName( "FontName" ) ) + { + aTmp = xPropSet->getPropertyValue( "FontName" ); + if( auto aFName = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !aFName->isEmpty() ) + { + vcl::Font aFixedFont( OutputDevice::GetDefaultFont( + DefaultFontType::FIXED, LANGUAGE_ENGLISH_US, + GetDefaultFontFlags::OnlyOne ) ); + if( !bEdit || *aFName != aFixedFont.GetFamilyName() ) + { + FontFamily eFamily = FAMILY_DONTKNOW; + if( xPropSetInfo->hasPropertyByName( "FontFamily" ) ) + { + auto aTmp2 = xPropSet->getPropertyValue( "FontFamily" ); + if( auto n = o3tl::tryAccess<sal_Int16>(aTmp2) ) + eFamily = static_cast<FontFamily>(*n); + } + SvxFontItem aItem(eFamily, *aFName, OUString(), PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, RES_CHRATR_FONT); + aItemSet.Put( aItem ); + } + } + } + } + if( xPropSetInfo->hasPropertyByName( "FontWeight" ) ) + { + aTmp = xPropSet->getPropertyValue( "FontWeight" ); + if( auto x = o3tl::tryAccess<float>(aTmp) ) + { + FontWeight eWeight = + vcl::unohelper::ConvertFontWeight( *x ); + if( eWeight != WEIGHT_DONTKNOW && eWeight != WEIGHT_NORMAL ) + aItemSet.Put( SvxWeightItem( eWeight, RES_CHRATR_WEIGHT ) ); + } + } + if( xPropSetInfo->hasPropertyByName( "FontSlant" ) ) + { + aTmp = xPropSet->getPropertyValue( "FontSlant" ); + if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) ) + { + FontItalic eItalic = static_cast<FontItalic>(*n); + if( eItalic != ITALIC_DONTKNOW && eItalic != ITALIC_NONE ) + aItemSet.Put( SvxPostureItem( eItalic, RES_CHRATR_POSTURE ) ); + } + } + if( xPropSetInfo->hasPropertyByName( "FontLineStyle" ) ) + { + aTmp = xPropSet->getPropertyValue( "FontLineStyle" ); + if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) ) + { + FontLineStyle eUnderline = static_cast<FontLineStyle>(*n); + if( eUnderline != LINESTYLE_DONTKNOW && + eUnderline != LINESTYLE_NONE ) + aItemSet.Put( SvxUnderlineItem( eUnderline, RES_CHRATR_UNDERLINE ) ); + } + } + if( xPropSetInfo->hasPropertyByName( "FontStrikeout" ) ) + { + aTmp = xPropSet->getPropertyValue( "FontStrikeout" ); + if( auto n = o3tl::tryAccess<sal_Int16>(aTmp) ) + { + FontStrikeout eStrikeout = static_cast<FontStrikeout>(*n); + if( eStrikeout != STRIKEOUT_DONTKNOW && + eStrikeout != STRIKEOUT_NONE ) + aItemSet.Put( SvxCrossedOutItem( eStrikeout, RES_CHRATR_CROSSEDOUT ) ); + } + } + + rWrt.OutCSS1_FrameFormatOptions( rFormat, nFrameOpts, &rFormObj, + &aItemSet ); + } + + uno::Reference< form::XFormComponent > xFormComp( xControlModel, uno::UNO_QUERY ); + lcl_html_outEvents( rWrt.Strm(), xFormComp, rWrt.m_bCfgStarBasic ); + + rWrt.Strm().WriteChar( '>' ); + + if( TAG_SELECT == eTag ) + { + aTmp = xPropSet->getPropertyValue( "StringItemList" ); + if( auto aList = o3tl::tryAccess<uno::Sequence<OUString>>(aTmp) ) + { + rWrt.IncIndentLevel(); // the content of Select can be indented + sal_Int32 nCnt = aList->getLength(); + const OUString *pStrings = aList->getConstArray(); + + const OUString *pValues = nullptr; + sal_Int32 nValCnt = 0; + auto aTmp2 = xPropSet->getPropertyValue( "ListSource" ); + uno::Sequence<OUString> aValList; + if( auto s = o3tl::tryAccess<uno::Sequence<OUString>>(aTmp2) ) + { + aValList = *s; + nValCnt = aValList.getLength(); + pValues = aValList.getConstArray(); + } + + uno::Any aSelTmp = xPropSet->getPropertyValue( "DefaultSelection" ); + const sal_Int16 *pSels = nullptr; + sal_Int32 nSel = 0; + sal_Int32 nSelCnt = 0; + uno::Sequence<sal_Int16> aSelList; + if( auto s = o3tl::tryAccess<uno::Sequence<sal_Int16>>(aSelTmp) ) + { + aSelList = *s; + nSelCnt = aSelList.getLength(); + pSels = aSelList.getConstArray(); + } + + for( sal_Int32 i = 0; i < nCnt; i++ ) + { + OUString sVal; + bool bSelected = false, bEmptyVal = false; + if( i < nValCnt ) + { + const OUString& rVal = pValues[i]; + if( rVal == "$$$empty$$$" ) + bEmptyVal = true; + else + sVal = rVal; + } + + bSelected = (nSel < nSelCnt) && pSels[nSel] == i; + if( bSelected ) + nSel++; + + rWrt.OutNewLine(); // every Option gets its own line + sOut = "<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_option; + if( !sVal.isEmpty() || bEmptyVal ) + { + sOut += " " OOO_STRING_SVTOOLS_HTML_O_value "=\""; + rWrt.Strm().WriteOString( sOut ); + HTMLOutFuncs::Out_String( rWrt.Strm(), sVal ); + sOut = "\""_ostr; + } + if( bSelected ) + sOut += " " OOO_STRING_SVTOOLS_HTML_O_selected; + + sOut += ">"; + rWrt.Strm().WriteOString( sOut ); + + HTMLOutFuncs::Out_String( rWrt.Strm(), pStrings[i] ); + } + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_option), false ); + + rWrt.DecIndentLevel(); + rWrt.OutNewLine();// the </SELECT> gets its own line + } + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_select), false ); + } + else if( TAG_TEXTAREA == eTag ) + { + // In TextAreas no additional spaces or LF may be exported! + OUString sVal; + aTmp = xPropSet->getPropertyValue( "DefaultText" ); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !s->isEmpty() ) + { + sVal = *s; + } + } + if( !sVal.isEmpty() ) + { + sVal = convertLineEnd(sVal, LINEEND_LF); + sal_Int32 nPos = 0; + while ( nPos != -1 ) + { + if( nPos ) + rWrt.Strm().WriteOString( SAL_NEWLINE_STRING ); + OUString aLine = sVal.getToken( 0, 0x0A, nPos ); + HTMLOutFuncs::Out_String( rWrt.Strm(), aLine ); + } + } + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_textarea), false ); + } + else if( TYPE_CHECKBOX == eType || TYPE_RADIO == eType ) + { + aTmp = xPropSet->getPropertyValue("Label"); + if( auto s = o3tl::tryAccess<OUString>(aTmp) ) + { + if( !s->isEmpty() ) + { + HTMLOutFuncs::Out_String( rWrt.Strm(), *s ).WriteChar( ' ' ); + } + } + } + + if( !aEndTags.isEmpty() ) + rWrt.Strm().WriteOString( aEndTags ); + + // Controls aren't bound to a paragraph, therefore don't output LF anymore! + rWrt.SetLFPossible(false); + + if( rWrt.mxFormComps.is() ) + rWrt.OutHiddenControls( rWrt.mxFormComps, xPropSet ); + return rWrt; +} + +/** + * Find out if a format belongs to a control and if yes return its form. + */ +static void AddControl( HTMLControls& rControls, + const SdrUnoObj& rFormObj, + SwNodeOffset nNodeIdx ) +{ + const uno::Reference< awt::XControlModel >& xControlModel = + rFormObj.GetUnoControlModel(); + if( !xControlModel.is() ) + return; + + uno::Reference< form::XFormComponent > xFormComp( xControlModel, uno::UNO_QUERY ); + uno::Reference< uno::XInterface > xIfc = xFormComp->getParent(); + uno::Reference< form::XForm > xForm(xIfc, uno::UNO_QUERY); + + OSL_ENSURE( xForm.is(), "Where is the form?" ); + if( xForm.is() ) + { + uno::Reference< container::XIndexContainer > xFormComps( xForm, uno::UNO_QUERY ); + std::unique_ptr<HTMLControl> pHCntrl(new HTMLControl( xFormComps, nNodeIdx )); + auto itPair = rControls.insert( std::move(pHCntrl) ); + if (!itPair.second ) + { + if( (*itPair.first)->xFormComps==xFormComps ) + (*itPair.first)->nCount++; + } + } +} + +void SwHTMLWriter::GetControls() +{ + // Idea: first off collect the paragraph- and character-bound controls. + // In the process for every control the paragraph position and VCForm are + // saved in an array. + // With that array it's possible to find out where form::Forms must be + // opened and closed. + + // collect the paragraph-bound controls + for( size_t i=0; i<m_aHTMLPosFlyFrames.size(); i++ ) + { + const SwHTMLPosFlyFrame* pPosFlyFrame = m_aHTMLPosFlyFrames[ i ].get(); + if( HtmlOut::Control != pPosFlyFrame->GetOutFn() ) + continue; + + const SdrObject *pSdrObj = pPosFlyFrame->GetSdrObject(); + OSL_ENSURE( pSdrObj, "Where is the SdrObject?" ); + if( !pSdrObj ) + continue; + + AddControl( m_aHTMLControls, dynamic_cast<const SdrUnoObj&>(*pSdrObj), + pPosFlyFrame->GetNdIndex().GetIndex() ); + } + + // and now the ones in a character-bound frame + for(sw::SpzFrameFormat* pSpz: *m_pDoc->GetSpzFrameFormats()) + { + if( RES_DRAWFRMFMT != pSpz->Which() ) + continue; + + const SwFormatAnchor& rAnchor = pSpz->GetAnchor(); + const SwNode *pAnchorNode = rAnchor.GetAnchorNode(); + if ((RndStdIds::FLY_AS_CHAR != rAnchor.GetAnchorId()) || !pAnchorNode) + continue; + + const SdrObject *pSdrObj = + SwHTMLWriter::GetHTMLControl(*static_cast<SwDrawFrameFormat*>(pSpz) ); + if( !pSdrObj ) + continue; + + AddControl( m_aHTMLControls, dynamic_cast<const SdrUnoObj&>(*pSdrObj), pAnchorNode->GetIndex() ); + } +} + +HTMLControl::HTMLControl( + uno::Reference< container::XIndexContainer > _xFormComps, + SwNodeOffset nIdx ) : + xFormComps(std::move( _xFormComps )), nNdIdx( nIdx ), nCount( 1 ) +{} + +HTMLControl::~HTMLControl() +{} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |