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/.
10 #include "SdtHelper.hxx"
11 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
12 #include <com/sun/star/drawing/XControlShape.hpp>
13 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
14 #include <com/sun/star/text/VertOrientation.hpp>
15 #include <com/sun/star/util/DateTime.hpp>
16 #include <com/sun/star/util/Date.hpp>
17 #include <sal/log.hxx>
18 #include <cppuhelper/exc_hlp.hxx>
19 #include <editeng/unoprnms.hxx>
20 #include <vcl/svapp.hxx>
21 #include <unotools/datetime.hxx>
22 #include <comphelper/sequence.hxx>
23 #include <xmloff/odffields.hxx>
25 #include "DomainMapper_Impl.hxx"
26 #include "StyleSheetTable.hxx"
28 namespace writerfilter
33 using namespace ::com::sun::star
;
35 /// w:sdt's w:dropDownList doesn't have width, so guess the size based on the longest string.
36 static awt::Size
lcl_getOptimalWidth(const StyleSheetTablePtr
& pStyleSheet
, OUString
const& rDefault
, std::vector
<OUString
>& rItems
)
38 OUString aLongest
= rDefault
;
39 sal_Int32 nHeight
= 0;
40 for (const OUString
& rItem
: rItems
)
41 if (rItem
.getLength() > aLongest
.getLength())
44 MapMode
aMap(MapUnit::Map100thMM
);
45 OutputDevice
* pOut
= Application::GetDefaultDevice();
46 pOut
->Push(PushFlags::FONT
| PushFlags::MAPMODE
);
48 PropertyMapPtr pDefaultCharProps
= pStyleSheet
->GetDefaultCharProps();
49 vcl::Font
aFont(pOut
->GetFont());
50 boost::optional
<PropertyMap::Property
> aFontName
= pDefaultCharProps
->getProperty(PROP_CHAR_FONT_NAME
);
52 aFont
.SetFamilyName(aFontName
->second
.get
<OUString
>());
53 boost::optional
<PropertyMap::Property
> aHeight
= pDefaultCharProps
->getProperty(PROP_CHAR_HEIGHT
);
56 nHeight
= aHeight
->second
.get
<double>() * 35; // points -> mm100
57 aFont
.SetFontSize(Size(0, nHeight
));
60 pOut
->SetMapMode(aMap
);
61 sal_Int32 nWidth
= pOut
->GetTextWidth(aLongest
);
65 // Border: see PDFWriterImpl::drawFieldBorder(), border size is font height / 4,
66 // so additional width / height needed is height / 2.
67 sal_Int32 nBorder
= nHeight
/ 2;
69 // Width: space for the text + the square having the dropdown arrow.
70 return {nWidth
+ nBorder
+ nHeight
, nHeight
+ nBorder
};
73 SdtHelper::SdtHelper(DomainMapper_Impl
& rDM_Impl
)
74 : m_rDM_Impl(rDM_Impl
)
75 , m_bInsideDropDownControl(false)
76 , m_bHasElements(false)
77 , m_bOutsideAParagraph(false)
81 SdtHelper::~SdtHelper() = default;
83 void SdtHelper::createDropDownControl()
85 assert(m_bInsideDropDownControl
);
86 OUString aDefaultText
= m_aSdtTexts
.makeStringAndClear();
87 uno::Reference
<awt::XControlModel
> xControlModel(m_rDM_Impl
.GetTextFactory()->createInstance("com.sun.star.form.component.ComboBox"), uno::UNO_QUERY
);
88 uno::Reference
<beans::XPropertySet
> xPropertySet(xControlModel
, uno::UNO_QUERY
);
89 xPropertySet
->setPropertyValue("DefaultText", uno::makeAny(aDefaultText
));
90 xPropertySet
->setPropertyValue("Dropdown", uno::makeAny(true));
91 xPropertySet
->setPropertyValue("StringItemList", uno::makeAny(comphelper::containerToSequence(m_aDropDownItems
)));
93 createControlShape(lcl_getOptimalWidth(m_rDM_Impl
.GetStyleSheetTable(), aDefaultText
, m_aDropDownItems
),
94 xControlModel
, uno::Sequence
<beans::PropertyValue
>());
95 m_aDropDownItems
.clear();
96 m_bInsideDropDownControl
= false;
99 bool SdtHelper::validateDateFormat()
101 return !m_sDateFormat
.toString().isEmpty() && !m_sLocale
.toString().isEmpty();
104 void SdtHelper::createDateContentControl()
106 if(!m_xDateFieldStartRange
.is())
109 uno::Reference
<text::XTextCursor
> xCrsr
;
110 if(m_rDM_Impl
.HasTopText())
112 uno::Reference
<text::XTextAppend
> xTextAppend
= m_rDM_Impl
.GetTopTextAppend();
113 if (xTextAppend
.is())
115 xCrsr
= xTextAppend
->createTextCursorByRange(xTextAppend
);
122 xCrsr
->gotoRange(m_xDateFieldStartRange
, false);
124 = (m_rDM_Impl
.hasTableManager() && m_rDM_Impl
.getTableManager().isInTable())
125 || (m_rDM_Impl
.m_nTableDepth
> 0);
127 xCrsr
->goRight(1, false);
128 xCrsr
->gotoEnd(true);
130 catch (uno::Exception
&) {
131 OSL_ENSURE(false, "Cannot get the right text range for date field");
135 uno::Reference
< uno::XInterface
> xFieldInterface
;
136 xFieldInterface
= m_rDM_Impl
.GetTextFactory()->createInstance("com.sun.star.text.Fieldmark");
137 uno::Reference
< text::XFormField
> xFormField( xFieldInterface
, uno::UNO_QUERY
);
138 uno::Reference
< text::XTextContent
> xToInsert(xFormField
, uno::UNO_QUERY
);
139 if ( xFormField
.is() && xToInsert
.is() )
141 xToInsert
->attach( uno::Reference
< text::XTextRange
>( xCrsr
, uno::UNO_QUERY_THROW
));
142 xFormField
->setFieldType(ODF_FORMDATE
);
143 uno::Reference
<container::XNameContainer
> xNameCont
= xFormField
->getParameters();
146 OUString sDateFormat
= m_sDateFormat
.makeStringAndClear();
147 // Replace quotation mark used for marking static strings in date format
148 sDateFormat
= sDateFormat
.replaceAll("'", "\"");
149 xNameCont
->insertByName(ODF_FORMDATE_DATEFORMAT
, uno::makeAny(sDateFormat
));
150 xNameCont
->insertByName(ODF_FORMDATE_DATEFORMAT_LANGUAGE
, uno::makeAny(m_sLocale
.makeStringAndClear()));
152 OUString sFullDate
= m_sDate
.makeStringAndClear();
153 if(!sFullDate
.isEmpty())
155 sal_Int32 nTimeSep
= sFullDate
.indexOf("T");
157 sFullDate
= sFullDate
.copy(0, nTimeSep
);
158 xNameCont
->insertByName(ODF_FORMDATE_CURRENTDATE
, uno::makeAny(sFullDate
));
164 void SdtHelper::createControlShape(awt::Size aSize
, uno::Reference
<awt::XControlModel
> const& xControlModel
, const uno::Sequence
<beans::PropertyValue
>& rGrabBag
)
166 uno::Reference
<drawing::XControlShape
> xControlShape(m_rDM_Impl
.GetTextFactory()->createInstance("com.sun.star.drawing.ControlShape"), uno::UNO_QUERY
);
167 xControlShape
->setSize(aSize
);
168 xControlShape
->setControl(xControlModel
);
170 uno::Reference
<beans::XPropertySet
> xPropertySet(xControlShape
, uno::UNO_QUERY
);
171 xPropertySet
->setPropertyValue("VertOrient", uno::makeAny(text::VertOrientation::CENTER
));
173 if (rGrabBag
.hasElements())
174 xPropertySet
->setPropertyValue(UNO_NAME_MISC_OBJ_INTEROPGRABBAG
, uno::makeAny(rGrabBag
));
176 uno::Reference
<text::XTextContent
> xTextContent(xControlShape
, uno::UNO_QUERY
);
177 m_rDM_Impl
.appendTextContent(xTextContent
, uno::Sequence
< beans::PropertyValue
>());
178 m_bHasElements
= true;
181 void SdtHelper::appendToInteropGrabBag(const beans::PropertyValue
& rValue
)
183 m_aGrabBag
.push_back(rValue
);
186 uno::Sequence
<beans::PropertyValue
> SdtHelper::getInteropGrabBagAndClear()
188 uno::Sequence
<beans::PropertyValue
> aRet
= comphelper::containerToSequence(m_aGrabBag
);
193 bool SdtHelper::isInteropGrabBagEmpty()
195 return m_aGrabBag
.empty();
198 sal_Int32
SdtHelper::getInteropGrabBagSize()
200 return m_aGrabBag
.size();
203 bool SdtHelper::containedInInteropGrabBag(const OUString
& rValueName
)
205 for (beans::PropertyValue
& i
: m_aGrabBag
)
206 if (i
.Name
== rValueName
)
212 } // namespace dmapper
213 } // namespace writerfilter
215 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */