1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <com/sun/star/awt/XControlModel.hpp>
23 #include <com/sun/star/beans/XPropertySet.hpp>
24 #include <com/sun/star/container/XIndexContainer.hpp>
25 #include <com/sun/star/container/XNamed.hpp>
26 #include <com/sun/star/drawing/XControlShape.hpp>
27 #include <com/sun/star/drawing/XDrawPage.hpp>
28 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
29 #include <com/sun/star/form/XForm.hpp>
30 #include <com/sun/star/form/XFormComponent.hpp>
31 #include <com/sun/star/form/XFormsSupplier.hpp>
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/text/TextContentAnchorType.hpp>
34 #include <com/sun/star/text/VertOrientation.hpp>
35 #include <com/sun/star/uno/Any.hxx>
37 #include <o3tl/safeint.hxx>
39 #include "FormControlHelper.hxx"
41 #include <xmloff/odffields.hxx>
42 #include <comphelper/sequence.hxx>
43 #include <comphelper/diagnose_ex.hxx>
45 namespace writerfilter::dmapper
{
47 using namespace ::com::sun::star
;
49 struct FormControlHelper::FormControlHelper_Impl
: public virtual SvRefBase
53 uno::Reference
<drawing::XDrawPage
> rDrawPage
;
54 uno::Reference
<form::XForm
> rForm
;
55 uno::Reference
<form::XFormComponent
> rFormComponent
;
56 uno::Reference
<lang::XMultiServiceFactory
> rServiceFactory
;
57 uno::Reference
<text::XTextDocument
> rTextDocument
;
59 uno::Reference
<drawing::XDrawPage
> const & getDrawPage();
60 uno::Reference
<lang::XMultiServiceFactory
> const & getServiceFactory();
61 uno::Reference
<form::XForm
> const & getForm();
62 uno::Reference
<container::XIndexContainer
> getFormComps();
65 uno::Reference
<drawing::XDrawPage
> const & FormControlHelper::FormControlHelper_Impl::getDrawPage()
69 uno::Reference
<drawing::XDrawPageSupplier
>
70 xDrawPageSupplier(rTextDocument
, uno::UNO_QUERY
);
71 if (xDrawPageSupplier
.is())
72 rDrawPage
= xDrawPageSupplier
->getDrawPage();
78 uno::Reference
<lang::XMultiServiceFactory
> const & FormControlHelper::FormControlHelper_Impl::getServiceFactory()
80 if (! rServiceFactory
.is())
81 rServiceFactory
.set(rTextDocument
, uno::UNO_QUERY
);
83 return rServiceFactory
;
86 uno::Reference
<form::XForm
> const & FormControlHelper::FormControlHelper_Impl::getForm()
90 uno::Reference
<form::XFormsSupplier
> xFormsSupplier(getDrawPage(), uno::UNO_QUERY
);
92 if (xFormsSupplier
.is())
94 uno::Reference
<container::XNameContainer
> xFormsNamedContainer(xFormsSupplier
->getForms());
95 static constexpr OUStringLiteral sDOCXForm
= u
"DOCX-Standard";
97 OUString
sFormName(sDOCXForm
);
98 sal_uInt16 nUnique
= 0;
100 while (xFormsNamedContainer
->hasByName(sFormName
))
103 sFormName
= sDOCXForm
+ OUString::number(nUnique
);
106 uno::Reference
<uno::XInterface
> xForm(getServiceFactory()->createInstance("com.sun.star.form.component.Form"));
109 uno::Reference
<beans::XPropertySet
>
110 xFormProperties(xForm
, uno::UNO_QUERY
);
111 uno::Any
aAny(sFormName
);
112 xFormProperties
->setPropertyValue("Name", aAny
);
115 rForm
.set(xForm
, uno::UNO_QUERY
);
117 uno::Reference
<container::XIndexContainer
> xForms(xFormsNamedContainer
, uno::UNO_QUERY
);
118 uno::Any
aAny(xForm
);
119 xForms
->insertByIndex(xForms
->getCount(), aAny
);
126 uno::Reference
<container::XIndexContainer
> FormControlHelper::FormControlHelper_Impl::getFormComps()
128 uno::Reference
<container::XIndexContainer
> xIndexContainer(getForm(), uno::UNO_QUERY
);
130 return xIndexContainer
;
133 FormControlHelper::FormControlHelper(FieldId eFieldId
,
134 uno::Reference
<text::XTextDocument
> const& xTextDocument
,
135 FFDataHandler::Pointer_t pFFData
)
136 : m_pFFData(std::move(pFFData
)), m_pImpl(new FormControlHelper_Impl
)
138 m_pImpl
->m_eFieldId
= eFieldId
;
139 m_pImpl
->rTextDocument
= xTextDocument
;
142 FormControlHelper::~FormControlHelper()
146 bool FormControlHelper::createCheckbox(uno::Reference
<text::XTextRange
> const& xTextRange
,
147 const OUString
& rControlName
)
151 uno::Reference
<lang::XMultiServiceFactory
>
152 xServiceFactory(m_pImpl
->getServiceFactory());
154 if (! xServiceFactory
.is())
157 uno::Reference
<uno::XInterface
> xInterface
= xServiceFactory
->createInstance("com.sun.star.form.component.CheckBox");
159 if (!xInterface
.is())
162 m_pImpl
->rFormComponent
.set(xInterface
, uno::UNO_QUERY
);
163 if (!m_pImpl
->rFormComponent
.is())
166 uno::Reference
<beans::XPropertySet
> xPropSet(xInterface
, uno::UNO_QUERY
);
168 sal_uInt32 nCheckBoxHeight
= 16 * m_pFFData
->getCheckboxHeight();
170 if (m_pFFData
->getCheckboxAutoHeight())
172 uno::Reference
<beans::XPropertySet
> xTextRangeProps(xTextRange
, uno::UNO_QUERY
);
176 float fCheckBoxHeight
= 0.0;
177 xTextRangeProps
->getPropertyValue("CharHeight") >>= fCheckBoxHeight
;
178 nCheckBoxHeight
= static_cast<sal_uInt32
>(floor(fCheckBoxHeight
* 35.3));
180 catch (beans::UnknownPropertyException
&)
185 m_pImpl
->aSize
.Width
= nCheckBoxHeight
;
186 m_pImpl
->aSize
.Height
= m_pImpl
->aSize
.Width
;
188 if (!m_pFFData
->getStatusText().isEmpty())
190 xPropSet
->setPropertyValue("HelpText", uno::Any(m_pFFData
->getStatusText()));
193 xPropSet
->setPropertyValue("DefaultState", uno::Any(m_pFFData
->getCheckboxChecked()));
195 if (!m_pFFData
->getHelpText().isEmpty())
197 xPropSet
->setPropertyValue("HelpF1Text", uno::Any(m_pFFData
->getHelpText()));
200 xPropSet
->setPropertyValue("Name", uno::Any(rControlName
));
205 void FormControlHelper::processField(uno::Reference
<text::XFormField
> const& xFormField
)
207 // Set field type first before adding parameters.
208 if (m_pImpl
->m_eFieldId
== FIELD_FORMTEXT
)
210 xFormField
->setFieldType(ODF_FORMTEXT
);
212 else if (m_pImpl
->m_eFieldId
== FIELD_FORMCHECKBOX
)
214 xFormField
->setFieldType(ODF_FORMCHECKBOX
);
216 else if (m_pImpl
->m_eFieldId
== FIELD_FORMDROPDOWN
)
218 xFormField
->setFieldType(ODF_FORMDROPDOWN
);
221 uno::Reference
<container::XNameContainer
> xNameCont
= xFormField
->getParameters();
222 uno::Reference
<container::XNamed
> xNamed( xFormField
, uno::UNO_QUERY
);
223 if ( !(m_pFFData
&& xNamed
.is() && xNameCont
.is()) )
226 OUString sTmp
= m_pFFData
->getEntryMacro();
227 if ( !sTmp
.isEmpty() )
228 xNameCont
->insertByName( "EntryMacro", uno::Any(sTmp
) );
229 sTmp
= m_pFFData
->getExitMacro();
230 if ( !sTmp
.isEmpty() )
231 xNameCont
->insertByName( "ExitMacro", uno::Any(sTmp
) );
233 sTmp
= m_pFFData
->getHelpText();
234 if ( !sTmp
.isEmpty() )
235 xNameCont
->insertByName( "Help", uno::Any(sTmp
) );
237 sTmp
= m_pFFData
->getStatusText();
238 if ( !sTmp
.isEmpty() )
239 xNameCont
->insertByName( "Hint", uno::Any(sTmp
) );
241 if (m_pImpl
->m_eFieldId
== FIELD_FORMTEXT
)
243 sTmp
= m_pFFData
->getName();
246 if ( !sTmp
.isEmpty() )
247 xNamed
->setName( sTmp
);
249 catch ( uno::Exception
& )
251 TOOLS_INFO_EXCEPTION("writerfilter", "Set Formfield name failed");
254 sTmp
= m_pFFData
->getTextType();
255 if ( !sTmp
.isEmpty() )
256 xNameCont
->insertByName( "Type", uno::Any(sTmp
) );
258 const sal_uInt16 nMaxLength
= m_pFFData
->getTextMaxLength();
261 xNameCont
->insertByName( "MaxLength", uno::Any(nMaxLength
) );
264 sTmp
= m_pFFData
->getTextDefault();
265 if ( !sTmp
.isEmpty() )
266 xNameCont
->insertByName( "Content", uno::Any(sTmp
) );
268 sTmp
= m_pFFData
->getTextFormat();
269 if ( !sTmp
.isEmpty() )
270 xNameCont
->insertByName( "Format", uno::Any(sTmp
) );
272 else if (m_pImpl
->m_eFieldId
== FIELD_FORMCHECKBOX
)
274 uno::Reference
<beans::XPropertySet
> xPropSet(xFormField
, uno::UNO_QUERY
);
276 aAny
<<= m_pFFData
->getCheckboxChecked();
278 xPropSet
->setPropertyValue("Checked", aAny
);
280 else if (m_pImpl
->m_eFieldId
== FIELD_FORMDROPDOWN
)
282 const FFDataHandler::DropDownEntries_t
& rEntries
= m_pFFData
->getDropDownEntries();
283 if (!rEntries
.empty())
285 if ( xNameCont
->hasByName(ODF_FORMDROPDOWN_LISTENTRY
) )
286 xNameCont
->replaceByName(ODF_FORMDROPDOWN_LISTENTRY
, uno::Any(comphelper::containerToSequence(rEntries
)));
288 xNameCont
->insertByName(ODF_FORMDROPDOWN_LISTENTRY
, uno::Any(comphelper::containerToSequence(rEntries
)));
290 sal_Int32 nResult
= m_pFFData
->getDropDownResult().toInt32();
291 // 0 is valid, but also how toInt32 reports parse error, but it's a sensible default...
292 if (0 <= nResult
&& o3tl::make_unsigned(nResult
) < rEntries
.size())
294 if ( xNameCont
->hasByName(ODF_FORMDROPDOWN_RESULT
) )
295 xNameCont
->replaceByName(ODF_FORMDROPDOWN_RESULT
, uno::Any( nResult
) );
297 xNameCont
->insertByName(ODF_FORMDROPDOWN_RESULT
, uno::Any( nResult
) );
303 void FormControlHelper::insertControl(uno::Reference
<text::XTextRange
> const& xTextRange
)
305 bool bCreated
= false;
308 uno::Reference
<container::XNameContainer
> xFormCompsByName(m_pImpl
->getForm(), uno::UNO_QUERY
);
309 uno::Reference
<container::XIndexContainer
> xFormComps(m_pImpl
->getFormComps());
310 if (! xFormComps
.is())
313 sal_Int32 nControl
= 0;
315 OUString sControlName
;
319 OUString sTmp
= "Control" + OUString::number(nControl
);
322 if (! xFormCompsByName
->hasByName(sTmp
))
330 switch (m_pImpl
->m_eFieldId
)
332 case FIELD_FORMCHECKBOX
:
333 bCreated
= createCheckbox(xTextRange
, sControlName
);
342 uno::Any
aAny(m_pImpl
->rFormComponent
);
343 xFormComps
->insertByIndex(xFormComps
->getCount(), aAny
);
345 if (! m_pImpl
->getServiceFactory().is())
348 uno::Reference
<uno::XInterface
> xInterface
= m_pImpl
->getServiceFactory()->createInstance("com.sun.star.drawing.ControlShape");
350 if (! xInterface
.is())
353 uno::Reference
<drawing::XShape
> xShape(xInterface
, uno::UNO_QUERY
);
358 xShape
->setSize(m_pImpl
->aSize
);
360 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
362 sal_uInt16 nTmp
= sal_uInt16(text::TextContentAnchorType_AS_CHARACTER
);
363 xShapeProps
->setPropertyValue("AnchorType", uno::Any(sal_uInt16(nTmp
)));
365 nTmp
= text::VertOrientation::CENTER
;
366 xShapeProps
->setPropertyValue("VertOrient", uno::Any(sal_uInt16(nTmp
)));
368 xShapeProps
->setPropertyValue("TextRange", uno::Any(xTextRange
));
370 uno::Reference
<drawing::XControlShape
> xControlShape(xShape
, uno::UNO_QUERY
);
371 uno::Reference
<awt::XControlModel
> xControlModel(m_pImpl
->rFormComponent
, uno::UNO_QUERY
);
372 xControlShape
->setControl(xControlModel
);
374 m_pImpl
->getDrawPage()->add(xShape
);
379 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */