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 #include "PropertyMap.hxx"
20 #include <ooxml/resourceids.hxx>
21 #include "DomainMapper_Impl.hxx"
22 #include "ConversionHelper.hxx"
23 #include <editeng/boxitem.hxx>
24 #include <i18nutil/paper.hxx>
25 #include <osl/diagnose.h>
26 #include <rtl/ustring.hxx>
27 #include <sal/log.hxx>
28 #include <com/sun/star/beans/PropertyAttribute.hpp>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/beans/XMultiPropertySet.hpp>
31 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/table/BorderLine2.hpp>
34 #include <com/sun/star/container/XEnumeration.hpp>
35 #include <com/sun/star/container/XEnumerationAccess.hpp>
36 #include <com/sun/star/container/XNameContainer.hpp>
37 #include <com/sun/star/style/BreakType.hpp>
38 #include <com/sun/star/style/PageStyleLayout.hpp>
39 #include <com/sun/star/style/XStyle.hpp>
40 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
41 #include <com/sun/star/table/ShadowFormat.hpp>
42 #include <com/sun/star/text/RelOrientation.hpp>
43 #include <com/sun/star/text/HoriOrientation.hpp>
44 #include <com/sun/star/text/HorizontalAdjust.hpp>
45 #include <com/sun/star/text/SizeType.hpp>
46 #include <com/sun/star/text/VertOrientation.hpp>
47 #include <com/sun/star/text/WritingMode.hpp>
48 #include <com/sun/star/text/WritingMode2.hpp>
49 #include <com/sun/star/text/XTextColumns.hpp>
50 #include <com/sun/star/text/XText.hpp>
51 #include <com/sun/star/text/TextGridMode.hpp>
52 #include <com/sun/star/text/XTextCopy.hpp>
53 #include <com/sun/star/style/VerticalAlignment.hpp>
54 #include <comphelper/sequence.hxx>
55 #include <comphelper/propertyvalue.hxx>
56 #include <tools/diagnose_ex.h>
57 #include "PropertyMapHelper.hxx"
58 #include <o3tl/sorted_vector.hxx>
59
60 using namespace com::sun::star;
61
62 namespace writerfilter {
63 namespace dmapper {
64
GetPropertyValues(bool bCharGrabBag)65 uno::Sequence< beans::PropertyValue > PropertyMap::GetPropertyValues( bool bCharGrabBag )
66 {
67 using comphelper::makePropertyValue;
68
69 if ( m_aValues.empty() && !m_vMap.empty() )
70 {
71 size_t nCharGrabBag = 0;
72 size_t nParaGrabBag = 0;
73 size_t nCellGrabBag = 0;
74 size_t nRowGrabBag = 0;
75
76 const PropValue* pParaStyleProp = nullptr;
77 const PropValue* pCharStyleProp = nullptr;
78 const PropValue* pNumRuleProp = nullptr;
79
80 for ( const auto& rPropPair : m_vMap )
81 {
82 if ( rPropPair.second.getGrabBagType() == CHAR_GRAB_BAG )
83 nCharGrabBag++;
84 else if ( rPropPair.second.getGrabBagType() == PARA_GRAB_BAG )
85 nParaGrabBag++;
86 else if ( rPropPair.second.getGrabBagType() == CELL_GRAB_BAG )
87 nCellGrabBag++;
88 else if ( rPropPair.first == PROP_CELL_INTEROP_GRAB_BAG )
89 {
90 uno::Sequence< beans::PropertyValue > aSeq;
91 rPropPair.second.getValue() >>= aSeq;
92 nCellGrabBag += aSeq.getLength();
93 }
94 else if ( rPropPair.second.getGrabBagType() == ROW_GRAB_BAG )
95 nRowGrabBag++;
96
97 if ( rPropPair.first == PROP_PARA_STYLE_NAME ) pParaStyleProp = &rPropPair.second;
98 if ( rPropPair.first == PROP_CHAR_STYLE_NAME ) pCharStyleProp = &rPropPair.second;
99 if ( rPropPair.first == PROP_NUMBERING_RULES ) pNumRuleProp = &rPropPair.second;
100 }
101
102 // Style names have to be the first elements within the property sequence
103 // otherwise they will overwrite 'hard' attributes
104 if ( pParaStyleProp != nullptr )
105 m_aValues.push_back( makePropertyValue( getPropertyName( PROP_PARA_STYLE_NAME ), pParaStyleProp->getValue() ) );
106 if ( pCharStyleProp != nullptr )
107 m_aValues.push_back( makePropertyValue( getPropertyName( PROP_CHAR_STYLE_NAME ), pCharStyleProp->getValue() ) );
108 if ( pNumRuleProp != nullptr )
109 m_aValues.push_back( makePropertyValue(getPropertyName( PROP_NUMBERING_RULES ), pNumRuleProp->getValue() ) );
110
111 // If there are any grab bag properties, we need one slot for them.
112 uno::Sequence< beans::PropertyValue > aCharGrabBagValues( nCharGrabBag );
113 uno::Sequence< beans::PropertyValue > aParaGrabBagValues( nParaGrabBag );
114 uno::Sequence< beans::PropertyValue > aCellGrabBagValues( nCellGrabBag );
115 uno::Sequence< beans::PropertyValue > aRowGrabBagValues ( nRowGrabBag );
116 beans::PropertyValue* pCharGrabBagValues = aCharGrabBagValues.getArray();
117 beans::PropertyValue* pParaGrabBagValues = aParaGrabBagValues.getArray();
118 beans::PropertyValue* pCellGrabBagValues = aCellGrabBagValues.getArray();
119 beans::PropertyValue* pRowGrabBagValues = aRowGrabBagValues.getArray();
120 // Record index for the next property to be added in each grab bag.
121 sal_Int32 nRowGrabBagValue = 0;
122 sal_Int32 nCellGrabBagValue = 0;
123 sal_Int32 nParaGrabBagValue = 0;
124 sal_Int32 nCharGrabBagValue = 0;
125
126 for ( const auto& rPropPair : m_vMap )
127 {
128 if ( rPropPair.first != PROP_PARA_STYLE_NAME &&
129 rPropPair.first != PROP_CHAR_STYLE_NAME &&
130 rPropPair.first != PROP_NUMBERING_RULES )
131 {
132 if ( rPropPair.second.getGrabBagType() == CHAR_GRAB_BAG )
133 {
134 if ( bCharGrabBag )
135 {
136 pCharGrabBagValues[nCharGrabBagValue].Name = getPropertyName( rPropPair.first );
137 pCharGrabBagValues[nCharGrabBagValue].Value = rPropPair.second.getValue();
138 ++nCharGrabBagValue;
139 }
140 }
141 else if ( rPropPair.second.getGrabBagType() == PARA_GRAB_BAG )
142 {
143 pParaGrabBagValues[nParaGrabBagValue].Name = getPropertyName( rPropPair.first );
144 pParaGrabBagValues[nParaGrabBagValue].Value = rPropPair.second.getValue();
145 ++nParaGrabBagValue;
146 }
147 else if ( rPropPair.second.getGrabBagType() == CELL_GRAB_BAG )
148 {
149 pCellGrabBagValues[nCellGrabBagValue].Name = getPropertyName( rPropPair.first );
150 pCellGrabBagValues[nCellGrabBagValue].Value = rPropPair.second.getValue();
151 ++nCellGrabBagValue;
152 }
153 else if ( rPropPair.second.getGrabBagType() == ROW_GRAB_BAG )
154 {
155 pRowGrabBagValues[nRowGrabBagValue].Name = getPropertyName( rPropPair.first );
156 pRowGrabBagValues[nRowGrabBagValue].Value = rPropPair.second.getValue();
157 ++nRowGrabBagValue;
158 }
159 else if ( rPropPair.first == PROP_CELL_INTEROP_GRAB_BAG )
160 {
161 uno::Sequence< beans::PropertyValue > aSeq;
162 rPropPair.second.getValue() >>= aSeq;
163 std::copy(aSeq.begin(), aSeq.end(), pCellGrabBagValues + nCellGrabBagValue);
164 nCellGrabBagValue += aSeq.getLength();
165 }
166 else
167 {
168 m_aValues.push_back( makePropertyValue( getPropertyName( rPropPair.first ), rPropPair.second.getValue() ) );
169 }
170 }
171 }
172
173 if ( nCharGrabBag && bCharGrabBag )
174 m_aValues.push_back( makePropertyValue( "CharInteropGrabBag", uno::makeAny( aCharGrabBagValues ) ) );
175
176 if ( nParaGrabBag )
177 m_aValues.push_back( makePropertyValue( "ParaInteropGrabBag", uno::makeAny( aParaGrabBagValues ) ) );
178
179 if ( nCellGrabBag )
180 m_aValues.push_back( makePropertyValue( "CellInteropGrabBag", uno::makeAny( aCellGrabBagValues ) ) );
181
182 if ( nRowGrabBag )
183 m_aValues.push_back( makePropertyValue( "RowInteropGrabBag", uno::makeAny( aRowGrabBagValues ) ) );
184 }
185
186 return comphelper::containerToSequence( m_aValues );
187 }
188
189 #ifdef DBG_UTIL
lcl_AnyToTag(const uno::Any & rAny)190 static void lcl_AnyToTag( const uno::Any& rAny )
191 {
192 try {
193 sal_Int32 aInt = 0;
194 if ( rAny >>= aInt )
195 {
196 TagLogger::getInstance().attribute( "value", rAny );
197 }
198 else
199 {
200 TagLogger::getInstance().attribute( "unsignedValue", 0 );
201 }
202
203 sal_uInt32 auInt = 0;
204 rAny >>= auInt;
205 TagLogger::getInstance().attribute( "unsignedValue", auInt );
206
207 float aFloat = 0.0f;
208 if ( rAny >>= aFloat )
209 {
210 TagLogger::getInstance().attribute( "floatValue", rAny );
211 }
212 else
213 {
214 TagLogger::getInstance().attribute( "unsignedValue", 0 );
215 }
216
217 OUString aStr;
218 rAny >>= aStr;
219 TagLogger::getInstance().attribute( "stringValue", aStr );
220 }
221 catch ( ... )
222 {
223 }
224 }
225 #endif
226
Insert(PropertyIds eId,const uno::Any & rAny,bool bOverwrite,GrabBagType i_GrabBagType)227 void PropertyMap::Insert( PropertyIds eId, const uno::Any& rAny, bool bOverwrite, GrabBagType i_GrabBagType )
228 {
229 #ifdef DBG_UTIL
230 const OUString& rInsert = getPropertyName(eId);
231
232 TagLogger::getInstance().startElement("propertyMap.insert");
233 TagLogger::getInstance().attribute("name", rInsert);
234 lcl_AnyToTag(rAny);
235 TagLogger::getInstance().endElement();
236 #endif
237
238 if ( !bOverwrite )
239 m_vMap.insert(std::make_pair(eId, PropValue(rAny, i_GrabBagType)));
240 else
241 m_vMap[eId] = PropValue(rAny, i_GrabBagType);
242
243 Invalidate();
244 }
245
Erase(PropertyIds eId)246 void PropertyMap::Erase( PropertyIds eId )
247 {
248 // Safe call to erase, it throws no exceptions, even if eId is not in m_vMap
249 m_vMap.erase(eId);
250
251 Invalidate();
252 }
253
getProperty(PropertyIds eId) const254 boost::optional< PropertyMap::Property > PropertyMap::getProperty( PropertyIds eId ) const
255 {
256 std::map< PropertyIds, PropValue >::const_iterator aIter = m_vMap.find( eId );
257 if ( aIter == m_vMap.end() )
258 return boost::optional<Property>();
259 else
260 return std::make_pair( eId, aIter->second.getValue() );
261 }
262
isSet(PropertyIds eId) const263 bool PropertyMap::isSet( PropertyIds eId) const
264 {
265 return m_vMap.find( eId ) != m_vMap.end();
266 }
267
268 #ifdef DBG_UTIL
dumpXml() const269 void PropertyMap::dumpXml() const
270 {
271 TagLogger::getInstance().startElement( "PropertyMap" );
272
273 for ( const auto& rPropPair : m_vMap )
274 {
275 TagLogger::getInstance().startElement( "property" );
276
277 TagLogger::getInstance().attribute( "name", getPropertyName( rPropPair.first ) );
278
279 switch ( rPropPair.first )
280 {
281 case PROP_TABLE_COLUMN_SEPARATORS:
282 lcl_DumpTableColumnSeparators( rPropPair.second.getValue() );
283 break;
284 default:
285 {
286 try
287 {
288 sal_Int32 aInt = 0;
289 rPropPair.second.getValue() >>= aInt;
290 TagLogger::getInstance().attribute( "value", aInt );
291
292 sal_uInt32 auInt = 0;
293 rPropPair.second.getValue() >>= auInt;
294 TagLogger::getInstance().attribute( "unsignedValue", auInt );
295
296 float aFloat = 0.0;
297 rPropPair.second.getValue() >>= aFloat;
298 TagLogger::getInstance().attribute( "floatValue", aFloat );
299
300 rPropPair.second.getValue() >>= auInt;
301 TagLogger::getInstance().attribute( "stringValue", OUString() );
302 }
303 catch ( ... )
304 {
305 }
306 }
307 break;
308 }
309
310 TagLogger::getInstance().endElement();
311 }
312
313 TagLogger::getInstance().endElement();
314 }
315 #endif
316
InsertProps(const PropertyMapPtr & rMap,const bool bOverwrite)317 void PropertyMap::InsertProps( const PropertyMapPtr& rMap, const bool bOverwrite )
318 {
319 if ( rMap )
320 {
321 for ( const auto& rPropPair : rMap->m_vMap )
322 {
323 if ( bOverwrite || !m_vMap.count(rPropPair.first) )
324 m_vMap[rPropPair.first] = rPropPair.second;
325 }
326
327 insertTableProperties( rMap.get(), bOverwrite );
328
329 Invalidate();
330 }
331 }
332
insertTableProperties(const PropertyMap *,const bool)333 void PropertyMap::insertTableProperties( const PropertyMap*, const bool )
334 {
335 #ifdef DBG_UTIL
336 TagLogger::getInstance().element( "PropertyMap.insertTableProperties" );
337 #endif
338 }
339
printProperties()340 void PropertyMap::printProperties()
341 {
342 #ifdef DBG_UTIL
343 TagLogger::getInstance().startElement( "properties" );
344
345 for ( const auto& rPropPair : m_vMap )
346 {
347 SAL_INFO( "writerfilter", getPropertyName( rPropPair.first ) );
348
349 table::BorderLine2 aLine;
350 sal_Int32 nColor;
351 if ( rPropPair.second.getValue() >>= aLine )
352 {
353 TagLogger::getInstance().startElement( "borderline" );
354 TagLogger::getInstance().attribute( "color", aLine.Color );
355 TagLogger::getInstance().attribute( "inner", aLine.InnerLineWidth );
356 TagLogger::getInstance().attribute( "outer", aLine.OuterLineWidth );
357 TagLogger::getInstance().endElement();
358 }
359 else if ( rPropPair.second.getValue() >>= nColor )
360 {
361 TagLogger::getInstance().startElement( "color" );
362 TagLogger::getInstance().attribute( "number", nColor );
363 TagLogger::getInstance().endElement();
364 }
365 }
366
367 TagLogger::getInstance().endElement();
368 #else
369 (void) this; // avoid loplugin:staticmethods
370 #endif
371 }
372
SectionPropertyMap(bool bIsFirstSection)373 SectionPropertyMap::SectionPropertyMap( bool bIsFirstSection )
374 : m_bIsFirstSection( bIsFirstSection )
375 , m_eBorderApply( BorderApply::ToAllInSection )
376 , m_eBorderOffsetFrom( BorderOffsetFrom::Text )
377 , m_bTitlePage( false )
378 , m_nColumnCount( 0 )
379 , m_nColumnDistance( 1249 )
380 , m_bSeparatorLineIsOn( false )
381 , m_bEvenlySpaced( false )
382 , m_nPageNumber( -1 )
383 , m_nPageNumberType( -1 )
384 , m_nBreakType( -1 )
385 , m_nLeftMargin( 2540 ) // page left margin, default 1 inch = 1440 twip -> 2540 1/100 mm
386 , m_nRightMargin( 2540 ) // page right margin, default 1 inch = 1440 twip -> 2540 1/100 mm
387 , m_nTopMargin( 2540 )
388 , m_nBottomMargin( 2540 )
389 , m_nHeaderTop( 1270 ) // 720 twip
390 , m_nHeaderBottom( 1270 ) // 720 twip
391 , m_nGridType( 0 )
392 , m_nGridLinePitch( 1 )
393 , m_nDxtCharSpace( 0 )
394 , m_bGridSnapToChars( true )
395 , m_nLnnMod( 0 )
396 , m_nLnc(NS_ooxml::LN_Value_ST_LineNumberRestart_newPage)
397 , m_ndxaLnn( 0 )
398 , m_nLnnMin( 0 )
399 , m_bDefaultHeaderLinkToPrevious( true )
400 , m_bEvenPageHeaderLinkToPrevious( true )
401 , m_bFirstPageHeaderLinkToPrevious( true )
402 , m_bDefaultFooterLinkToPrevious( true )
403 , m_bEvenPageFooterLinkToPrevious( true )
404 , m_bFirstPageFooterLinkToPrevious( true )
405 {
406 #ifdef DBG_UTIL
407 static sal_Int32 nNumber = 0;
408 m_nDebugSectionNumber = nNumber++;
409 #endif
410
411 for ( sal_Int32 nBorder = 0; nBorder < 4; ++nBorder )
412 {
413 m_nBorderDistances[nBorder] = -1;
414 m_bBorderShadows[nBorder] = false;
415 }
416 // todo: set defaults in ApplyPropertiesToPageStyles
417 // initialize defaults
418 PaperInfo aLetter( PAPER_LETTER );
419 // page height, 1/100mm
420 Insert( PROP_HEIGHT, uno::makeAny( static_cast<sal_Int32>(aLetter.getHeight()) ) );
421 // page width, 1/100mm
422 Insert( PROP_WIDTH, uno::makeAny( static_cast<sal_Int32>(aLetter.getWidth()) ) );
423 // page left margin, default 0x5a0 (1440) twip -> 2540 1/100 mm
424 Insert( PROP_LEFT_MARGIN, uno::makeAny( sal_Int32(2540) ) );
425 // page right margin, default 0x5a0 (1440) twip -> 2540 1/100 mm
426 Insert( PROP_RIGHT_MARGIN, uno::makeAny( sal_Int32(2540) ) );
427 // page top margin, default 0x5a0 (1440) twip -> 2540 1/100 mm
428 Insert( PROP_TOP_MARGIN, uno::makeAny( sal_Int32(2540) ) );
429 // page bottom margin, default 0x5a0 (1440) twip -> 2540 1/100 mm
430 Insert( PROP_BOTTOM_MARGIN, uno::makeAny( sal_Int32(2540) ) );
431 // page style layout
432 Insert( PROP_PAGE_STYLE_LAYOUT, uno::makeAny( style::PageStyleLayout_ALL ) );
433 uno::Any aFalse( uno::makeAny( false ) );
434 Insert( PROP_GRID_DISPLAY, aFalse );
435 Insert( PROP_GRID_PRINT, aFalse );
436 Insert( PROP_GRID_MODE, uno::makeAny( text::TextGridMode::NONE ) );
437
438 if ( m_bIsFirstSection )
439 {
440 m_sFirstPageStyleName = getPropertyName( PROP_FIRST_PAGE );
441 m_sFollowPageStyleName = getPropertyName( PROP_STANDARD );
442 }
443 }
444
GetPageStyle(DomainMapper_Impl & rDM_Impl,bool bFirst)445 uno::Reference< beans::XPropertySet > SectionPropertyMap::GetPageStyle( DomainMapper_Impl& rDM_Impl,
446 bool bFirst )
447 {
448 const uno::Reference< container::XNameContainer >& xPageStyles = rDM_Impl.GetPageStyles();
449 const uno::Reference < lang::XMultiServiceFactory >& xTextFactory = rDM_Impl.GetTextFactory();
450 uno::Reference< beans::XPropertySet > xRet;
451 try
452 {
453 if ( bFirst )
454 {
455 if ( m_sFirstPageStyleName.isEmpty() && xPageStyles.is() )
456 {
457 m_sFirstPageStyleName = rDM_Impl.GetUnusedPageStyleName();
458 m_aFirstPageStyle.set( xTextFactory->createInstance( "com.sun.star.style.PageStyle" ),
459 uno::UNO_QUERY );
460
461 // Call insertByName() before GetPageStyle(), otherwise the
462 // first and the follow page style will have the same name, and
463 // insertByName() will fail.
464 if ( xPageStyles.is() )
465 xPageStyles->insertByName( m_sFirstPageStyleName, uno::makeAny( m_aFirstPageStyle ) );
466
467 // Ensure that m_aFollowPageStyle has been created
468 GetPageStyle( rDM_Impl, false );
469 // Chain m_aFollowPageStyle to be after m_aFirstPageStyle
470 m_aFirstPageStyle->setPropertyValue( "FollowStyle",
471 uno::makeAny( m_sFollowPageStyleName ) );
472 }
473 else if ( !m_aFirstPageStyle.is() && xPageStyles.is() )
474 {
475 xPageStyles->getByName( m_sFirstPageStyleName ) >>= m_aFirstPageStyle;
476 }
477 xRet = m_aFirstPageStyle;
478 }
479 else
480 {
481 if ( m_sFollowPageStyleName.isEmpty() && xPageStyles.is() )
482 {
483 m_sFollowPageStyleName = rDM_Impl.GetUnusedPageStyleName();
484 m_aFollowPageStyle.set( xTextFactory->createInstance( "com.sun.star.style.PageStyle" ),
485 uno::UNO_QUERY );
486 xPageStyles->insertByName( m_sFollowPageStyleName, uno::makeAny( m_aFollowPageStyle ) );
487 }
488 else if ( !m_aFollowPageStyle.is() && xPageStyles.is() )
489 {
490 xPageStyles->getByName( m_sFollowPageStyleName ) >>= m_aFollowPageStyle;
491 }
492 xRet = m_aFollowPageStyle;
493 }
494
495 }
496 catch ( const uno::Exception& )
497 {
498 DBG_UNHANDLED_EXCEPTION( "writerfilter" );
499 }
500
501 return xRet;
502 }
503
SetBorder(BorderPosition ePos,sal_Int32 nLineDistance,const table::BorderLine2 & rBorderLine,bool bShadow)504 void SectionPropertyMap::SetBorder( BorderPosition ePos, sal_Int32 nLineDistance, const table::BorderLine2& rBorderLine, bool bShadow )
505 {
506 m_oBorderLines[ePos] = rBorderLine;
507 m_nBorderDistances[ePos] = nLineDistance;
508 m_bBorderShadows[ePos] = bShadow;
509 }
510
ApplyBorderToPageStyles(DomainMapper_Impl & rDM_Impl,BorderApply eBorderApply,BorderOffsetFrom eOffsetFrom)511 void SectionPropertyMap::ApplyBorderToPageStyles( DomainMapper_Impl& rDM_Impl,
512 BorderApply eBorderApply, BorderOffsetFrom eOffsetFrom )
513 {
514 /*
515 page border applies to:
516 nIntValue & 0x07 ->
517 0 all pages in this section
518 1 first page in this section
519 2 all pages in this section but first
520 3 whole document (all sections)
521 nIntValue & 0x18 -> page border depth 0 - in front 1- in back
522 nIntValue & 0xe0 ->
523 page border offset from:
524 0 offset from text
525 1 offset from edge of page
526 */
527 uno::Reference< beans::XPropertySet > xFirst;
528 uno::Reference< beans::XPropertySet > xSecond;
529 // todo: negative spacing (from ww8par6.cxx)
530 switch ( eBorderApply )
531 {
532 case BorderApply::ToAllInSection: // all styles
533 if ( !m_sFollowPageStyleName.isEmpty() )
534 xFirst = GetPageStyle( rDM_Impl, false );
535 if ( !m_sFirstPageStyleName.isEmpty() )
536 xSecond = GetPageStyle( rDM_Impl, true );
537 break;
538 case BorderApply::ToFirstPageInSection: // first page
539 if ( !m_sFirstPageStyleName.isEmpty() )
540 xFirst = GetPageStyle( rDM_Impl, true );
541 break;
542 case BorderApply::ToAllButFirstInSection: // left and right
543 if ( !m_sFollowPageStyleName.isEmpty() )
544 xFirst = GetPageStyle( rDM_Impl, false );
545 break;
546 default:
547 return;
548 }
549
550 // has to be sorted like enum BorderPosition: l-r-t-b
551 const PropertyIds aBorderIds[4] =
552 {
553 PROP_LEFT_BORDER,
554 PROP_RIGHT_BORDER,
555 PROP_TOP_BORDER,
556 PROP_BOTTOM_BORDER
557 };
558
559 const PropertyIds aBorderDistanceIds[4] =
560 {
561 PROP_LEFT_BORDER_DISTANCE,
562 PROP_RIGHT_BORDER_DISTANCE,
563 PROP_TOP_BORDER_DISTANCE,
564 PROP_BOTTOM_BORDER_DISTANCE
565 };
566
567 const PropertyIds aMarginIds[4] =
568 {
569 PROP_LEFT_MARGIN,
570 PROP_RIGHT_MARGIN,
571 PROP_TOP_MARGIN,
572 PROP_BOTTOM_MARGIN
573 };
574
575 for ( sal_Int32 nBorder = 0; nBorder < 4; ++nBorder )
576 {
577 if ( m_oBorderLines[nBorder] )
578 {
579 const OUString sBorderName = getPropertyName( aBorderIds[nBorder] );
580 if ( xFirst.is() )
581 xFirst->setPropertyValue( sBorderName, uno::makeAny( *m_oBorderLines[nBorder] ) );
582 if ( xSecond.is() )
583 xSecond->setPropertyValue( sBorderName, uno::makeAny( *m_oBorderLines[nBorder] ) );
584 }
585 if ( m_nBorderDistances[nBorder] >= 0 )
586 {
587 sal_uInt32 nLineWidth = 0;
588 if ( m_oBorderLines[nBorder] )
589 nLineWidth = m_oBorderLines[nBorder]->LineWidth;
590 if ( xFirst.is() )
591 SetBorderDistance( xFirst, aMarginIds[nBorder], aBorderDistanceIds[nBorder],
592 m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth );
593 if ( xSecond.is() )
594 SetBorderDistance( xSecond, aMarginIds[nBorder], aBorderDistanceIds[nBorder],
595 m_nBorderDistances[nBorder], eOffsetFrom, nLineWidth );
596 }
597 }
598
599 if ( m_bBorderShadows[BORDER_RIGHT] )
600 {
601 table::ShadowFormat aFormat = getShadowFromBorder( *m_oBorderLines[BORDER_RIGHT] );
602 if ( xFirst.is() )
603 xFirst->setPropertyValue( getPropertyName( PROP_SHADOW_FORMAT ), uno::makeAny( aFormat ) );
604 if ( xSecond.is() )
605 xSecond->setPropertyValue( getPropertyName( PROP_SHADOW_FORMAT ), uno::makeAny( aFormat ) );
606 }
607 }
608
getShadowFromBorder(const table::BorderLine2 & rBorder)609 table::ShadowFormat PropertyMap::getShadowFromBorder( const table::BorderLine2& rBorder )
610 {
611 // In Word UI, shadow is a boolean property, in OOXML, it's a boolean
612 // property of each 4 border type, finally in Writer the border is a
613 // property of the page style, with shadow location, distance and
614 // color. See SwWW8ImplReader::SetShadow().
615 table::ShadowFormat aFormat;
616 aFormat.Color = sal_Int32(COL_BLACK);
617 aFormat.Location = table::ShadowLocation_BOTTOM_RIGHT;
618 aFormat.ShadowWidth = rBorder.LineWidth;
619 return aFormat;
620 }
621
SetBorderDistance(const uno::Reference<beans::XPropertySet> & xStyle,PropertyIds eMarginId,PropertyIds eDistId,sal_Int32 nDistance,BorderOffsetFrom eOffsetFrom,sal_uInt32 nLineWidth)622 void SectionPropertyMap::SetBorderDistance( const uno::Reference< beans::XPropertySet >& xStyle,
623 PropertyIds eMarginId,
624 PropertyIds eDistId,
625 sal_Int32 nDistance,
626 BorderOffsetFrom eOffsetFrom,
627 sal_uInt32 nLineWidth )
628 {
629 if (!xStyle.is())
630 return;
631 const OUString sMarginName = getPropertyName( eMarginId );
632 const OUString sBorderDistanceName = getPropertyName( eDistId );
633 uno::Any aMargin = xStyle->getPropertyValue( sMarginName );
634 sal_Int32 nMargin = 0;
635 aMargin >>= nMargin;
636 editeng::BorderDistanceFromWord(eOffsetFrom == BorderOffsetFrom::Edge, nMargin, nDistance,
637 nLineWidth);
638
639 // Change the margins with the border distance
640 uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
641 uno::Sequence<OUString> aProperties { sMarginName, sBorderDistanceName };
642 uno::Sequence<uno::Any> aValues { uno::makeAny( nMargin ), uno::makeAny( nDistance ) };
643 xMultiSet->setPropertyValues( aProperties, aValues );
644 }
645
DontBalanceTextColumns()646 void SectionPropertyMap::DontBalanceTextColumns()
647 {
648 try
649 {
650 if ( m_xColumnContainer.is() )
651 m_xColumnContainer->setPropertyValue( "DontBalanceTextColumns", uno::makeAny( true ) );
652 }
653 catch ( const uno::Exception& )
654 {
655 OSL_FAIL( "Exception in SectionPropertyMap::DontBalanceTextColumns" );
656 }
657 }
658
ApplySectionProperties(const uno::Reference<beans::XPropertySet> & xSection,DomainMapper_Impl &)659 void SectionPropertyMap::ApplySectionProperties( const uno::Reference< beans::XPropertySet >& xSection, DomainMapper_Impl& /*rDM_Impl*/ )
660 {
661 try
662 {
663 if ( xSection.is() )
664 {
665 boost::optional< PropertyMap::Property > pProp = getProperty( PROP_WRITING_MODE );
666 if ( pProp )
667 xSection->setPropertyValue( "WritingMode", pProp->second );
668 }
669 }
670 catch ( uno::Exception& )
671 {
672 DBG_UNHANDLED_EXCEPTION("writerfilter", "Exception in SectionPropertyMap::ApplySectionProperties");
673 }
674 }
675
ApplyProtectionProperties(uno::Reference<beans::XPropertySet> & xSection,DomainMapper_Impl & rDM_Impl)676 void SectionPropertyMap::ApplyProtectionProperties( uno::Reference< beans::XPropertySet >& xSection, DomainMapper_Impl& rDM_Impl )
677 {
678 try
679 {
680 // Word implements section protection differently than LO.
681 // PROP_IS_PROTECTED only applies if global setting GetProtectForm is enabled.
682 bool bIsProtected = rDM_Impl.GetSettingsTable()->GetProtectForm();
683 if ( bIsProtected )
684 {
685 // If form protection is enabled then section protection is enabled, unless explicitly disabled
686 if ( isSet(PROP_IS_PROTECTED) )
687 getProperty(PROP_IS_PROTECTED)->second >>= bIsProtected;
688 if ( !xSection.is() )
689 xSection = rDM_Impl.appendTextSectionAfter( m_xStartingRange );
690 if ( xSection.is() )
691 xSection->setPropertyValue( getPropertyName(PROP_IS_PROTECTED), uno::makeAny(bIsProtected) );
692 }
693 }
694 catch ( uno::Exception& )
695 {
696 DBG_UNHANDLED_EXCEPTION("writerfilter", "ApplyProtectionProperties failed setting PROP_IS_PROTECTED");
697 }
698 }
699
ApplyColumnProperties(const uno::Reference<beans::XPropertySet> & xColumnContainer,DomainMapper_Impl & rDM_Impl)700 uno::Reference< text::XTextColumns > SectionPropertyMap::ApplyColumnProperties( const uno::Reference< beans::XPropertySet >& xColumnContainer,
701 DomainMapper_Impl& rDM_Impl )
702 {
703 uno::Reference< text::XTextColumns > xColumns;
704 try
705 {
706 const OUString sTextColumns = getPropertyName( PROP_TEXT_COLUMNS );
707 if ( xColumnContainer.is() )
708 xColumnContainer->getPropertyValue( sTextColumns ) >>= xColumns;
709 uno::Reference< beans::XPropertySet > xColumnPropSet( xColumns, uno::UNO_QUERY_THROW );
710 if ( !m_bEvenlySpaced &&
711 ( sal_Int32(m_aColWidth.size()) == (m_nColumnCount + 1) ) &&
712 ( (sal_Int32(m_aColDistance.size()) == m_nColumnCount) || (sal_Int32(m_aColDistance.size()) == m_nColumnCount + 1) ) )
713 {
714 // the column width in word is an absolute value, in OOo it's relative
715 // the distances are both absolute
716 sal_Int32 nColSum = 0;
717 for ( sal_Int32 nCol = 0; nCol <= m_nColumnCount; ++nCol )
718 {
719 nColSum += m_aColWidth[nCol];
720 if ( nCol )
721 nColSum += m_aColDistance[nCol - 1];
722 }
723
724 sal_Int32 nRefValue = xColumns->getReferenceValue();
725 double fRel = nColSum ? double( nRefValue ) / double( nColSum ) : 0.0;
726 uno::Sequence< text::TextColumn > aColumns( m_nColumnCount + 1 );
727 text::TextColumn* pColumn = aColumns.getArray();
728
729 nColSum = 0;
730 for ( sal_Int32 nCol = 0; nCol <= m_nColumnCount; ++nCol )
731 {
732 const double fLeft = nCol ? m_aColDistance[nCol - 1] / 2 : 0;
733 pColumn[nCol].LeftMargin = fLeft;
734 const double fRight = nCol == m_nColumnCount ? 0 : m_aColDistance[nCol] / 2;
735 pColumn[nCol].RightMargin = fRight;
736 const double fWidth = m_aColWidth[nCol];
737 pColumn[nCol].Width = (fWidth + fLeft + fRight) * fRel;
738 nColSum += pColumn[nCol].Width;
739 }
740 if ( nColSum != nRefValue )
741 pColumn[m_nColumnCount].Width += (nRefValue - nColSum);
742 assert( pColumn[m_nColumnCount].Width >= 0 );
743
744 xColumns->setColumns( aColumns );
745 }
746 else
747 {
748 xColumns->setColumnCount( m_nColumnCount + 1 );
749 xColumnPropSet->setPropertyValue( getPropertyName( PROP_AUTOMATIC_DISTANCE ), uno::makeAny( m_nColumnDistance ) );
750 }
751
752 if ( m_bSeparatorLineIsOn )
753 {
754 xColumnPropSet->setPropertyValue( "SeparatorLineIsOn", uno::makeAny( true ) );
755 xColumnPropSet->setPropertyValue( "SeparatorLineVerticalAlignment", uno::makeAny( style::VerticalAlignment_TOP ) );
756 xColumnPropSet->setPropertyValue( "SeparatorLineRelativeHeight", uno::makeAny( static_cast<sal_Int8>(100) ) );
757 xColumnPropSet->setPropertyValue( "SeparatorLineColor", uno::makeAny( static_cast<sal_Int32>(COL_BLACK) ) );
758 // 1 twip -> 2 mm100.
759 xColumnPropSet->setPropertyValue( "SeparatorLineWidth", uno::makeAny( static_cast<sal_Int32>(2) ) );
760 }
761 xColumnContainer->setPropertyValue( sTextColumns, uno::makeAny( xColumns ) );
762 // Set the columns to be unbalanced if that compatibility option is set or this is the last section.
763 m_xColumnContainer = xColumnContainer;
764 if ( rDM_Impl.GetSettingsTable()->GetNoColumnBalance() || rDM_Impl.GetIsLastSectionGroup() )
765 DontBalanceTextColumns();
766 }
767 catch ( const uno::Exception& )
768 {
769 OSL_FAIL( "Exception in SectionPropertyMap::ApplyColumnProperties" );
770 }
771 return xColumns;
772 }
773
HasHeader(bool bFirstPage) const774 bool SectionPropertyMap::HasHeader( bool bFirstPage ) const
775 {
776 bool bRet = false;
777 if ( (bFirstPage && m_aFirstPageStyle.is()) || (!bFirstPage && m_aFollowPageStyle.is()) )
778 {
779 if ( bFirstPage )
780 m_aFirstPageStyle->getPropertyValue(
781 getPropertyName( PROP_HEADER_IS_ON ) ) >>= bRet;
782 else
783 m_aFollowPageStyle->getPropertyValue(
784 getPropertyName( PROP_HEADER_IS_ON ) ) >>= bRet;
785 }
786 return bRet;
787 }
788
HasFooter(bool bFirstPage) const789 bool SectionPropertyMap::HasFooter( bool bFirstPage ) const
790 {
791 bool bRet = false;
792 if ( (bFirstPage && m_aFirstPageStyle.is()) || (!bFirstPage && m_aFollowPageStyle.is()) )
793 {
794 if ( bFirstPage )
795 m_aFirstPageStyle->getPropertyValue( getPropertyName( PROP_FOOTER_IS_ON ) ) >>= bRet;
796 else
797 m_aFollowPageStyle->getPropertyValue( getPropertyName( PROP_FOOTER_IS_ON ) ) >>= bRet;
798 }
799 return bRet;
800 }
801
802 #define MIN_HEAD_FOOT_HEIGHT 100 // minimum header/footer height
803
CopyHeaderFooterTextProperty(const uno::Reference<beans::XPropertySet> & xPrevStyle,const uno::Reference<beans::XPropertySet> & xStyle,PropertyIds ePropId)804 void SectionPropertyMap::CopyHeaderFooterTextProperty( const uno::Reference< beans::XPropertySet >& xPrevStyle,
805 const uno::Reference< beans::XPropertySet >& xStyle,
806 PropertyIds ePropId )
807 {
808 try {
809 OUString sName = getPropertyName( ePropId );
810
811 SAL_INFO( "writerfilter", "Copying " << sName );
812 uno::Reference< text::XTextCopy > xTxt;
813 if ( xStyle.is() )
814 xTxt.set( xStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
815
816 uno::Reference< text::XTextCopy > xPrevTxt;
817 if ( xPrevStyle.is() )
818 xPrevTxt.set( xPrevStyle->getPropertyValue( sName ), uno::UNO_QUERY_THROW );
819
820 xTxt->copyText( xPrevTxt );
821 }
822 catch ( const uno::Exception& )
823 {
824 TOOLS_INFO_EXCEPTION( "writerfilter", "An exception occurred in SectionPropertyMap::CopyHeaderFooterTextProperty( )" );
825 }
826 }
827
828 // Copy headers and footers from the previous page style.
CopyHeaderFooter(const uno::Reference<beans::XPropertySet> & xPrevStyle,const uno::Reference<beans::XPropertySet> & xStyle,bool bOmitRightHeader,bool bOmitLeftHeader,bool bOmitRightFooter,bool bOmitLeftFooter)829 void SectionPropertyMap::CopyHeaderFooter( const uno::Reference< beans::XPropertySet >& xPrevStyle,
830 const uno::Reference< beans::XPropertySet >& xStyle,
831 bool bOmitRightHeader,
832 bool bOmitLeftHeader,
833 bool bOmitRightFooter,
834 bool bOmitLeftFooter )
835 {
836 bool bHasPrevHeader = false;
837 bool bHeaderIsShared = true;
838 OUString sHeaderIsOn = getPropertyName( PROP_HEADER_IS_ON );
839 OUString sHeaderIsShared = getPropertyName( PROP_HEADER_IS_SHARED );
840 if ( xPrevStyle.is() )
841 {
842 xPrevStyle->getPropertyValue( sHeaderIsOn ) >>= bHasPrevHeader;
843 xPrevStyle->getPropertyValue( sHeaderIsShared ) >>= bHeaderIsShared;
844 }
845
846 if ( bHasPrevHeader )
847 {
848 uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
849 uno::Sequence<OUString> aProperties { sHeaderIsOn, sHeaderIsShared };
850 uno::Sequence<uno::Any> aValues { uno::makeAny( true ), uno::makeAny( bHeaderIsShared ) };
851 xMultiSet->setPropertyValues( aProperties, aValues );
852 if ( !bOmitRightHeader )
853 {
854 CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
855 PROP_HEADER_TEXT );
856 }
857 if ( !bHeaderIsShared && !bOmitLeftHeader )
858 {
859 CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
860 PROP_HEADER_TEXT_LEFT );
861 }
862 }
863
864 bool bHasPrevFooter = false;
865 bool bFooterIsShared = true;
866 OUString sFooterIsOn = getPropertyName( PROP_FOOTER_IS_ON );
867 OUString sFooterIsShared = getPropertyName( PROP_FOOTER_IS_SHARED );
868 if ( xPrevStyle.is() )
869 {
870 xPrevStyle->getPropertyValue( sFooterIsOn ) >>= bHasPrevFooter;
871 xPrevStyle->getPropertyValue( sFooterIsShared ) >>= bFooterIsShared;
872 }
873
874 if ( bHasPrevFooter )
875 {
876 uno::Reference< beans::XMultiPropertySet > xMultiSet( xStyle, uno::UNO_QUERY_THROW );
877 uno::Sequence<OUString> aProperties { sFooterIsOn, sFooterIsShared };
878 uno::Sequence<uno::Any> aValues { uno::makeAny( true ), uno::makeAny( bFooterIsShared ) };
879 xMultiSet->setPropertyValues( aProperties, aValues );
880 if ( !bOmitRightFooter )
881 {
882 CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
883 PROP_FOOTER_TEXT );
884 }
885 if ( !bFooterIsShared && !bOmitLeftFooter )
886 {
887 CopyHeaderFooterTextProperty( xPrevStyle, xStyle,
888 PROP_FOOTER_TEXT_LEFT );
889 }
890 }
891 }
892
893 // Copy header and footer content from the previous docx section as needed.
894 //
895 // Any headers and footers which were not defined in this docx section
896 // should be "linked" with the corresponding header or footer from the
897 // previous section. LO does not support linking of header/footer content
898 // across page styles so we just copy the content from the previous section.
CopyLastHeaderFooter(bool bFirstPage,DomainMapper_Impl & rDM_Impl)899 void SectionPropertyMap::CopyLastHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl )
900 {
901 SAL_INFO( "writerfilter", "START>>> SectionPropertyMap::CopyLastHeaderFooter()" );
902 SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
903 if ( pLastContext )
904 {
905 uno::Reference< beans::XPropertySet > xPrevStyle = pLastContext->GetPageStyle( rDM_Impl,
906 bFirstPage );
907 uno::Reference< beans::XPropertySet > xStyle = GetPageStyle( rDM_Impl,
908 bFirstPage );
909
910 if ( bFirstPage )
911 {
912 CopyHeaderFooter( xPrevStyle, xStyle,
913 !m_bFirstPageHeaderLinkToPrevious, true,
914 !m_bFirstPageFooterLinkToPrevious, true );
915 }
916 else
917 {
918 CopyHeaderFooter( xPrevStyle, xStyle,
919 !m_bDefaultHeaderLinkToPrevious,
920 !m_bEvenPageHeaderLinkToPrevious,
921 !m_bDefaultFooterLinkToPrevious,
922 !m_bEvenPageFooterLinkToPrevious );
923 }
924 }
925 SAL_INFO( "writerfilter", "END>>> SectionPropertyMap::CopyLastHeaderFooter()" );
926 }
927
PrepareHeaderFooterProperties(bool bFirstPage)928 void SectionPropertyMap::PrepareHeaderFooterProperties( bool bFirstPage )
929 {
930 bool bCopyFirstToFollow = bFirstPage && m_bTitlePage && m_aFollowPageStyle.is();
931
932 sal_Int32 nTopMargin = m_nTopMargin;
933 sal_Int32 nHeaderTop = m_nHeaderTop;
934 if ( HasHeader( bFirstPage ) )
935 {
936 nTopMargin = nHeaderTop;
937 if ( m_nTopMargin > 0 && m_nTopMargin > nHeaderTop )
938 nHeaderTop = m_nTopMargin - nHeaderTop;
939 else
940 nHeaderTop = 0;
941
942 // minimum header height 1mm
943 if ( nHeaderTop < MIN_HEAD_FOOT_HEIGHT )
944 nHeaderTop = MIN_HEAD_FOOT_HEIGHT;
945 }
946
947
948 if ( m_nTopMargin >= 0 ) //fixed height header -> see WW8Par6.hxx
949 {
950 Insert( PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::makeAny( true ) );
951 Insert( PROP_HEADER_DYNAMIC_SPACING, uno::makeAny( true ) );
952 Insert( PROP_HEADER_BODY_DISTANCE, uno::makeAny( nHeaderTop - MIN_HEAD_FOOT_HEIGHT ) );// ULSpace.Top()
953 Insert( PROP_HEADER_HEIGHT, uno::makeAny( nHeaderTop ) );
954
955 if (bCopyFirstToFollow && HasHeader(/*bFirstPage=*/true))
956 {
957 m_aFollowPageStyle->setPropertyValue("HeaderDynamicSpacing",
958 getProperty(PROP_HEADER_DYNAMIC_SPACING)->second);
959 m_aFollowPageStyle->setPropertyValue("HeaderHeight",
960 getProperty(PROP_HEADER_HEIGHT)->second);
961 }
962 }
963 else
964 {
965 //todo: old filter fakes a frame into the header/footer to support overlapping
966 //current setting is completely wrong!
967 Insert( PROP_HEADER_HEIGHT, uno::makeAny( nHeaderTop ) );
968 Insert( PROP_HEADER_BODY_DISTANCE, uno::makeAny( m_nTopMargin - nHeaderTop ) );
969 Insert( PROP_HEADER_IS_DYNAMIC_HEIGHT, uno::makeAny( false ) );
970 Insert( PROP_HEADER_DYNAMIC_SPACING, uno::makeAny( false ) );
971 }
972
973 sal_Int32 nBottomMargin = m_nBottomMargin;
974 sal_Int32 nHeaderBottom = m_nHeaderBottom;
975 if ( HasFooter( bFirstPage ) )
976 {
977 nBottomMargin = nHeaderBottom;
978 if ( m_nBottomMargin > 0 && m_nBottomMargin > nHeaderBottom )
979 nHeaderBottom = m_nBottomMargin - nHeaderBottom;
980 else
981 nHeaderBottom = 0;
982 if ( nHeaderBottom < MIN_HEAD_FOOT_HEIGHT )
983 nHeaderBottom = MIN_HEAD_FOOT_HEIGHT;
984 }
985
986 if ( m_nBottomMargin >= 0 ) //fixed height footer -> see WW8Par6.hxx
987 {
988 Insert( PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::makeAny( true ) );
989 Insert( PROP_FOOTER_DYNAMIC_SPACING, uno::makeAny( true ) );
990 Insert( PROP_FOOTER_BODY_DISTANCE, uno::makeAny( nHeaderBottom - MIN_HEAD_FOOT_HEIGHT ) );
991 Insert( PROP_FOOTER_HEIGHT, uno::makeAny( nHeaderBottom ) );
992
993 if (bCopyFirstToFollow && HasFooter(/*bFirstPage=*/true))
994 {
995 m_aFollowPageStyle->setPropertyValue("FooterDynamicSpacing",
996 getProperty(PROP_FOOTER_DYNAMIC_SPACING)->second);
997 m_aFollowPageStyle->setPropertyValue("FooterHeight",
998 getProperty(PROP_FOOTER_HEIGHT)->second);
999 }
1000 }
1001 else
1002 {
1003 //todo: old filter fakes a frame into the header/footer to support overlapping
1004 //current setting is completely wrong!
1005 Insert( PROP_FOOTER_IS_DYNAMIC_HEIGHT, uno::makeAny( false ) );
1006 Insert( PROP_FOOTER_DYNAMIC_SPACING, uno::makeAny( false ) );
1007 Insert( PROP_FOOTER_HEIGHT, uno::makeAny( m_nBottomMargin - nHeaderBottom ) );
1008 Insert( PROP_FOOTER_BODY_DISTANCE, uno::makeAny( nHeaderBottom ) );
1009 }
1010
1011 //now set the top/bottom margin for the follow page style
1012 Insert( PROP_TOP_MARGIN, uno::makeAny( std::max<sal_Int32>(nTopMargin, 0) ) );
1013 Insert( PROP_BOTTOM_MARGIN, uno::makeAny( std::max<sal_Int32>(nBottomMargin, 0) ) );
1014
1015 if (bCopyFirstToFollow)
1016 {
1017 if (HasHeader(/*bFirstPage=*/true))
1018 m_aFollowPageStyle->setPropertyValue("TopMargin", getProperty(PROP_TOP_MARGIN)->second);
1019 if (HasFooter(/*bFirstPage=*/true))
1020 m_aFollowPageStyle->setPropertyValue("BottomMargin",
1021 getProperty(PROP_BOTTOM_MARGIN)->second);
1022 }
1023 }
1024
lcl_GetRangeProperties(bool bIsFirstSection,DomainMapper_Impl & rDM_Impl,const uno::Reference<text::XTextRange> & xStartingRange)1025 static uno::Reference< beans::XPropertySet > lcl_GetRangeProperties( bool bIsFirstSection,
1026 DomainMapper_Impl& rDM_Impl,
1027 const uno::Reference< text::XTextRange >& xStartingRange )
1028 {
1029 uno::Reference< beans::XPropertySet > xRangeProperties;
1030 if ( bIsFirstSection && rDM_Impl.GetBodyText().is() )
1031 {
1032 uno::Reference< container::XEnumerationAccess > xEnumAccess( rDM_Impl.GetBodyText(), uno::UNO_QUERY_THROW );
1033 uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
1034 xRangeProperties.set( xEnum->nextElement(), uno::UNO_QUERY_THROW );
1035 if ( rDM_Impl.GetIsDummyParaAddedForTableInSection() && xEnum->hasMoreElements() )
1036 xRangeProperties.set( xEnum->nextElement(), uno::UNO_QUERY_THROW );
1037 }
1038 else if ( xStartingRange.is() )
1039 xRangeProperties.set( xStartingRange, uno::UNO_QUERY_THROW );
1040 return xRangeProperties;
1041 }
1042
HandleMarginsHeaderFooter(bool bFirstPage,DomainMapper_Impl & rDM_Impl)1043 void SectionPropertyMap::HandleMarginsHeaderFooter( bool bFirstPage, DomainMapper_Impl& rDM_Impl )
1044 {
1045 Insert( PROP_LEFT_MARGIN, uno::makeAny( m_nLeftMargin ) );
1046 Insert( PROP_RIGHT_MARGIN, uno::makeAny( m_nRightMargin ) );
1047
1048 if ( rDM_Impl.m_oBackgroundColor )
1049 Insert( PROP_BACK_COLOR, uno::makeAny( *rDM_Impl.m_oBackgroundColor ) );
1050
1051 // Check for missing footnote separator only in case there is at least
1052 // one footnote.
1053 if (rDM_Impl.m_bHasFtn && !rDM_Impl.m_bHasFtnSep)
1054 {
1055 // Set footnote line width to zero, document has no footnote separator.
1056 Insert(PROP_FOOTNOTE_LINE_RELATIVE_WIDTH, uno::makeAny(sal_Int32(0)));
1057 }
1058 if ( rDM_Impl.m_bHasFtnSep )
1059 {
1060 //If default paragraph style is RTL, footnote separator should be right aligned
1061 //and for RTL locales, LTR default paragraph style should present a left aligned footnote separator
1062 try
1063 {
1064 uno::Reference<style::XStyleFamiliesSupplier> xStylesSupplier(rDM_Impl.GetTextDocument(), uno::UNO_QUERY);
1065 if ( xStylesSupplier.is() )
1066 {
1067 uno::Reference<container::XNameAccess> xStyleFamilies = xStylesSupplier->getStyleFamilies();
1068 uno::Reference<container::XNameAccess> xParagraphStyles;
1069 if ( xStyleFamilies.is() )
1070 xStyleFamilies->getByName("ParagraphStyles") >>= xParagraphStyles;
1071 uno::Reference<beans::XPropertySet> xStandard;
1072 if ( xParagraphStyles.is() )
1073 xParagraphStyles->getByName("Standard") >>= xStandard;
1074 if ( xStandard.is() )
1075 {
1076 sal_Int16 aWritingMode(0);
1077 xStandard->getPropertyValue( getPropertyName(PROP_WRITING_MODE) ) >>= aWritingMode;
1078 if( aWritingMode == text::WritingMode2::RL_TB )
1079 Insert( PROP_FOOTNOTE_LINE_ADJUST, uno::makeAny( sal_Int16(text::HorizontalAdjust_RIGHT) ), false );
1080 else
1081 Insert( PROP_FOOTNOTE_LINE_ADJUST, uno::makeAny( sal_Int16(text::HorizontalAdjust_LEFT) ), false );
1082 }
1083 }
1084 }
1085 catch ( const uno::Exception& ) {}
1086 }
1087
1088 /*** if headers/footers are available then the top/bottom margins of the
1089 header/footer are copied to the top/bottom margin of the page
1090 */
1091 CopyLastHeaderFooter( bFirstPage, rDM_Impl );
1092 PrepareHeaderFooterProperties( bFirstPage );
1093 }
1094
FloatingTableConversion(const DomainMapper_Impl & rDM_Impl,FloatingTableInfo & rInfo)1095 bool SectionPropertyMap::FloatingTableConversion( const DomainMapper_Impl& rDM_Impl, FloatingTableInfo& rInfo )
1096 {
1097 // This is OOXML version of the code deciding if the table needs to be
1098 // in a floating frame.
1099 // For ww8 code, see SwWW8ImplReader::FloatingTableConversion in
1100 // sw/source/filter/ww8/ww8par.cxx
1101 // The two should do the same, so if you make changes here, please check
1102 // that the other is in sync.
1103
1104 // Note that this is just a list of heuristics till sw core can have a
1105 // table that is floating and can span over multiple pages at the same
1106 // time.
1107
1108 // If there is an explicit section break right after a table, then there
1109 // will be no wrapping anyway.
1110 if (rDM_Impl.m_bConvertedTable && !rDM_Impl.GetIsLastSectionGroup() && rInfo.m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_nextPage)
1111 return false;
1112
1113 sal_Int32 nPageWidth = GetPageWidth();
1114 sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin();
1115 // Count the layout width of the table.
1116 sal_Int32 nTableWidth = rInfo.m_nTableWidth;
1117 if (rInfo.m_nTableWidthType == text::SizeType::VARIABLE)
1118 {
1119 nTableWidth *= nTextAreaWidth / 100.0;
1120 }
1121 sal_Int32 nLeftMargin = 0;
1122 if ( rInfo.getPropertyValue( "LeftMargin" ) >>= nLeftMargin )
1123 nTableWidth += nLeftMargin;
1124 sal_Int32 nRightMargin = 0;
1125 if ( rInfo.getPropertyValue( "RightMargin" ) >>= nRightMargin )
1126 nTableWidth += nRightMargin;
1127
1128 sal_Int16 nHoriOrientRelation = rInfo.getPropertyValue( "HoriOrientRelation" ).get<sal_Int16>();
1129 sal_Int16 nVertOrientRelation = rInfo.getPropertyValue( "VertOrientRelation" ).get<sal_Int16>();
1130 if ( nHoriOrientRelation == text::RelOrientation::PAGE_FRAME && nVertOrientRelation == text::RelOrientation::PAGE_FRAME )
1131 {
1132 sal_Int16 nHoriOrient = rInfo.getPropertyValue( "HoriOrient" ).get<sal_Int16>();
1133 sal_Int16 nVertOrient = rInfo.getPropertyValue( "VertOrient" ).get<sal_Int16>();
1134 if ( nHoriOrient == text::HoriOrientation::NONE && nVertOrient == text::VertOrientation::NONE )
1135 {
1136 // Anchor position is relative to the page horizontally and vertically as well and is an absolute position.
1137 // The more close we are to the left edge, the less likely there will be any wrapping.
1138 // The more close we are to the bottom, the more likely the table will span over to the next page
1139 // So if we're in the bottom left quarter, don't do any conversion.
1140 sal_Int32 nHoriOrientPosition = rInfo.getPropertyValue( "HoriOrientPosition" ).get<sal_Int32>();
1141 sal_Int32 nVertOrientPosition = rInfo.getPropertyValue( "VertOrientPosition" ).get<sal_Int32>();
1142 sal_Int32 nPageHeight = getProperty( PROP_HEIGHT )->second.get<sal_Int32>();
1143 if ( nHoriOrientPosition < (nPageWidth / 2) && nVertOrientPosition >( nPageHeight / 2 ) )
1144 return false;
1145 }
1146 }
1147
1148 // It seems Word has a limit here, so that in case the table width is quite
1149 // close to the text area width, then it won't perform a wrapping, even in
1150 // case the content (e.g. an empty paragraph) would fit. The magic constant
1151 // here represents this limit.
1152 const sal_Int32 nMagicNumber = 469;
1153
1154 // If the table's with is smaller than the text area width, text might
1155 // be next to the table and so it should behave as a floating table.
1156 if ( (nTableWidth + nMagicNumber) < nTextAreaWidth )
1157 return true;
1158
1159 // If the position is relative to the edge of the page, then we need to check the whole
1160 // page width to see whether text can fit next to the table.
1161 if ( nHoriOrientRelation == text::RelOrientation::PAGE_FRAME )
1162 {
1163 // If the table is wide enough so that no text fits next to it, then don't create a fly
1164 // for the table: no wrapping will be performed anyway, but multi-page
1165 // tables will be broken.
1166 if ((nTableWidth + nMagicNumber) < (nPageWidth - std::min(GetLeftMargin(), GetRightMargin())))
1167 return true;
1168 }
1169
1170 // If there are columns, always create the fly, otherwise the columns would
1171 // restrict geometry of the table.
1172 if ( ColumnCount() + 1 >= 2 )
1173 return true;
1174
1175 return false;
1176 }
1177
InheritOrFinalizePageStyles(DomainMapper_Impl & rDM_Impl)1178 void SectionPropertyMap::InheritOrFinalizePageStyles( DomainMapper_Impl& rDM_Impl )
1179 {
1180 // if no new styles have been created for this section, inherit from the previous section,
1181 // otherwise apply this section's settings to the new style.
1182 // Ensure that FollowPage is inherited first - otherwise GetPageStyle may auto-create a follow when checking FirstPage.
1183 SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
1184 //tdf124637 TODO: identify and skip special sections (like footnotes/endnotes)
1185 if ( pLastContext && m_sFollowPageStyleName.isEmpty() )
1186 m_sFollowPageStyleName = pLastContext->GetPageStyleName();
1187 else
1188 {
1189 HandleMarginsHeaderFooter( /*bFirst=*/false, rDM_Impl );
1190 GetPageStyle( rDM_Impl, /*bFirst=*/false );
1191 if ( rDM_Impl.IsNewDoc() && m_aFollowPageStyle.is() )
1192 ApplyProperties_( m_aFollowPageStyle );
1193 }
1194
1195 // FirstPageStyle may only be inherited if it will not be used or re-linked to a different follow
1196 if ( !m_bTitlePage && pLastContext && m_sFirstPageStyleName.isEmpty() )
1197 m_sFirstPageStyleName = pLastContext->GetPageStyleName( /*bFirst=*/true );
1198 else
1199 {
1200 HandleMarginsHeaderFooter( /*bFirst=*/true, rDM_Impl );
1201 GetPageStyle( rDM_Impl, /*bFirst=*/true );
1202 if ( rDM_Impl.IsNewDoc() && m_aFirstPageStyle.is() )
1203 ApplyProperties_( m_aFirstPageStyle );
1204
1205 // Chain m_aFollowPageStyle to be after m_aFirstPageStyle
1206 m_aFirstPageStyle->setPropertyValue( "FollowStyle", uno::makeAny( m_sFollowPageStyleName ) );
1207 }
1208 }
1209
HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl & rDM_Impl)1210 void SectionPropertyMap::HandleIncreasedAnchoredObjectSpacing(DomainMapper_Impl& rDM_Impl)
1211 {
1212 // Ignore Word 2010 and older.
1213 if (rDM_Impl.GetSettingsTable()->GetWordCompatibilityMode() < 15)
1214 return;
1215
1216 sal_Int32 nPageWidth = GetPageWidth();
1217 sal_Int32 nTextAreaWidth = nPageWidth - GetLeftMargin() - GetRightMargin();
1218
1219 std::vector<AnchoredObjectsInfo>& rAnchoredObjectAnchors = rDM_Impl.m_aAnchoredObjectAnchors;
1220 for (const auto& rAnchor : rAnchoredObjectAnchors)
1221 {
1222 // Ignore this paragraph when there are not enough shapes to trigger the Word bug we
1223 // emulate.
1224 if (rAnchor.m_aAnchoredObjects.size() < 4)
1225 continue;
1226
1227 // Ignore this paragraph if none of the objects are wrapped in the background.
1228 sal_Int32 nOpaqueCount = 0;
1229 for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
1230 {
1231 uno::Reference<beans::XPropertySet> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
1232 if (!xShape.is())
1233 {
1234 continue;
1235 }
1236
1237 bool bOpaque = true;
1238 xShape->getPropertyValue("Opaque") >>= bOpaque;
1239 if (!bOpaque)
1240 {
1241 ++nOpaqueCount;
1242 }
1243 }
1244 if (nOpaqueCount < 1)
1245 {
1246 continue;
1247 }
1248
1249 // Analyze the anchored objects of this paragraph, now that we know the
1250 // page width.
1251 sal_Int32 nShapesWidth = 0;
1252 for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
1253 {
1254 uno::Reference<drawing::XShape> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
1255 if (!xShape.is())
1256 continue;
1257
1258 uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
1259 if (!xPropertySet.is())
1260 continue;
1261
1262 // Ignore objects with no wrapping.
1263 text::WrapTextMode eWrap = text::WrapTextMode_THROUGH;
1264 xPropertySet->getPropertyValue("Surround") >>= eWrap;
1265 if (eWrap == text::WrapTextMode_THROUGH)
1266 continue;
1267
1268 // Use the original left margin, in case GraphicImport::lcl_sprm() reduced the doc model
1269 // one to 0.
1270 sal_Int32 nLeftMargin = rAnchored.m_nLeftMargin;
1271 sal_Int32 nRightMargin = 0;
1272 xPropertySet->getPropertyValue("RightMargin") >>= nRightMargin;
1273 nShapesWidth += xShape->getSize().Width + nLeftMargin + nRightMargin;
1274 }
1275
1276 // Ignore cases when we have enough horizontal space for the shapes.
1277 if (nTextAreaWidth > nShapesWidth)
1278 continue;
1279
1280 sal_Int32 nHeight = 0;
1281 for (const auto& rAnchored : rAnchor.m_aAnchoredObjects)
1282 {
1283 uno::Reference<drawing::XShape> xShape(rAnchored.m_xAnchoredObject, uno::UNO_QUERY);
1284 if (!xShape.is())
1285 continue;
1286
1287 nHeight += xShape->getSize().Height;
1288 }
1289
1290 uno::Reference<beans::XPropertySet> xParagraph(rAnchor.m_xParagraph, uno::UNO_QUERY);
1291 if (xParagraph.is())
1292 {
1293 sal_Int32 nTopMargin = 0;
1294 xParagraph->getPropertyValue("ParaTopMargin") >>= nTopMargin;
1295 // Increase top spacing of the paragraph to match Word layout
1296 // behavior.
1297 nTopMargin = std::max(nTopMargin, nHeight);
1298 xParagraph->setPropertyValue("ParaTopMargin", uno::makeAny(nTopMargin));
1299 }
1300 }
1301 rAnchoredObjectAnchors.clear();
1302 }
1303
CloseSectionGroup(DomainMapper_Impl & rDM_Impl)1304 void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
1305 {
1306 // The default section type is nextPage.
1307 if ( m_nBreakType == -1 )
1308 m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
1309 // if page orientation differs from previous section, it can't be treated as continuous
1310 else if ( m_nBreakType == NS_ooxml::LN_Value_ST_SectionMark_continuous )
1311 {
1312 SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
1313 if ( pLastContext )
1314 {
1315 bool bIsLandscape = false;
1316 boost::optional< PropertyMap::Property > pProp = getProperty( PROP_IS_LANDSCAPE );
1317 if ( pProp )
1318 pProp->second >>= bIsLandscape;
1319
1320 bool bPrevIsLandscape = false;
1321 pProp = pLastContext->getProperty( PROP_IS_LANDSCAPE );
1322 if ( pProp )
1323 pProp->second >>= bPrevIsLandscape;
1324
1325 if ( bIsLandscape != bPrevIsLandscape )
1326 m_nBreakType = NS_ooxml::LN_Value_ST_SectionMark_nextPage;
1327 }
1328 }
1329
1330 // Text area width is known at the end of a section: decide if tables should be converted or not.
1331 std::vector<FloatingTableInfo>& rPendingFloatingTables = rDM_Impl.m_aPendingFloatingTables;
1332 uno::Reference<text::XTextAppendAndConvert> xBodyText( rDM_Impl.GetBodyText(), uno::UNO_QUERY );
1333 for ( FloatingTableInfo & rInfo : rPendingFloatingTables )
1334 {
1335 rInfo.m_nBreakType = m_nBreakType;
1336 if ( FloatingTableConversion( rDM_Impl, rInfo ) )
1337 {
1338 try
1339 {
1340 xBodyText->convertToTextFrame(rInfo.m_xStart, rInfo.m_xEnd,
1341 rInfo.m_aFrameProperties);
1342 }
1343 catch (const uno::Exception&)
1344 {
1345 DBG_UNHANDLED_EXCEPTION("writerfilter", "convertToTextFrame() failed");
1346 }
1347 }
1348 }
1349 rPendingFloatingTables.clear();
1350
1351 try
1352 {
1353 HandleIncreasedAnchoredObjectSpacing(rDM_Impl);
1354 }
1355 catch (const uno::Exception&)
1356 {
1357 DBG_UNHANDLED_EXCEPTION("writerfilter", "HandleIncreasedAnchoredObjectSpacing() failed");
1358 }
1359
1360 if ( m_nLnnMod )
1361 {
1362 bool bFirst = rDM_Impl.IsLineNumberingSet();
1363 rDM_Impl.SetLineNumbering( m_nLnnMod, m_nLnc, m_ndxaLnn );
1364 if ( m_nLnnMin > 0 || (bFirst && m_nLnc == NS_ooxml::LN_Value_ST_LineNumberRestart_newSection) )
1365 {
1366 //set the starting value at the beginning of the section
1367 try
1368 {
1369 uno::Reference< beans::XPropertySet > xRangeProperties;
1370 if ( m_xStartingRange.is() )
1371 {
1372 xRangeProperties.set( m_xStartingRange, uno::UNO_QUERY_THROW );
1373 }
1374 else
1375 {
1376 //set the start value at the beginning of the document
1377 xRangeProperties.set( rDM_Impl.GetTextDocument()->getText()->getStart(), uno::UNO_QUERY_THROW );
1378 }
1379 // Writer is 1-based, Word is 0-based.
1380 xRangeProperties->setPropertyValue(
1381 getPropertyName(PROP_PARA_LINE_NUMBER_START_VALUE),
1382 uno::makeAny(m_nLnnMin + 1));
1383 }
1384 catch ( const uno::Exception& )
1385 {
1386 DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup");
1387 }
1388 }
1389 }
1390
1391 if (m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_continuous)
1392 && !rDM_Impl.IsInComments())
1393 {
1394 //todo: insert a section or access the already inserted section
1395 uno::Reference< beans::XPropertySet > xSection =
1396 rDM_Impl.appendTextSectionAfter( m_xStartingRange );
1397 if ( xSection.is() )
1398 {
1399 if ( m_nColumnCount > 0 )
1400 ApplyColumnProperties( xSection, rDM_Impl );
1401
1402 ApplyProtectionProperties( xSection, rDM_Impl );
1403 }
1404
1405 try
1406 {
1407 InheritOrFinalizePageStyles( rDM_Impl );
1408 ApplySectionProperties( xSection, rDM_Impl ); //depends on InheritOrFinalizePageStyles
1409 OUString aName = m_bTitlePage ? m_sFirstPageStyleName : m_sFollowPageStyleName;
1410 uno::Reference< beans::XPropertySet > xRangeProperties( lcl_GetRangeProperties( m_bIsFirstSection, rDM_Impl, m_xStartingRange ) );
1411 if ( m_bIsFirstSection && !aName.isEmpty() && xRangeProperties.is() )
1412 {
1413 xRangeProperties->setPropertyValue( getPropertyName( PROP_PAGE_DESC_NAME ), uno::makeAny( aName ) );
1414 }
1415 else if ((!m_bFirstPageHeaderLinkToPrevious ||
1416 !m_bFirstPageFooterLinkToPrevious ||
1417 !m_bDefaultHeaderLinkToPrevious ||
1418 !m_bDefaultFooterLinkToPrevious ||
1419 !m_bEvenPageHeaderLinkToPrevious ||
1420 !m_bEvenPageFooterLinkToPrevious)
1421 && rDM_Impl.GetCurrentXText())
1422 { // find a node in the section that has a page break and change
1423 // it to apply the page style; see "nightmare scenario" in
1424 // wwSectionManager::InsertSegments()
1425 auto xTextAppend = rDM_Impl.GetCurrentXText();
1426 uno::Reference<container::XEnumerationAccess> const xCursor(
1427 xTextAppend->createTextCursorByRange(
1428 uno::Reference<text::XTextContent>(xSection, uno::UNO_QUERY_THROW)->getAnchor()),
1429 uno::UNO_QUERY_THROW);
1430 uno::Reference<container::XEnumeration> const xEnum(
1431 xCursor->createEnumeration());
1432 bool isFound = false;
1433 while (xEnum->hasMoreElements())
1434 {
1435 uno::Reference<beans::XPropertySet> xElem;
1436 xEnum->nextElement() >>= xElem;
1437 if (xElem->getPropertySetInfo()->hasPropertyByName("BreakType"))
1438 {
1439 style::BreakType bt;
1440 if ((xElem->getPropertyValue("BreakType") >>= bt)
1441 && bt == style::BreakType_PAGE_BEFORE)
1442 {
1443 // tdf#112201: do *not* use m_sFirstPageStyleName here!
1444 xElem->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME),
1445 uno::makeAny(m_sFollowPageStyleName));
1446 isFound = true;
1447 break;
1448 }
1449 }
1450 }
1451 if (!isFound)
1452 { // HACK: try the last paragraph of the previous section
1453 uno::Reference<text::XParagraphCursor> const xPCursor(xCursor, uno::UNO_QUERY_THROW);
1454 xPCursor->gotoPreviousParagraph(false);
1455 uno::Reference<beans::XPropertySet> const xPSCursor(xCursor, uno::UNO_QUERY_THROW);
1456 style::BreakType bt;
1457 if ((xPSCursor->getPropertyValue("BreakType") >>= bt)
1458 && bt == style::BreakType_PAGE_BEFORE)
1459 {
1460 xPSCursor->setPropertyValue(getPropertyName(PROP_PAGE_DESC_NAME),
1461 uno::makeAny(m_sFollowPageStyleName));
1462 }
1463 }
1464 }
1465 }
1466 catch ( const uno::Exception& )
1467 {
1468 SAL_WARN( "writerfilter", "failed to set PageDescName!" );
1469 }
1470 }
1471 // If the section is of type "New column" (0x01), then simply insert a column break.
1472 // But only if there actually are columns on the page, otherwise a column break
1473 // seems to be handled like a page break by MSO.
1474 else if (m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_nextColumn)
1475 && 0 < m_nColumnCount && !rDM_Impl.IsInComments())
1476 {
1477 try
1478 {
1479 InheritOrFinalizePageStyles( rDM_Impl );
1480 uno::Reference< beans::XPropertySet > xRangeProperties;
1481 if ( m_xStartingRange.is() )
1482 {
1483 xRangeProperties.set( m_xStartingRange, uno::UNO_QUERY_THROW );
1484 }
1485 else
1486 {
1487 //set the start value at the beginning of the document
1488 xRangeProperties.set( rDM_Impl.GetTextDocument()->getText()->getStart(), uno::UNO_QUERY_THROW );
1489 }
1490 xRangeProperties->setPropertyValue( getPropertyName( PROP_BREAK_TYPE ), uno::makeAny( style::BreakType_COLUMN_BEFORE ) );
1491 }
1492 catch ( const uno::Exception& ) {}
1493 }
1494 else if (!rDM_Impl.IsInComments())
1495 {
1496 uno::Reference< beans::XPropertySet > xSection;
1497 ApplyProtectionProperties( xSection, rDM_Impl );
1498
1499 //get the properties and create appropriate page styles
1500 uno::Reference< beans::XPropertySet > xFollowPageStyle = GetPageStyle( rDM_Impl, false );
1501
1502 HandleMarginsHeaderFooter(/*bFirstPage=*/false, rDM_Impl );
1503
1504 if ( rDM_Impl.GetSettingsTable()->GetMirrorMarginSettings() )
1505 {
1506 Insert( PROP_PAGE_STYLE_LAYOUT, uno::makeAny( style::PageStyleLayout_MIRRORED ) );
1507 }
1508 uno::Reference< text::XTextColumns > xColumns;
1509 if ( m_nColumnCount > 0 )
1510 {
1511 // prefer setting column properties into a section, not a page style if at all possible.
1512 if ( !xSection.is() )
1513 xSection = rDM_Impl.appendTextSectionAfter( m_xStartingRange );
1514 if ( xSection.is() )
1515 ApplyColumnProperties( xSection, rDM_Impl );
1516 else
1517 xColumns = ApplyColumnProperties( xFollowPageStyle, rDM_Impl );
1518 }
1519
1520 // these BreakTypes are effectively page-breaks: don't evenly distribute text in columns before a page break;
1521 SectionPropertyMap* pLastContext = rDM_Impl.GetLastSectionContext();
1522 if ( pLastContext && pLastContext->ColumnCount() )
1523 pLastContext->DontBalanceTextColumns();
1524
1525 //prepare text grid properties
1526 sal_Int32 nHeight = 1;
1527 boost::optional< PropertyMap::Property > pProp = getProperty( PROP_HEIGHT );
1528 if ( pProp )
1529 pProp->second >>= nHeight;
1530
1531 sal_Int32 nWidth = 1;
1532 pProp = getProperty( PROP_WIDTH );
1533 if ( pProp )
1534 pProp->second >>= nWidth;
1535
1536 text::WritingMode eWritingMode = text::WritingMode_LR_TB;
1537 pProp = getProperty( PROP_WRITING_MODE );
1538 if ( pProp )
1539 pProp->second >>= eWritingMode;
1540
1541 sal_Int32 nTextAreaHeight = eWritingMode == text::WritingMode_LR_TB ?
1542 nHeight - m_nTopMargin - m_nBottomMargin :
1543 nWidth - m_nLeftMargin - m_nRightMargin;
1544
1545 sal_Int32 nGridLinePitch = m_nGridLinePitch;
1546 //sep.dyaLinePitch
1547 if ( nGridLinePitch < 1 || nGridLinePitch > 31680 )
1548 {
1549 SAL_WARN( "writerfilter", "sep.dyaLinePitch outside legal range: " << nGridLinePitch );
1550 nGridLinePitch = 1;
1551 }
1552
1553 const sal_Int32 nGridLines = nTextAreaHeight / nGridLinePitch;
1554 if ( nGridLines >= 0 && nGridLines <= SAL_MAX_INT16 )
1555 Insert( PROP_GRID_LINES, uno::makeAny( sal_Int16(nGridLines) ) );
1556
1557 // PROP_GRID_MODE
1558 Insert( PROP_GRID_MODE, uno::makeAny( static_cast<sal_Int16> (m_nGridType) ) );
1559 if ( m_nGridType == text::TextGridMode::LINES_AND_CHARS )
1560 {
1561 Insert( PROP_GRID_SNAP_TO_CHARS, uno::makeAny( m_bGridSnapToChars ) );
1562 }
1563
1564 sal_Int32 nCharWidth = 423; //240 twip/ 12 pt
1565 const StyleSheetEntryPtr pEntry = rDM_Impl.GetStyleSheetTable()->FindStyleSheetByConvertedStyleName( "Standard" );
1566 if ( pEntry.get() )
1567 {
1568 boost::optional< PropertyMap::Property > pPropHeight = pEntry->pProperties->getProperty( PROP_CHAR_HEIGHT_ASIAN );
1569 if ( pPropHeight )
1570 {
1571 double fHeight = 0;
1572 if ( pPropHeight->second >>= fHeight )
1573 nCharWidth = ConversionHelper::convertTwipToMM100( static_cast<long>(fHeight * 20.0 + 0.5) );
1574 }
1575 }
1576
1577 //dxtCharSpace
1578 if ( m_nDxtCharSpace )
1579 {
1580 sal_Int32 nCharSpace = m_nDxtCharSpace;
1581 //main lives in top 20 bits, and is signed.
1582 sal_Int32 nMain = (nCharSpace & 0xFFFFF000);
1583 nMain /= 0x1000;
1584 nCharWidth += ConversionHelper::convertTwipToMM100( nMain * 20 );
1585
1586 sal_Int32 nFraction = (nCharSpace & 0x00000FFF);
1587 nFraction = (nFraction * 20) / 0xFFF;
1588 nCharWidth += ConversionHelper::convertTwipToMM100( nFraction );
1589 }
1590
1591 if ( m_nPageNumberType >= 0 )
1592 Insert( PROP_NUMBERING_TYPE, uno::makeAny( m_nPageNumberType ) );
1593
1594 // #i119558#, force to set document as standard page mode,
1595 // refer to ww8 import process function "SwWW8ImplReader::SetDocumentGrid"
1596 try
1597 {
1598 uno::Reference< beans::XPropertySet > xDocProperties;
1599 xDocProperties.set( rDM_Impl.GetTextDocument(), uno::UNO_QUERY_THROW );
1600 Insert(PROP_GRID_STANDARD_MODE, uno::makeAny(true));
1601 xDocProperties->setPropertyValue("DefaultPageMode", uno::makeAny(false));
1602 }
1603 catch ( const uno::Exception& )
1604 {
1605 DBG_UNHANDLED_EXCEPTION("writerfilter.dmapper", "Exception in SectionPropertyMap::CloseSectionGroup");
1606 }
1607
1608 Insert( PROP_GRID_BASE_HEIGHT, uno::makeAny( nGridLinePitch ) );
1609 Insert( PROP_GRID_BASE_WIDTH, uno::makeAny( nCharWidth ) );
1610 Insert( PROP_GRID_RUBY_HEIGHT, uno::makeAny( sal_Int32( 0 ) ) );
1611
1612 if ( rDM_Impl.IsNewDoc() )
1613 ApplyProperties_( xFollowPageStyle );
1614
1615 //todo: creating a "First Page" style depends on HasTitlePage and _fFacingPage_
1616 if ( m_bTitlePage )
1617 {
1618 CopyLastHeaderFooter( true, rDM_Impl );
1619 PrepareHeaderFooterProperties( true );
1620 uno::Reference< beans::XPropertySet > xFirstPageStyle = GetPageStyle(
1621 rDM_Impl, true );
1622 if ( rDM_Impl.IsNewDoc() )
1623 ApplyProperties_( xFirstPageStyle );
1624
1625 if ( xColumns.is() )
1626 xFirstPageStyle->setPropertyValue(
1627 getPropertyName( PROP_TEXT_COLUMNS ), uno::makeAny( xColumns ) );
1628 }
1629
1630 ApplyBorderToPageStyles( rDM_Impl, m_eBorderApply, m_eBorderOffsetFrom );
1631
1632 try
1633 {
1634 //now apply this break at the first paragraph of this section
1635 uno::Reference< beans::XPropertySet > xRangeProperties( lcl_GetRangeProperties( m_bIsFirstSection, rDM_Impl, m_xStartingRange ) );
1636
1637 // Handle page breaks with odd/even page numbering. We need to use an extra page style for setting the page style
1638 // to left/right, because if we set it to the normal style, we'd set it to "First Page"/"Default Style", which would
1639 // break them (all default pages would be only left or right).
1640 if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_evenPage) || m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_oddPage) )
1641 {
1642 OUString* pageStyle = m_bTitlePage ? &m_sFirstPageStyleName : &m_sFollowPageStyleName;
1643 OUString evenOddStyleName = rDM_Impl.GetUnusedPageStyleName();
1644 uno::Reference< beans::XPropertySet > evenOddStyle(
1645 rDM_Impl.GetTextFactory()->createInstance( "com.sun.star.style.PageStyle" ),
1646 uno::UNO_QUERY );
1647 // Unfortunately using setParent() does not work for page styles, so make a deep copy of the page style.
1648 uno::Reference< beans::XPropertySet > pageProperties( m_bTitlePage ? m_aFirstPageStyle : m_aFollowPageStyle );
1649 uno::Reference< beans::XPropertySetInfo > pagePropertiesInfo( pageProperties->getPropertySetInfo() );
1650 const uno::Sequence< beans::Property > propertyList( pagePropertiesInfo->getProperties() );
1651 // Ignore write-only properties.
1652 static const o3tl::sorted_vector<OUString> aBlacklist
1653 = { "FooterBackGraphicURL", "BackGraphicURL", "HeaderBackGraphicURL" };
1654 for ( const auto& rProperty : propertyList )
1655 {
1656 if ( (rProperty.Attributes & beans::PropertyAttribute::READONLY) == 0 )
1657 {
1658 if (aBlacklist.find(rProperty.Name) == aBlacklist.end())
1659 evenOddStyle->setPropertyValue(
1660 rProperty.Name,
1661 pageProperties->getPropertyValue(rProperty.Name));
1662 }
1663 }
1664 evenOddStyle->setPropertyValue( "FollowStyle", uno::makeAny( *pageStyle ) );
1665 rDM_Impl.GetPageStyles()->insertByName( evenOddStyleName, uno::makeAny( evenOddStyle ) );
1666 evenOddStyle->setPropertyValue( "HeaderIsOn", uno::makeAny( false ) );
1667 evenOddStyle->setPropertyValue( "FooterIsOn", uno::makeAny( false ) );
1668 CopyHeaderFooter( pageProperties, evenOddStyle );
1669 *pageStyle = evenOddStyleName; // And use it instead of the original one (which is set as follow of this one).
1670 if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_evenPage) )
1671 evenOddStyle->setPropertyValue( getPropertyName( PROP_PAGE_STYLE_LAYOUT ), uno::makeAny( style::PageStyleLayout_LEFT ) );
1672 else if ( m_nBreakType == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_SectionMark_oddPage) )
1673 evenOddStyle->setPropertyValue( getPropertyName( PROP_PAGE_STYLE_LAYOUT ), uno::makeAny( style::PageStyleLayout_RIGHT ) );
1674 }
1675
1676 if ( xRangeProperties.is() && rDM_Impl.IsNewDoc() )
1677 {
1678 // Avoid setting page style in case of autotext: so inserting the autotext at the
1679 // end of the document does not introduce an unwanted page break.
1680 if (!rDM_Impl.IsReadGlossaries() && !rDM_Impl.IsInFootOrEndnote())
1681 {
1682 xRangeProperties->setPropertyValue(
1683 getPropertyName( PROP_PAGE_DESC_NAME ),
1684 uno::makeAny( m_bTitlePage ? m_sFirstPageStyleName
1685 : m_sFollowPageStyleName ) );
1686 }
1687
1688 if (0 <= m_nPageNumber)
1689 {
1690 sal_Int16 nPageNumber = static_cast< sal_Int16 >(m_nPageNumber);
1691 xRangeProperties->setPropertyValue(getPropertyName(PROP_PAGE_NUMBER_OFFSET),
1692 uno::makeAny(nPageNumber));
1693 }
1694 }
1695 }
1696 catch ( const uno::Exception& )
1697 {
1698 OSL_FAIL( "Exception in SectionPropertyMap::CloseSectionGroup" );
1699 }
1700 }
1701
1702 // Now that the margins are known, resize relative width shapes because some shapes in LO do not support percentage-sizes
1703 sal_Int32 nParagraphWidth = GetPageWidth() - m_nLeftMargin - m_nRightMargin;
1704 if ( m_nColumnCount > 0 )
1705 {
1706 // skip custom-width columns since we don't know what column the shape is in.
1707 if ( !m_aColWidth.empty() )
1708 nParagraphWidth = 0;
1709 else
1710 nParagraphWidth = (nParagraphWidth - (m_nColumnDistance * m_nColumnCount)) / (m_nColumnCount + 1);
1711 }
1712 if ( nParagraphWidth > 0 )
1713 {
1714 const OUString sPropRelativeWidth = getPropertyName(PROP_RELATIVE_WIDTH);
1715 for ( const auto& xShape : m_xRelativeWidthShapes )
1716 {
1717 const uno::Reference<beans::XPropertySet> xShapePropertySet( xShape, uno::UNO_QUERY );
1718 if ( xShapePropertySet->getPropertySetInfo()->hasPropertyByName(sPropRelativeWidth) )
1719 {
1720 sal_uInt16 nPercent = 0;
1721 try
1722 {
1723 xShapePropertySet->getPropertyValue(sPropRelativeWidth) >>= nPercent;
1724 }
1725 catch (const css::uno::RuntimeException& e)
1726 {
1727 // May happen e.g. when text frame has no frame format
1728 // See sw/qa/extras/ooxmlimport/data/n779627.docx
1729 SAL_WARN("writerfilter", "Getting relative width failed. " << e.Message);
1730 }
1731 if ( nPercent )
1732 {
1733 const sal_Int32 nWidth = nParagraphWidth * nPercent / 100;
1734 xShape->setSize( awt::Size( nWidth, xShape->getSize().Height ) );
1735 }
1736 }
1737 }
1738 }
1739 m_xRelativeWidthShapes.clear();
1740
1741 rDM_Impl.SetIsLastSectionGroup( false );
1742 rDM_Impl.SetIsFirstParagraphInSection( true );
1743
1744 if ( !rDM_Impl.IsInFootOrEndnote() )
1745 {
1746 rDM_Impl.m_bHasFtn = false;
1747 rDM_Impl.m_bHasFtnSep = false;
1748 }
1749 }
1750
1751 // Clear the flag that says we should take the header/footer content from
1752 // the previous section. This should be called when we encounter a header
1753 // or footer definition for this section.
ClearHeaderFooterLinkToPrevious(bool bHeader,PageType eType)1754 void SectionPropertyMap::ClearHeaderFooterLinkToPrevious( bool bHeader, PageType eType )
1755 {
1756 if ( bHeader )
1757 {
1758 switch ( eType )
1759 {
1760 case PAGE_FIRST: m_bFirstPageHeaderLinkToPrevious = false; break;
1761 case PAGE_LEFT: m_bEvenPageHeaderLinkToPrevious = false; break;
1762 case PAGE_RIGHT: m_bDefaultHeaderLinkToPrevious = false; break;
1763 // no default case as all enumeration values have been covered
1764 }
1765 }
1766 else
1767 {
1768 switch ( eType )
1769 {
1770 case PAGE_FIRST: m_bFirstPageFooterLinkToPrevious = false; break;
1771 case PAGE_LEFT: m_bEvenPageFooterLinkToPrevious = false; break;
1772 case PAGE_RIGHT: m_bDefaultFooterLinkToPrevious = false; break;
1773 }
1774 }
1775 }
1776
1777 class NamedPropertyValue
1778 {
1779 private:
1780 OUString const m_aName;
1781
1782 public:
NamedPropertyValue(const OUString & i_aStr)1783 explicit NamedPropertyValue( const OUString& i_aStr )
1784 : m_aName( i_aStr )
1785 {
1786 }
1787
operator ()(beans::PropertyValue const & aVal)1788 bool operator() ( beans::PropertyValue const & aVal )
1789 {
1790 return aVal.Name == m_aName;
1791 }
1792 };
1793
ApplyProperties_(const uno::Reference<beans::XPropertySet> & xStyle)1794 void SectionPropertyMap::ApplyProperties_( const uno::Reference< beans::XPropertySet >& xStyle )
1795 {
1796 uno::Reference< beans::XMultiPropertySet > const xMultiSet( xStyle, uno::UNO_QUERY );
1797
1798 std::vector< OUString > vNames;
1799 std::vector< uno::Any > vValues;
1800 {
1801 // Convert GetPropertyValues() value into something useful
1802 uno::Sequence< beans::PropertyValue > vPropVals = GetPropertyValues();
1803
1804 //Temporarily store the items that are in grab bags
1805 uno::Sequence< beans::PropertyValue > vCharVals;
1806 uno::Sequence< beans::PropertyValue > vParaVals;
1807 beans::PropertyValue* pCharGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "CharInteropGrabBag" ) );
1808 if ( pCharGrabBag != vPropVals.end() )
1809 (pCharGrabBag->Value) >>= vCharVals;
1810 beans::PropertyValue* pParaGrabBag = std::find_if( vPropVals.begin(), vPropVals.end(), NamedPropertyValue( "ParaInteropGrabBag" ) );
1811 if ( pParaGrabBag != vPropVals.end() )
1812 (pParaGrabBag->Value) >>= vParaVals;
1813
1814 for ( beans::PropertyValue* pIter = vPropVals.begin(); pIter != vPropVals.end(); ++pIter )
1815 {
1816 if ( pIter != pCharGrabBag && pIter != pParaGrabBag
1817 && pIter->Name != "IsProtected" //section-only property
1818 )
1819 {
1820 vNames.push_back( pIter->Name );
1821 vValues.push_back( pIter->Value );
1822 }
1823 }
1824 for ( const beans::PropertyValue & v : std::as_const(vCharVals) )
1825 {
1826 vNames.push_back( v.Name );
1827 vValues.push_back( v.Value );
1828 }
1829 for ( const beans::PropertyValue & v : std::as_const(vParaVals) )
1830 {
1831 vNames.push_back( v.Name );
1832 vValues.push_back( v.Value );
1833 }
1834 }
1835 if ( xMultiSet.is() )
1836 {
1837 try
1838 {
1839 xMultiSet->setPropertyValues( comphelper::containerToSequence( vNames ), comphelper::containerToSequence( vValues ) );
1840 return;
1841 }
1842 catch ( const uno::Exception& )
1843 {
1844 OSL_FAIL( "Exception in SectionPropertyMap::ApplyProperties_" );
1845 }
1846 }
1847 for ( size_t i = 0; i < vNames.size(); ++i )
1848 {
1849 try
1850 {
1851 if ( xStyle.is() )
1852 xStyle->setPropertyValue( vNames[i], vValues[i] );
1853 }
1854 catch ( const uno::Exception& )
1855 {
1856 OSL_FAIL( "Exception in SectionPropertyMap::ApplyProperties_" );
1857 }
1858 }
1859 }
1860
GetPageWidth() const1861 sal_Int32 SectionPropertyMap::GetPageWidth() const
1862 {
1863 return getProperty( PROP_WIDTH )->second.get<sal_Int32>();
1864 }
1865
StyleSheetPropertyMap()1866 StyleSheetPropertyMap::StyleSheetPropertyMap()
1867 : mnListLevel( -1 )
1868 , mnOutlineLevel( -1 )
1869 , mnNumId( -1 )
1870 {
1871 }
1872
ParagraphProperties()1873 ParagraphProperties::ParagraphProperties()
1874 : m_bFrameMode( false )
1875 , m_nDropCap( NS_ooxml::LN_Value_doc_ST_DropCap_none )
1876 , m_nLines( 0 )
1877 , m_w( -1 )
1878 , m_h( -1 )
1879 , m_nWrap( text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE )
1880 , m_hAnchor( -1 )
1881 , m_vAnchor( -1 )
1882 , m_x( -1 )
1883 , m_bxValid( false )
1884 , m_y( -1 )
1885 , m_byValid( false )
1886 , m_hSpace( -1 )
1887 , m_vSpace( -1 )
1888 , m_hRule( -1 )
1889 , m_xAlign( -1 )
1890 , m_yAlign( -1 )
1891 , m_nDropCapLength( 0 )
1892 {
1893 }
1894
operator ==(const ParagraphProperties & rCompare)1895 bool ParagraphProperties::operator==( const ParagraphProperties& rCompare )
1896 {
1897 return ( m_bFrameMode == rCompare.m_bFrameMode &&
1898 m_nDropCap == rCompare.m_nDropCap &&
1899 m_nLines == rCompare.m_nLines &&
1900 m_w == rCompare.m_w &&
1901 m_h == rCompare.m_h &&
1902 m_nWrap == rCompare.m_nWrap &&
1903 m_hAnchor == rCompare.m_hAnchor &&
1904 m_vAnchor == rCompare.m_vAnchor &&
1905 m_x == rCompare.m_x &&
1906 m_bxValid == rCompare.m_bxValid &&
1907 m_y == rCompare.m_y &&
1908 m_byValid == rCompare.m_byValid &&
1909 m_hSpace == rCompare.m_hSpace &&
1910 m_vSpace == rCompare.m_vSpace &&
1911 m_hRule == rCompare.m_hRule &&
1912 m_xAlign == rCompare.m_xAlign &&
1913 m_yAlign == rCompare.m_yAlign );
1914 }
1915
ResetFrameProperties()1916 void ParagraphProperties::ResetFrameProperties()
1917 {
1918 m_bFrameMode = false;
1919 m_nDropCap = NS_ooxml::LN_Value_doc_ST_DropCap_none;
1920 m_nLines = 0;
1921 m_w = -1;
1922 m_h = -1;
1923 m_nWrap = text::WrapTextMode::WrapTextMode_MAKE_FIXED_SIZE;
1924 m_hAnchor = -1;
1925 m_vAnchor = -1;
1926 m_x = -1;
1927 m_bxValid = false;
1928 m_y = -1;
1929 m_byValid = false;
1930 m_hSpace = -1;
1931 m_vSpace = -1;
1932 m_hRule = -1;
1933 m_xAlign = -1;
1934 m_yAlign = -1;
1935 m_nDropCapLength = 0;
1936 }
1937
getValue(TablePropertyMapTarget eWhich,sal_Int32 & nFill)1938 bool TablePropertyMap::getValue( TablePropertyMapTarget eWhich, sal_Int32& nFill )
1939 {
1940 if ( eWhich < TablePropertyMapTarget_MAX )
1941 {
1942 if ( m_aValidValues[eWhich].bValid )
1943 nFill = m_aValidValues[eWhich].nValue;
1944 return m_aValidValues[eWhich].bValid;
1945 }
1946 else
1947 {
1948 OSL_FAIL( "invalid TablePropertyMapTarget" );
1949 return false;
1950 }
1951 }
1952
setValue(TablePropertyMapTarget eWhich,sal_Int32 nSet)1953 void TablePropertyMap::setValue( TablePropertyMapTarget eWhich, sal_Int32 nSet )
1954 {
1955 if ( eWhich < TablePropertyMapTarget_MAX )
1956 {
1957 m_aValidValues[eWhich].bValid = true;
1958 m_aValidValues[eWhich].nValue = nSet;
1959 }
1960 else
1961 OSL_FAIL( "invalid TablePropertyMapTarget" );
1962 }
1963
insertTableProperties(const PropertyMap * pMap,const bool bOverwrite)1964 void TablePropertyMap::insertTableProperties( const PropertyMap* pMap, const bool bOverwrite )
1965 {
1966 #ifdef DBG_UTIL
1967 TagLogger::getInstance().startElement( "TablePropertyMap.insertTableProperties" );
1968 pMap->dumpXml();
1969 #endif
1970
1971 const TablePropertyMap* pSource = dynamic_cast< const TablePropertyMap* >(pMap);
1972 if ( pSource )
1973 {
1974 for ( sal_Int32 eTarget = TablePropertyMapTarget_START;
1975 eTarget < TablePropertyMapTarget_MAX; ++eTarget )
1976 {
1977 if ( pSource->m_aValidValues[eTarget].bValid && (bOverwrite || !m_aValidValues[eTarget].bValid) )
1978 {
1979 m_aValidValues[eTarget].bValid = true;
1980 m_aValidValues[eTarget].nValue = pSource->m_aValidValues[eTarget].nValue;
1981 }
1982 }
1983 }
1984
1985 #ifdef DBG_UTIL
1986 dumpXml();
1987 TagLogger::getInstance().endElement();
1988 #endif
1989 }
1990
1991 } // namespace dmapper
1992 } // namespace writerfilter
1993
1994 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1995