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 <PageMasterImportContext.hxx>
21 #include <xmloff/xmlimppr.hxx>
22 #include <xmloff/xmlnamespace.hxx>
23 #include <xmloff/xmlprmap.hxx>
24 #include <xmloff/xmltoken.hxx>
25 #include "PageMasterPropHdl.hxx"
26 #include "PagePropertySetContext.hxx"
27 #include "PageHeaderFooterContext.hxx"
28 #include <PageMasterStyleMap.hxx>
29 #include <com/sun/star/frame/XModel.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 #include <osl/diagnose.h>
32
33 //
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/beans/XPropertySetInfo.hpp>
36 #include <com/sun/star/drawing/FillStyle.hpp>
37 #include <com/sun/star/drawing/BitmapMode.hpp>
38 #include <xmloff/xmlerror.hxx>
39 #include <xmloff/XMLTextMasterPageContext.hxx>
40
41 using namespace ::com::sun::star;
42 using namespace ::xmloff::token;
43 using namespace ::com::sun::star::uno;
44 using namespace ::com::sun::star::lang;
45
46 //
47 using namespace ::com::sun::star::beans;
48
SetAttribute(sal_Int32 nElement,const OUString & rValue)49 void PageStyleContext::SetAttribute( sal_Int32 nElement,
50 const OUString& rValue )
51 {
52 if( nElement == XML_ELEMENT(STYLE, XML_PAGE_USAGE) )
53 {
54 sPageUsage = rValue;
55 }
56 else
57 {
58 XMLPropStyleContext::SetAttribute( nElement, rValue );
59 }
60 }
61
62
PageStyleContext(SvXMLImport & rImport,SvXMLStylesContext & rStyles,bool bDefaultStyle)63 PageStyleContext::PageStyleContext( SvXMLImport& rImport,
64 SvXMLStylesContext& rStyles,
65 bool bDefaultStyle) :
66 XMLPropStyleContext( rImport, rStyles, XmlStyleFamily::PAGE_MASTER, bDefaultStyle),
67 sPageUsage(),
68 m_bIsFillStyleAlreadyConverted(false) //
69 {
70 }
71
~PageStyleContext()72 PageStyleContext::~PageStyleContext()
73 {
74 }
75
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)76 css::uno::Reference< css::xml::sax::XFastContextHandler > PageStyleContext::createFastChildContext(
77 sal_Int32 nElement,
78 const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
79 {
80 if( nElement == XML_ELEMENT(STYLE, XML_HEADER_STYLE) ||
81 nElement == XML_ELEMENT(STYLE, XML_FOOTER_STYLE) )
82 {
83 bool bHeader = nElement == XML_ELEMENT(STYLE, XML_HEADER_STYLE);
84 rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap =
85 GetStyles()->GetImportPropertyMapper( GetFamily() );
86 if( xImpPrMap.is() )
87 {
88 const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper();
89 sal_Int32 nFlag;
90 if (bHeader)
91 nFlag = CTF_PM_HEADERFLAG;
92 else
93 nFlag = CTF_PM_FOOTERFLAG;
94 sal_Int32 nStartIndex (-1);
95 sal_Int32 nEndIndex (-1);
96 bool bFirst(false);
97 bool bEnd(false);
98 sal_Int32 nIndex = 0;
99 while ( nIndex < rMapper->GetEntryCount() && !bEnd)
100 {
101 if ((rMapper->GetEntryContextId( nIndex ) & CTF_PM_FLAGMASK) == nFlag)
102 {
103 if (!bFirst)
104 {
105 bFirst = true;
106 nStartIndex = nIndex;
107 }
108 }
109 else if (bFirst)
110 {
111 bEnd = true;
112 nEndIndex = nIndex;
113 }
114 nIndex++;
115 }
116 if (!bEnd)
117 nEndIndex = nIndex;
118 return new PageHeaderFooterContext(GetImport(),
119 GetProperties(), xImpPrMap, nStartIndex, nEndIndex, bHeader);
120 }
121 }
122
123 if( nElement == XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_PROPERTIES) )
124 {
125 rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap =
126 GetStyles()->GetImportPropertyMapper( GetFamily() );
127 if( xImpPrMap.is() )
128 {
129 const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper();
130 sal_Int32 nEndIndex (-1);
131 bool bEnd(false);
132 sal_Int32 nIndex = 0;
133 sal_Int16 nContextID;
134 while ( nIndex < rMapper->GetEntryCount() && !bEnd)
135 {
136 nContextID = rMapper->GetEntryContextId( nIndex );
137 if (nContextID && ((nContextID & CTF_PM_FLAGMASK) != XML_PM_CTF_START))
138 {
139 nEndIndex = nIndex;
140 bEnd = true;
141 }
142 nIndex++;
143 }
144 if (!bEnd)
145 nEndIndex = nIndex;
146 return new PagePropertySetContext( GetImport(), nElement,
147 xAttrList,
148 XML_TYPE_PROP_PAGE_LAYOUT,
149 GetProperties(),
150 xImpPrMap, 0, nEndIndex, Page);
151 }
152 }
153
154 return XMLPropStyleContext::createFastChildContext(nElement, xAttrList);
155 }
156
FillPropertySet(const uno::Reference<beans::XPropertySet> &)157 void PageStyleContext::FillPropertySet(const uno::Reference<beans::XPropertySet > &)
158 {
159 assert(false); // don't call this virtual, call function below
160 }
161
FillPropertySet_PageStyle(const uno::Reference<beans::XPropertySet> & xPropSet,XMLPropStyleContext * const pDrawingPageStyle)162 void PageStyleContext::FillPropertySet_PageStyle(
163 const uno::Reference<beans::XPropertySet> & xPropSet,
164 XMLPropStyleContext *const pDrawingPageStyle)
165 {
166 // need to filter out old fill definitions when the new ones are used. The new
167 // ones are used when a FillStyle is defined
168 if(!m_bIsFillStyleAlreadyConverted && !GetProperties().empty())
169 {
170 static OUString s_FillStyle("FillStyle");
171 static OUString s_HeaderFillStyle("HeaderFillStyle");
172 static OUString s_FooterFillStyle("FooterFillStyle");
173
174 // note: the function must only check by property name, not any id/flag!
175 if (doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle)
176 || (pDrawingPageStyle && pDrawingPageStyle->doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle)))
177 {
178 deactivateOldFillStyleDefinitions(getStandardSet());
179 }
180
181 if(doNewDrawingLayerFillStyleDefinitionsExist(s_HeaderFillStyle))
182 {
183 deactivateOldFillStyleDefinitions(getHeaderSet());
184 }
185
186 if(doNewDrawingLayerFillStyleDefinitionsExist(s_FooterFillStyle))
187 {
188 deactivateOldFillStyleDefinitions(getFooterSet());
189 }
190
191 m_bIsFillStyleAlreadyConverted = true;
192 }
193
194 // do not use XMLPropStyleContext::FillPropertySet, we need to handle this ourselves since
195 // we have properties which use the MID_FLAG_NO_PROPERTY_IMPORT flag since they need some special
196 // handling
197 rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = GetStyles()->GetImportPropertyMapper(GetFamily());
198
199 if(xImpPrMap.is())
200 {
201 // properties that need special handling because they need the used name to be translated first
202 struct ContextID_Index_Pair aContextIDs[] =
203 {
204 { CTF_PM_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT },
205 { CTF_PM_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
206 { CTF_PM_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH },
207 { CTF_PM_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP },
208
209 // also need to special handling for header entries
210 { CTF_PM_HEADERFILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT },
211 { CTF_PM_HEADERFILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
212 { CTF_PM_HEADERFILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH },
213 { CTF_PM_HEADERFILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP },
214
215 // also need to special handling for footer entries
216 { CTF_PM_FOOTERFILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT },
217 { CTF_PM_FOOTERFILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
218 { CTF_PM_FOOTERFILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH },
219 { CTF_PM_FOOTERFILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP },
220
221 {-1, -1, drawing::FillStyle::FillStyle_GRADIENT}
222 };
223
224 // the style families associated with the same index modulo 4
225 static const XmlStyleFamily aFamilies[] =
226 {
227 XmlStyleFamily::SD_GRADIENT_ID,
228 XmlStyleFamily::SD_GRADIENT_ID,
229 XmlStyleFamily::SD_HATCH_ID,
230 XmlStyleFamily::SD_FILL_IMAGE_ID
231 };
232
233 // Fill PropertySet, but let it handle special properties not itself
234 xImpPrMap->FillPropertySet(GetProperties(), xPropSet, aContextIDs);
235
236 // get property set mapper
237 const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper();
238 Reference<XPropertySetInfo> const xInfo(xPropSet->getPropertySetInfo());
239
240 // don't look at the attributes, look at the property, could
241 // theoretically be inherited and we don't want to delete erroneously
242 drawing::FillStyle fillStyle{drawing::FillStyle_NONE};
243 drawing::FillStyle fillStyleHeader{drawing::FillStyle_NONE};
244 drawing::FillStyle fillStyleFooter{drawing::FillStyle_NONE};
245 if (xInfo->hasPropertyByName("FillStyle")) // SwXTextDefaults lacks it?
246 {
247 xPropSet->getPropertyValue("FillStyle") >>= fillStyle;
248 xPropSet->getPropertyValue("HeaderFillStyle") >>= fillStyleHeader;
249 xPropSet->getPropertyValue("FooterFillStyle") >>= fillStyleFooter;
250 }
251
252 // handle special attributes which have MID_FLAG_NO_PROPERTY_IMPORT set
253 for(sal_uInt16 i = 0; aContextIDs[i].nContextID != -1; i++)
254 {
255 sal_Int32 nIndex = aContextIDs[i].nIndex;
256
257 if(nIndex != -1)
258 {
259 drawing::FillStyle const* pFillStyle(nullptr);
260 switch(aContextIDs[i].nContextID)
261 {
262 case CTF_PM_FILLGRADIENTNAME:
263 case CTF_PM_FILLTRANSNAME:
264 case CTF_PM_FILLHATCHNAME:
265 case CTF_PM_FILLBITMAPNAME:
266 pFillStyle = &fillStyle;
267 [[fallthrough]];
268 case CTF_PM_HEADERFILLGRADIENTNAME:
269 case CTF_PM_HEADERFILLTRANSNAME:
270 case CTF_PM_HEADERFILLHATCHNAME:
271 case CTF_PM_HEADERFILLBITMAPNAME:
272 if (!pFillStyle) { pFillStyle = &fillStyleHeader; }
273 [[fallthrough]];
274 case CTF_PM_FOOTERFILLGRADIENTNAME:
275 case CTF_PM_FOOTERFILLTRANSNAME:
276 case CTF_PM_FOOTERFILLHATCHNAME:
277 case CTF_PM_FOOTERFILLBITMAPNAME:
278 {
279 if (!pFillStyle) { pFillStyle = &fillStyleFooter; }
280 struct XMLPropertyState& rState = GetProperties()[nIndex];
281 OUString sStyleName;
282 rState.maValue >>= sStyleName;
283
284 if (aContextIDs[i].nExpectedFillStyle != drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE
285 && aContextIDs[i].nExpectedFillStyle != *pFillStyle)
286 {
287 SAL_INFO("xmloff.style", "PageStyleContext: dropping fill named item: " << sStyleName);
288 break; // ignore it, it's not used
289 }
290 // translate the used name from ODF intern to the name used in the Model
291 sStyleName = GetImport().GetStyleDisplayName(aFamilies[i%4], sStyleName);
292
293 try
294 {
295 // set property
296 const OUString& rPropertyName = rMapper->GetEntryAPIName(rState.mnIndex);
297
298 if(xInfo->hasPropertyByName(rPropertyName))
299 {
300 xPropSet->setPropertyValue(rPropertyName,Any(sStyleName));
301 }
302 }
303 catch(css::lang::IllegalArgumentException& e)
304 {
305 Sequence<OUString> aSeq { sStyleName };
306 GetImport().SetError(
307 XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING,
308 aSeq,e.Message,nullptr);
309 }
310 break;
311 }
312 }
313 }
314 }
315 }
316 else
317 {
318 OSL_ENSURE(xImpPrMap.is(), "Got no SvXMLImportPropertyMapper (!)");
319 }
320
321 // pDrawingPageStyle overrides this
322 if (pDrawingPageStyle)
323 {
324 pDrawingPageStyle->FillPropertySet(xPropSet);
325 }
326 // horrible heuristic to guess BackgroundFullSize for Writer < 7.0
327 else if (!IsDefaultStyle() // ignore pool default, only fix existing styles
328 && (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x)
329 // also for AOO 4.x, assume there won't ever be a 4.2
330 || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x))
331 {
332 bool isFullSize(true); // default is current LO default
333 drawing::FillStyle fillStyle{drawing::FillStyle_NONE};
334 xPropSet->getPropertyValue("FillStyle") >>= fillStyle;
335 if (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_63x)
336 // also for AOO 4.x, assume there won't ever be a 4.2
337 || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x)
338 {
339 // before LO 6.3, always inside the margins (but ignore it if NONE)
340 if (fillStyle != drawing::FillStyle_NONE)
341 {
342 isFullSize = false;
343 }
344 }
345 else
346 {
347 // LO 6.3/6.4: guess depending on fill style/bitmap mode
348 // this should work even if the document doesn't contain fill style
349 // but only old background attributes
350 // (can't use the aContextIDs stuff above because that requires
351 // re-routing through handleSpecialItem())
352 switch (fillStyle)
353 {
354 case drawing::FillStyle_NONE:
355 break;
356 case drawing::FillStyle_SOLID:
357 case drawing::FillStyle_GRADIENT:
358 case drawing::FillStyle_HATCH:
359 isFullSize = true;
360 break;
361 case drawing::FillStyle_BITMAP:
362 {
363 drawing::BitmapMode bitmapMode{};
364 xPropSet->getPropertyValue("FillBitmapMode") >>= bitmapMode;
365 switch (bitmapMode)
366 {
367 case drawing::BitmapMode_REPEAT:
368 isFullSize = true;
369 break;
370 case drawing::BitmapMode_STRETCH:
371 case drawing::BitmapMode_NO_REPEAT:
372 isFullSize = false;
373 break;
374 default:
375 assert(false);
376 }
377 }
378 break;
379 default:
380 assert(false);
381 }
382 }
383 // set it explicitly if it's not the default
384 if (!isFullSize)
385 {
386 SAL_INFO("xmloff.style", "FillPropertySet_PageStyle: Heuristically resetting BackgroundFullSize");
387 xPropSet->setPropertyValue("BackgroundFullSize", uno::makeAny(isFullSize));
388 }
389 }
390
391 // old code, replaced by above stuff
392 // XMLPropStyleContext::FillPropertySet(rPropSet);
393
394 if (!sPageUsage.isEmpty())
395 {
396 uno::Any aPageUsage;
397 XMLPMPropHdl_PageStyleLayout aPageUsageHdl;
398 if (aPageUsageHdl.importXML(sPageUsage, aPageUsage, GetImport().GetMM100UnitConverter()))
399 xPropSet->setPropertyValue("PageStyleLayout", aPageUsage);
400 }
401 }
402
403 extern ContextID_Index_Pair const g_MasterPageContextIDs[] =
404 {
405 { CTF_PM_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT },
406 { CTF_PM_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE },
407 { CTF_PM_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH },
408 { CTF_PM_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP },
409
410 {-1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE}
411 };
412
413 extern XmlStyleFamily const g_MasterPageFamilies[] =
414 {
415 XmlStyleFamily::SD_GRADIENT_ID,
416 XmlStyleFamily::SD_GRADIENT_ID,
417 XmlStyleFamily::SD_HATCH_ID,
418 XmlStyleFamily::SD_FILL_IMAGE_ID
419 };
420
421 // text grid enhancement for better CJK support
422 //set default page layout style
SetDefaults()423 void PageStyleContext::SetDefaults( )
424 {
425 Reference < XMultiServiceFactory > xFactory ( GetImport().GetModel(), UNO_QUERY);
426 if (xFactory.is())
427 {
428 Reference < XInterface > xInt = xFactory->createInstance( "com.sun.star.text.Defaults" );
429 Reference < beans::XPropertySet > xProperties ( xInt, UNO_QUERY );
430 if ( xProperties.is() )
431 FillPropertySet_PageStyle(xProperties, nullptr);
432 }
433 }
434
435 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
436