lok: vcl: fix multiple floatwin removal case more robustly.
[LibreOffice.git] / writerfilter / source / dmapper / SdtHelper.cxx
bloba2f9c813137594fa6ccd363fc3ad71537b6cf746
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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
30 namespace dmapper
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())
42 aLongest = rItem;
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);
51 if (aFontName)
52 aFont.SetFamilyName(aFontName->second.get<OUString>());
53 boost::optional<PropertyMap::Property> aHeight = pDefaultCharProps->getProperty(PROP_CHAR_HEIGHT);
54 if (aHeight)
56 nHeight = aHeight->second.get<double>() * 35; // points -> mm100
57 aFont.SetFontSize(Size(0, nHeight));
59 pOut->SetFont(aFont);
60 pOut->SetMapMode(aMap);
61 sal_Int32 nWidth = pOut->GetTextWidth(aLongest);
63 pOut->Pop();
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())
107 return;
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);
118 if (xCrsr.is())
122 xCrsr->gotoRange(m_xDateFieldStartRange, false);
123 bool bIsInTable
124 = (m_rDM_Impl.hasTableManager() && m_rDM_Impl.getTableManager().isInTable())
125 || (m_rDM_Impl.m_nTableDepth > 0);
126 if (bIsInTable)
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");
132 return;
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();
144 if(xNameCont.is())
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");
156 if(nTimeSep != -1)
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);
189 m_aGrabBag.clear();
190 return aRet;
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)
207 return true;
209 return false;
212 } // namespace dmapper
213 } // namespace writerfilter
215 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */