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 <com/sun/star/beans/PropertyValue.hpp>
21 #include <com/sun/star/beans/XPropertySet.hpp>
22 #include <com/sun/star/awt/Size.hpp>
23 #include <com/sun/star/frame/XModel.hpp>
24 #include <com/sun/star/graphic/XGraphic.hpp>
25 #include <com/sun/star/awt/FontDescriptor.hpp>
26 #include <com/sun/star/text/HoriOrientation.hpp>
27 #include <com/sun/star/text/VertOrientation.hpp>
28 #include <com/sun/star/text/PositionAndSpaceMode.hpp>
29 #include <com/sun/star/text/LabelFollow.hpp>
30 #include <com/sun/star/container/XNameContainer.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/style/XStyle.hpp>
33 #include <com/sun/star/io/XOutputStream.hpp>
34 #include <com/sun/star/awt/XBitmap.hpp>
35 #include <com/sun/star/style/NumberingType.hpp>
36 #include <com/sun/star/container/XIndexReplace.hpp>
37 
38 #include <o3tl/any.hxx>
39 #include <o3tl/temporary.hxx>
40 #include <rtl/ustrbuf.hxx>
41 #include <sal/log.hxx>
42 #include <tools/diagnose_ex.h>
43 #include <comphelper/sequence.hxx>
44 #include <comphelper/propertyvalue.hxx>
45 
46 #include <tools/fontenum.hxx>
47 #include <tools/color.hxx>
48 
49 #include <sax/tools/converter.hxx>
50 
51 #include <vcl/vclenum.hxx>
52 
53 #include <xmloff/xmltkmap.hxx>
54 #include <xmloff/namespacemap.hxx>
55 #include <xmloff/xmlnamespace.hxx>
56 #include <xmloff/xmlimp.hxx>
57 #include <xmloff/XMLBase64ImportContext.hxx>
58 #include <xmloff/xmltoken.hxx>
59 
60 #include <xmloff/xmluconv.hxx>
61 #include "fonthdl.hxx"
62 #include <xmloff/XMLFontStylesContext.hxx>
63 #include <xmloff/families.hxx>
64 #include <xmloff/maptype.hxx>
65 
66 #include <xmloff/xmlnumi.hxx>
67 #include <optional>
68 
69 using namespace ::com::sun::star;
70 using namespace ::com::sun::star::uno;
71 using namespace ::com::sun::star::style;
72 using namespace ::com::sun::star::text;
73 using namespace ::com::sun::star::beans;
74 using namespace ::com::sun::star::container;
75 using namespace ::com::sun::star::lang;
76 using namespace ::com::sun::star::frame;
77 using namespace ::xmloff::token;
78 using namespace ::com::sun::star::io;
79 
80 class SvxXMLListLevelStyleContext_Impl;
81 
82 namespace {
83 
84 class SvxXMLListLevelStyleAttrContext_Impl : public SvXMLImportContext
85 {
86     SvxXMLListLevelStyleContext_Impl&   rListLevel;
87 
88 public:
89 
90     SvxXMLListLevelStyleAttrContext_Impl(
91             SvXMLImport& rImport, sal_Int32 nElement,
92             const Reference< xml::sax::XFastAttributeList >& xAttrList,
93             SvxXMLListLevelStyleContext_Impl& rLLevel   );
94 
95     virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
96         sal_Int32 nElement,
97         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
98 };
99 
100 class SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl : public SvXMLImportContext
101 {
102 public:
103 
104     SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl(
105             SvXMLImport& rImport, sal_Int32 nElement,
106             const Reference< xml::sax::XFastAttributeList >& xAttrList,
107             SvxXMLListLevelStyleContext_Impl& rLLevel   );
108 };
109 
110 }
111 
112 class SvxXMLListLevelStyleContext_Impl : public SvXMLImportContext
113 {
114     friend SvxXMLListLevelStyleAttrContext_Impl;
115 
116     OUString            sPrefix;
117     OUString            sSuffix;
118     std::optional<OUString> sListFormat;    // It is optional to distinguish empty format string
119                                             // from not existing format string in old docs
120     OUString            sTextStyleName;
121     OUString            sNumFormat;
122     OUString            sNumLetterSync;
123     OUString            sBulletFontName;
124     OUString            sBulletFontStyleName;
125     OUString            sImageURL;
126 
127     Reference < XOutputStream > xBase64Stream;
128 
129     sal_Int32           nLevel;
130     sal_Int32           nSpaceBefore;
131     sal_Int32           nMinLabelWidth;
132     sal_Int32           nMinLabelDist;
133     sal_Int32           nImageWidth;
134     sal_Int32           nImageHeight;
135     sal_Int16           nNumStartValue;
136     sal_Int16           nNumDisplayLevels;
137 
138     sal_Int16           eAdjust;
139     sal_Int16           eBulletFontFamily;
140     sal_Int16           eBulletFontPitch;
141     rtl_TextEncoding    eBulletFontEncoding;
142     sal_Int16           eImageVertOrient;
143 
144     sal_UCS4            cBullet;
145 
146     sal_Int16           nRelSize;
147     Color               m_nColor;
148 
149     sal_Int16           ePosAndSpaceMode;
150     sal_Int16           eLabelFollowedBy;
151     sal_Int32           nListtabStopPosition;
152     sal_Int32           nFirstLineIndent;
153     sal_Int32           nIndentAt;
154 
155     bool            bBullet : 1;
156     bool            bImage : 1;
157     bool            bNum : 1;
158     bool            bHasColor : 1;
159 
SetRelSize(sal_Int16 nRel)160     void SetRelSize( sal_Int16 nRel ) { nRelSize = nRel; }
SetColor(Color nColor)161     void SetColor( Color nColor )
162         { m_nColor = nColor; bHasColor = true; }
SetSpaceBefore(sal_Int32 nSet)163     void SetSpaceBefore( sal_Int32 nSet ) { nSpaceBefore = nSet; }
SetMinLabelWidth(sal_Int32 nSet)164     void SetMinLabelWidth( sal_Int32 nSet ) { nMinLabelWidth = nSet; }
SetMinLabelDist(sal_Int32 nSet)165     void SetMinLabelDist( sal_Int32 nSet ) { nMinLabelDist = nSet; }
SetAdjust(sal_Int16 eSet)166     void SetAdjust( sal_Int16 eSet ) { eAdjust = eSet; }
167 
SetBulletFontName(const OUString & rSet)168     void SetBulletFontName( const OUString& rSet ) { sBulletFontName = rSet; }
SetBulletFontStyleName(const OUString & rSet)169     void SetBulletFontStyleName( const OUString& rSet )
170          { sBulletFontStyleName = rSet; }
SetBulletFontFamily(sal_Int16 eSet)171     void SetBulletFontFamily( sal_Int16 eSet ) { eBulletFontFamily = eSet; }
SetBulletFontPitch(sal_Int16 eSet)172     void SetBulletFontPitch( sal_Int16 eSet ) { eBulletFontPitch = eSet; }
SetBulletFontEncoding(rtl_TextEncoding eSet)173     void SetBulletFontEncoding( rtl_TextEncoding eSet )
174          { eBulletFontEncoding = eSet; }
175 
SetImageWidth(sal_Int32 nSet)176     void SetImageWidth( sal_Int32 nSet ) { nImageWidth = nSet; }
SetImageHeight(sal_Int32 nSet)177     void SetImageHeight( sal_Int32 nSet ) { nImageHeight = nSet; }
SetImageVertOrient(sal_Int16 eSet)178     void SetImageVertOrient( sal_Int16 eSet )
179          { eImageVertOrient = eSet; }
180 
181 public:
182 
183     SvxXMLListLevelStyleContext_Impl(
184             SvXMLImport& rImport, sal_Int32 nElement,
185             const Reference< xml::sax::XFastAttributeList > & xAttrList );
186 
187     virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
188         sal_Int32 nElement,
189         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
190 
GetLevel() const191     sal_Int32 GetLevel() const { return nLevel; }
192     Sequence<beans::PropertyValue> GetProperties();
193 
SetPosAndSpaceMode(sal_Int16 eValue)194     void SetPosAndSpaceMode( sal_Int16 eValue )
195     {
196         ePosAndSpaceMode = eValue;
197     }
SetLabelFollowedBy(sal_Int16 eValue)198     void SetLabelFollowedBy( sal_Int16 eValue )
199     {
200         eLabelFollowedBy = eValue;
201     }
SetListtabStopPosition(sal_Int32 nValue)202     void SetListtabStopPosition( sal_Int32 nValue )
203     {
204         nListtabStopPosition = nValue;
205     }
SetFirstLineIndent(sal_Int32 nValue)206     void SetFirstLineIndent( sal_Int32 nValue )
207     {
208         nFirstLineIndent = nValue;
209     }
SetIndentAt(sal_Int32 nValue)210     void SetIndentAt( sal_Int32 nValue )
211     {
212         nIndentAt = nValue;
213     }
214 };
215 
216 constexpr OUStringLiteral gsStarBats( u"StarBats"  );
217 constexpr OUStringLiteral gsStarMath( u"StarMath"  );
218 
SvxXMLListLevelStyleContext_Impl(SvXMLImport & rImport,sal_Int32 nElement,const Reference<xml::sax::XFastAttributeList> & xAttrList)219 SvxXMLListLevelStyleContext_Impl::SvxXMLListLevelStyleContext_Impl(
220         SvXMLImport& rImport, sal_Int32 nElement,
221         const Reference< xml::sax::XFastAttributeList > & xAttrList )
222 
223 :   SvXMLImportContext( rImport )
224 ,   sNumFormat( "1" )
225 ,   nLevel( -1 )
226 ,   nSpaceBefore( 0 )
227 ,   nMinLabelWidth( 0 )
228 ,   nMinLabelDist( 0 )
229 ,   nImageWidth( 0 )
230 ,   nImageHeight( 0 )
231 ,   nNumStartValue( 1 )
232 ,   nNumDisplayLevels( 1 )
233 ,   eAdjust( HoriOrientation::LEFT )
234 ,   eBulletFontFamily( FAMILY_DONTKNOW )
235 ,   eBulletFontPitch( PITCH_DONTKNOW )
236 ,   eBulletFontEncoding( RTL_TEXTENCODING_DONTKNOW )
237 ,   eImageVertOrient(0)
238 ,   cBullet( 0 )
239 ,   nRelSize(0)
240 ,   m_nColor(0)
241 ,   ePosAndSpaceMode( PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION )
242 ,   eLabelFollowedBy( LabelFollow::LISTTAB )
243 ,   nListtabStopPosition( 0 )
244 ,   nFirstLineIndent( 0 )
245 ,   nIndentAt( 0 )
246 ,   bBullet( false )
247 ,   bImage( false )
248 ,   bNum( false )
249 ,   bHasColor( false )
250 {
251     switch (nElement & TOKEN_MASK)
252     {
253         case XML_LIST_LEVEL_STYLE_NUMBER:
254         case XML_OUTLINE_LEVEL_STYLE:
255             bNum = true;
256             break;
257         case XML_LIST_LEVEL_STYLE_BULLET:
258             bBullet = true;
259             break;
260         case XML_LIST_LEVEL_STYLE_IMAGE:
261             bImage = true;
262             break;
263     }
264 
265     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
266     {
267         switch( aIter.getToken() )
268         {
269         case XML_ELEMENT(TEXT, XML_LEVEL):
270             nLevel = aIter.toInt32();
271             if( nLevel >= 1 )
272                 nLevel--;
273             else
274                 nLevel = 0;
275             break;
276         case XML_ELEMENT(TEXT, XML_STYLE_NAME):
277             sTextStyleName = aIter.toString();
278             break;
279         case XML_ELEMENT(TEXT, XML_BULLET_CHAR):
280             if (!aIter.isEmpty())
281             {
282                 cBullet = aIter.toString().iterateCodePoints(&o3tl::temporary(sal_Int32(0)));
283             }
284             break;
285         case XML_ELEMENT(XLINK, XML_HREF):
286             if( bImage )
287                 sImageURL = aIter.toString();
288             break;
289         case XML_ELEMENT(XLINK, XML_TYPE):
290         case XML_ELEMENT(XLINK, XML_SHOW):
291         case XML_ELEMENT(XLINK, XML_ACTUATE):
292             // This properties will be ignored
293             break;
294         case XML_ELEMENT(STYLE, XML_NUM_FORMAT):
295             if( bNum )
296                 sNumFormat = aIter.toString();
297             break;
298         case XML_ELEMENT(STYLE, XML_NUM_PREFIX):
299             sPrefix = aIter.toString();
300             break;
301         case XML_ELEMENT(STYLE, XML_NUM_SUFFIX):
302             sSuffix = aIter.toString();
303             break;
304         case XML_ELEMENT(STYLE, XML_NUM_LIST_FORMAT):
305         case XML_ELEMENT(LO_EXT, XML_NUM_LIST_FORMAT):
306             sListFormat = std::make_optional(aIter.toString());
307             break;
308         case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC):
309             if( bNum )
310                 sNumLetterSync = aIter.toString();
311             break;
312         case XML_ELEMENT(TEXT, XML_START_VALUE):
313             if( bNum )
314             {
315                 sal_Int32 nTmp = aIter.toInt32();
316                 nNumStartValue =
317                     (nTmp < 0) ? 1 : ( (nTmp>SHRT_MAX) ? SHRT_MAX
318                                                         : static_cast<sal_Int16>(nTmp) );
319             }
320             break;
321         case XML_ELEMENT(TEXT, XML_DISPLAY_LEVELS):
322             if( bNum )
323             {
324                 sal_Int32 nTmp = aIter.toInt32();
325                 nNumDisplayLevels =
326                     (nTmp < 1) ? 1 : ( (nTmp>SHRT_MAX) ? SHRT_MAX
327                                                         : static_cast<sal_Int16>(nTmp) );
328             }
329             break;
330         default:
331             XMLOFF_WARN_UNKNOWN("xmloff", aIter);
332         }
333     }
334 }
335 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)336 css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLListLevelStyleContext_Impl::createFastChildContext(
337         sal_Int32 nElement,
338         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
339 {
340     if( nElement == XML_ELEMENT(STYLE, XML_LIST_LEVEL_PROPERTIES) ||
341         nElement == XML_ELEMENT(STYLE, XML_TEXT_PROPERTIES) )
342     {
343         return new SvxXMLListLevelStyleAttrContext_Impl( GetImport(),
344                                                          nElement,
345                                                          xAttrList,
346                                                          *this );
347     }
348     else if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) )
349     {
350         if( bImage && sImageURL.isEmpty() && !xBase64Stream.is() )
351         {
352             xBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64();
353             if( xBase64Stream.is() )
354                 return new XMLBase64ImportContext( GetImport(), xBase64Stream );
355         }
356     }
357     XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
358     return nullptr;
359 }
360 
GetProperties()361 Sequence<beans::PropertyValue> SvxXMLListLevelStyleContext_Impl::GetProperties()
362 {
363     if (!bBullet && !bImage && !bNum)
364     {
365         return Sequence<beans::PropertyValue>();
366     }
367 
368     sal_Int16 eType = NumberingType::NUMBER_NONE;
369     std::vector<beans::PropertyValue> aProperties;
370 
371     if( bBullet )
372     {
373         eType = NumberingType::CHAR_SPECIAL;
374     }
375     if( bImage )
376     {
377         eType = NumberingType::BITMAP;
378     }
379     if( bNum )
380     {
381         eType = NumberingType::ARABIC;
382         GetImport().GetMM100UnitConverter().convertNumFormat(
383                 eType, sNumFormat, sNumLetterSync, true );
384     }
385 
386     if (bBullet && !sSuffix.isEmpty())
387     {
388         sal_uInt16 const nVersion(GetImport().getGeneratorVersion());
389         sal_Int32 nUPD;
390         sal_Int32 nBuildId;
391         if (GetImport().getBuildIds(nUPD, nBuildId)
392             && (   (SvXMLImport::OOo_1x == nVersion)
393                 || (SvXMLImport::OOo_2x == nVersion)
394                 || (310 == nUPD) || (320 == nUPD) || (330 == nUPD)
395                 || ((300 == nUPD) && (nBuildId <= 9573))))
396         {
397             // #i93908# OOo < 3.4 wrote a bogus suffix for bullet chars
398             sSuffix.clear(); // clear it
399         }
400     }
401 
402     if (!sListFormat.has_value())
403     {
404         // This is older document: it has no list format, but can probably contain prefix and/or suffix
405         // Generate list format string, based on this
406         sListFormat = std::make_optional(sPrefix);
407 
408         for (int i = 1; i <= nNumDisplayLevels; i++)
409         {
410             *sListFormat += "%";
411             *sListFormat += OUString::number(nLevel - nNumDisplayLevels + i + 1);
412             *sListFormat += "%";
413             if (i != nNumDisplayLevels)
414                 *sListFormat += ".";     // Default separator for older ODT
415         }
416 
417         *sListFormat += sSuffix;
418     }
419 
420     aProperties.push_back(comphelper::makePropertyValue("NumberingType", eType));
421 
422     aProperties.push_back(comphelper::makePropertyValue("Prefix", sPrefix));
423 
424     aProperties.push_back(comphelper::makePropertyValue("Suffix", sSuffix));
425 
426     aProperties.push_back(comphelper::makePropertyValue("Adjust", eAdjust));
427 
428     sal_Int32 nLeftMargin = nSpaceBefore + nMinLabelWidth;
429     aProperties.push_back(comphelper::makePropertyValue("LeftMargin", nLeftMargin));
430 
431     sal_Int32 nFirstLineOffset = -nMinLabelWidth;
432     aProperties.push_back(comphelper::makePropertyValue("FirstLineOffset", nFirstLineOffset));
433 
434     aProperties.push_back(comphelper::makePropertyValue("SymbolTextDistance", static_cast<sal_Int16>(nMinLabelDist)));
435 
436     aProperties.push_back(comphelper::makePropertyValue("PositionAndSpaceMode", ePosAndSpaceMode));
437 
438     aProperties.push_back(comphelper::makePropertyValue("LabelFollowedBy", eLabelFollowedBy));
439 
440     aProperties.push_back(comphelper::makePropertyValue("ListtabStopPosition", nListtabStopPosition));
441 
442     aProperties.push_back(comphelper::makePropertyValue("FirstLineIndent", nFirstLineIndent));
443 
444     aProperties.push_back(comphelper::makePropertyValue("IndentAt", nIndentAt));
445 
446     OUString sDisplayTextStyleName = GetImport().GetStyleDisplayName(XmlStyleFamily::TEXT_TEXT, sTextStyleName);
447     aProperties.push_back(comphelper::makePropertyValue("CharStyleName", sDisplayTextStyleName));
448 
449     if( bBullet )
450     {
451         awt::FontDescriptor aFDesc;
452         aFDesc.Name = sBulletFontName;
453         if( !sBulletFontName.isEmpty() )
454         {
455             aFDesc.StyleName = sBulletFontStyleName;
456             aFDesc.Family = eBulletFontFamily;
457             aFDesc.Pitch = eBulletFontPitch;
458             aFDesc.CharSet = eBulletFontEncoding;
459             aFDesc.Weight = WEIGHT_DONTKNOW;
460             bool bStarSymbol = false;
461             if( aFDesc.Name.equalsIgnoreAsciiCase( gsStarBats ) )
462             {
463                 cBullet = GetImport().ConvStarBatsCharToStarSymbol( cBullet );
464                 bStarSymbol = true;
465             }
466             else if( aFDesc.Name.equalsIgnoreAsciiCase( gsStarMath ) )
467             {
468                 cBullet = GetImport().ConvStarMathCharToStarSymbol( cBullet );
469                 bStarSymbol = true;
470             }
471             if( bStarSymbol )
472                 aFDesc.Name = "StarSymbol" ;
473         }
474 
475         // Must append 'cBullet' even if it is zero
476         // if 'bBullet' is true and 'cBullet' is zero - BulletChar property must be 0.
477         aProperties.push_back(comphelper::makePropertyValue("BulletChar", OUString(&cBullet, 1)));
478         aProperties.push_back(comphelper::makePropertyValue("BulletFont", aFDesc));
479     }
480 
481     if( bImage )
482     {
483         uno::Reference<graphic::XGraphic> xGraphic;
484         if (!sImageURL.isEmpty())
485         {
486             xGraphic = GetImport().loadGraphicByURL(sImageURL);
487         }
488         else if( xBase64Stream.is() )
489         {
490             xGraphic = GetImport().loadGraphicFromBase64(xBase64Stream);
491         }
492 
493         uno::Reference<awt::XBitmap> xBitmap;
494         if (xGraphic.is())
495             xBitmap.set(xGraphic, uno::UNO_QUERY);
496 
497         if (xBitmap.is())
498         {
499             aProperties.push_back(comphelper::makePropertyValue("GraphicBitmap", xBitmap));
500         }
501 
502         awt::Size aSize(nImageWidth, nImageHeight);
503         aProperties.push_back(comphelper::makePropertyValue("GraphicSize", aSize));
504         aProperties.push_back(comphelper::makePropertyValue("VertOrient", eImageVertOrient));
505     }
506 
507     if( bNum )
508     {
509         aProperties.push_back(comphelper::makePropertyValue("StartWith", nNumStartValue));
510         aProperties.push_back(comphelper::makePropertyValue("ParentNumbering", nNumDisplayLevels));
511     }
512 
513     if( ( bNum || bBullet ) && nRelSize )
514     {
515         aProperties.push_back(comphelper::makePropertyValue("BulletRelSize", nRelSize));
516     }
517 
518     if( !bImage && bHasColor )
519     {
520         aProperties.push_back(comphelper::makePropertyValue("BulletColor", m_nColor));
521     }
522 
523     aProperties.push_back(comphelper::makePropertyValue("ListFormat", *sListFormat));
524 
525     return comphelper::containerToSequence(aProperties);
526 }
527 
SvxXMLListLevelStyleAttrContext_Impl(SvXMLImport & rImport,sal_Int32,const Reference<xml::sax::XFastAttributeList> & xAttrList,SvxXMLListLevelStyleContext_Impl & rLLevel)528 SvxXMLListLevelStyleAttrContext_Impl::SvxXMLListLevelStyleAttrContext_Impl(
529         SvXMLImport& rImport, sal_Int32 /*nElement*/,
530         const Reference< xml::sax::XFastAttributeList > & xAttrList,
531         SvxXMLListLevelStyleContext_Impl& rLLevel ) :
532     SvXMLImportContext( rImport ),
533     rListLevel( rLLevel )
534 {
535     SvXMLUnitConverter& rUnitConv = GetImport().GetMM100UnitConverter();
536 
537     OUString sFontName, sFontFamily, sFontStyleName, sFontFamilyGeneric,
538              sFontPitch, sFontCharset;
539     OUString sVerticalPos, sVerticalRel;
540 
541     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
542     {
543         sal_Int32 nVal;
544         switch( aIter.getToken() )
545         {
546         case XML_ELEMENT(TEXT, XML_SPACE_BEFORE):
547             if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), SHRT_MIN, SHRT_MAX))
548                 rListLevel.SetSpaceBefore( nVal );
549             break;
550         case XML_ELEMENT(TEXT, XML_MIN_LABEL_WIDTH):
551             if (rUnitConv.convertMeasureToCore( nVal, aIter.toView(), 0, SHRT_MAX ))
552                 rListLevel.SetMinLabelWidth( nVal );
553             break;
554         case XML_ELEMENT(TEXT, XML_MIN_LABEL_DISTANCE):
555             if (rUnitConv.convertMeasureToCore( nVal, aIter.toView(), 0, USHRT_MAX ))
556                 rListLevel.SetMinLabelDist( nVal );
557             break;
558         case XML_ELEMENT(FO, XML_TEXT_ALIGN):
559         case XML_ELEMENT(FO_COMPAT, XML_TEXT_ALIGN):
560             if( !aIter.isEmpty() )
561             {
562                 sal_Int16 eAdjust = HoriOrientation::LEFT;
563                 if( IsXMLToken( aIter, XML_CENTER ) )
564                     eAdjust = HoriOrientation::CENTER;
565                 else if( IsXMLToken( aIter, XML_END ) )
566                     eAdjust = HoriOrientation::RIGHT;
567                 rListLevel.SetAdjust( eAdjust );
568             }
569             break;
570         case XML_ELEMENT(STYLE, XML_FONT_NAME):
571             sFontName = aIter.toString();
572             break;
573         case XML_ELEMENT(FO, XML_FONT_FAMILY):
574         case XML_ELEMENT(FO_COMPAT, XML_FONT_FAMILY):
575             sFontFamily = aIter.toString();
576             break;
577         case XML_ELEMENT(STYLE, XML_FONT_FAMILY_GENERIC):
578             sFontFamilyGeneric = aIter.toString();
579             break;
580         case XML_ELEMENT(STYLE, XML_FONT_STYLE_NAME):
581             sFontStyleName = aIter.toString();
582             break;
583         case XML_ELEMENT(STYLE, XML_FONT_PITCH):
584             sFontPitch = aIter.toString();
585             break;
586         case XML_ELEMENT(STYLE, XML_FONT_CHARSET):
587             sFontCharset = aIter.toString();
588             break;
589         case XML_ELEMENT(STYLE, XML_VERTICAL_POS):
590             sVerticalPos = aIter.toString();
591             break;
592         case XML_ELEMENT(STYLE, XML_VERTICAL_REL):
593             sVerticalRel = aIter.toString();
594             break;
595         case XML_ELEMENT(FO, XML_WIDTH):
596         case XML_ELEMENT(FO_COMPAT, XML_WIDTH):
597             if (rUnitConv.convertMeasureToCore(nVal, aIter.toView()))
598                 rListLevel.SetImageWidth( nVal );
599             break;
600         case XML_ELEMENT(FO, XML_HEIGHT):
601         case XML_ELEMENT(FO_COMPAT, XML_HEIGHT):
602             if (rUnitConv.convertMeasureToCore(nVal, aIter.toView()))
603                 rListLevel.SetImageHeight( nVal );
604             break;
605         case XML_ELEMENT(FO, XML_COLOR):
606         case XML_ELEMENT(FO_COMPAT, XML_COLOR):
607             {
608                 Color nColor;
609                 if (::sax::Converter::convertColor( nColor, aIter.toView() ))
610                     rListLevel.SetColor( nColor );
611             }
612             break;
613         case XML_ELEMENT(STYLE, XML_USE_WINDOW_FONT_COLOR):
614             {
615                 if( IsXMLToken( aIter, XML_TRUE ) )
616                     rListLevel.SetColor(COL_AUTO);
617             }
618             break;
619         case XML_ELEMENT(FO, XML_FONT_SIZE):
620         case XML_ELEMENT(FO_COMPAT, XML_FONT_SIZE):
621             if (::sax::Converter::convertPercent( nVal, aIter.toView() ))
622                 rListLevel.SetRelSize( static_cast<sal_Int16>(nVal) );
623             break;
624         case XML_ELEMENT(TEXT, XML_LIST_LEVEL_POSITION_AND_SPACE_MODE):
625             {
626                 sal_Int16 ePosAndSpaceMode = PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION;
627                 if( IsXMLToken( aIter, XML_LABEL_ALIGNMENT ) )
628                     ePosAndSpaceMode = PositionAndSpaceMode::LABEL_ALIGNMENT;
629                 rListLevel.SetPosAndSpaceMode( ePosAndSpaceMode );
630             }
631             break;
632         default:
633             XMLOFF_WARN_UNKNOWN("xmloff", aIter);
634         }
635     }
636 
637     if( !sFontName.isEmpty() )
638     {
639         const XMLFontStylesContext *pFontDecls =
640             GetImport().GetFontDecls();
641         if( pFontDecls )
642         {
643             ::std::vector < XMLPropertyState > aProps;
644             if( pFontDecls->FillProperties( sFontName, aProps, 0, 1, 2, 3, 4 ) )
645             {
646                 OUString sTmp;
647                 sal_Int16 nTmp = 0;
648                 for( const auto& rProp : aProps )
649                 {
650                     switch( rProp.mnIndex )
651                     {
652                     case 0:
653                         rProp.maValue >>= sTmp;
654                         rListLevel.SetBulletFontName( sTmp);
655                         break;
656                     case 1:
657                         rProp.maValue >>= sTmp;
658                         rListLevel.SetBulletFontStyleName( sTmp );
659                         break;
660                     case 2:
661                         rProp.maValue >>= nTmp;
662                         rListLevel.SetBulletFontFamily( nTmp );
663                         break;
664                     case 3:
665                         rProp.maValue >>= nTmp;
666                         rListLevel.SetBulletFontPitch( nTmp );
667                         break;
668                     case 4:
669                         rProp.maValue >>= nTmp;
670                         rListLevel.SetBulletFontEncoding( nTmp );
671                         break;
672                     }
673                 }
674             }
675         }
676     }
677     if( !sFontFamily.isEmpty() )
678     {
679         Any aAny;
680 
681         XMLFontFamilyNamePropHdl aFamilyNameHdl;
682         if( aFamilyNameHdl.importXML( sFontFamily, aAny, rUnitConv ) )
683         {
684             OUString sTmp;
685             aAny >>= sTmp;
686             rListLevel.SetBulletFontName( sTmp);
687         }
688 
689         XMLFontFamilyPropHdl aFamilyHdl;
690         if( !sFontFamilyGeneric.isEmpty() &&
691             aFamilyHdl.importXML( sFontFamilyGeneric, aAny, rUnitConv  ) )
692         {
693             sal_Int16 nTmp = 0;
694             aAny >>= nTmp;
695             rListLevel.SetBulletFontFamily( nTmp );
696         }
697 
698         if( !sFontStyleName.isEmpty() )
699             rListLevel.SetBulletFontStyleName( sFontStyleName );
700 
701         XMLFontPitchPropHdl aPitchHdl;
702         if( !sFontPitch.isEmpty() &&
703             aPitchHdl.importXML( sFontPitch, aAny, rUnitConv  ) )
704         {
705             sal_Int16 nTmp = 0;
706             aAny >>= nTmp;
707             rListLevel.SetBulletFontPitch( nTmp );
708         }
709 
710         XMLFontEncodingPropHdl aEncHdl;
711         if( !sFontCharset.isEmpty() &&
712             aEncHdl.importXML( sFontCharset, aAny, rUnitConv  ) )
713         {
714             sal_Int16 nTmp = 0;
715             aAny >>= nTmp;
716             rListLevel.SetBulletFontEncoding( nTmp );
717         }
718     }
719 
720     sal_Int16 eVertOrient = VertOrientation::LINE_CENTER;
721     if( !sVerticalPos.isEmpty() )
722     {
723         if( IsXMLToken( sVerticalPos, XML_TOP ) )
724             eVertOrient = VertOrientation::LINE_TOP;
725         else if( IsXMLToken( sVerticalPos, XML_BOTTOM ) )
726             eVertOrient = VertOrientation::LINE_BOTTOM;
727     }
728     if( !sVerticalRel.isEmpty() )
729     {
730         if( IsXMLToken( sVerticalRel, XML_BASELINE ) )
731         {
732             // TOP and BOTTOM are exchanged for a baseline relation
733             switch( eVertOrient  )
734             {
735             case VertOrientation::LINE_TOP:
736                 eVertOrient = VertOrientation::BOTTOM;
737                 break;
738             case VertOrientation::LINE_CENTER:
739                 eVertOrient = VertOrientation::CENTER;
740                 break;
741             case VertOrientation::LINE_BOTTOM:
742                 eVertOrient = VertOrientation::TOP;
743                 break;
744             }
745         }
746         else if( IsXMLToken( sVerticalRel, XML_CHAR ) )
747         {
748             switch( eVertOrient  )
749             {
750             case VertOrientation::LINE_TOP:
751                 eVertOrient = VertOrientation::CHAR_TOP;
752                 break;
753             case VertOrientation::LINE_CENTER:
754                 eVertOrient = VertOrientation::CHAR_CENTER;
755                 break;
756             case VertOrientation::LINE_BOTTOM:
757                 eVertOrient = VertOrientation::CHAR_BOTTOM;
758                 break;
759             }
760         }
761     }
762     rListLevel.SetImageVertOrient( eVertOrient );
763 }
764 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)765 css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLListLevelStyleAttrContext_Impl::createFastChildContext(
766         sal_Int32 nElement,
767         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
768 {
769     if ( nElement == XML_ELEMENT(STYLE, XML_LIST_LEVEL_LABEL_ALIGNMENT) )
770     {
771         return new SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl( GetImport(),
772                                                              nElement,
773                                                              xAttrList,
774                                                              rListLevel );
775     }
776     XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
777     return nullptr;
778 }
779 
780 
SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl(SvXMLImport & rImport,sal_Int32,const Reference<xml::sax::XFastAttributeList> & xAttrList,SvxXMLListLevelStyleContext_Impl & rLLevel)781 SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl::SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl(
782         SvXMLImport& rImport, sal_Int32 /*nElement*/,
783         const Reference< xml::sax::XFastAttributeList > & xAttrList,
784         SvxXMLListLevelStyleContext_Impl& rLLevel ) :
785     SvXMLImportContext( rImport )
786 {
787     SvXMLUnitConverter& rUnitConv = GetImport().GetMM100UnitConverter();
788 
789     sal_Int16 eLabelFollowedBy = LabelFollow::LISTTAB;
790     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
791     {
792         sal_Int32 nVal;
793         switch( aIter.getToken() )
794         {
795         case XML_ELEMENT(TEXT, XML_LABEL_FOLLOWED_BY):
796         case XML_ELEMENT(LO_EXT, XML_LABEL_FOLLOWED_BY):
797             {
798                 if( eLabelFollowedBy == LabelFollow::NEWLINE)
799                     //NewLine from LO_EXT has precedence over other values of the Non LO_EXT namespace
800                     break;
801                 if( IsXMLToken( aIter, XML_SPACE ) )
802                     eLabelFollowedBy = LabelFollow::SPACE;
803                 else if( IsXMLToken( aIter, XML_NOTHING ) )
804                     eLabelFollowedBy = LabelFollow::NOTHING;
805                 else if( IsXMLToken( aIter, XML_NEWLINE ) )
806                     eLabelFollowedBy = LabelFollow::NEWLINE;
807             }
808             break;
809         case XML_ELEMENT(TEXT, XML_LIST_TAB_STOP_POSITION):
810             if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), 0, SHRT_MAX))
811                 rLLevel.SetListtabStopPosition( nVal );
812             break;
813         case XML_ELEMENT(FO, XML_TEXT_INDENT):
814         case XML_ELEMENT(FO_COMPAT, XML_TEXT_INDENT):
815             if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), SHRT_MIN, SHRT_MAX))
816                 rLLevel.SetFirstLineIndent( nVal );
817             break;
818         case XML_ELEMENT(FO, XML_MARGIN_LEFT):
819         case XML_ELEMENT(FO_COMPAT, XML_MARGIN_LEFT):
820             if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), SHRT_MIN, SHRT_MAX))
821                 rLLevel.SetIndentAt( nVal );
822             break;
823         default:
824             XMLOFF_WARN_UNKNOWN("xmloff", aIter);
825         }
826     }
827     rLLevel.SetLabelFollowedBy( eLabelFollowedBy );
828 }
829 
SetAttribute(sal_Int32 nElement,const OUString & rValue)830 void SvxXMLListStyleContext::SetAttribute( sal_Int32 nElement,
831                                            const OUString& rValue )
832 {
833     if( nElement == XML_ELEMENT(TEXT, XML_CONSECUTIVE_NUMBERING) )
834     {
835         bConsecutive = IsXMLToken( rValue, XML_TRUE );
836     }
837     else
838     {
839         SvXMLStyleContext::SetAttribute( nElement, rValue );
840     }
841 }
842 
843 constexpr OUStringLiteral sIsPhysical( u"IsPhysical"  );
844 constexpr OUStringLiteral sNumberingRules( u"NumberingRules"  );
845 constexpr OUStringLiteral sIsContinuousNumbering( u"IsContinuousNumbering"  );
846 
SvxXMLListStyleContext(SvXMLImport & rImport,bool bOutl)847 SvxXMLListStyleContext::SvxXMLListStyleContext( SvXMLImport& rImport,
848         bool bOutl )
849 :   SvXMLStyleContext( rImport, bOutl ? XmlStyleFamily::TEXT_OUTLINE : XmlStyleFamily::TEXT_LIST )
850 ,   bConsecutive( false )
851 ,   bOutline( bOutl )
852 {
853 }
854 
~SvxXMLListStyleContext()855 SvxXMLListStyleContext::~SvxXMLListStyleContext() {}
856 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)857 css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLListStyleContext::createFastChildContext(
858         sal_Int32 nElement,
859         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
860 {
861     if( bOutline
862         ? nElement == XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL_STYLE)
863         : ( nElement == XML_ELEMENT(TEXT, XML_LIST_LEVEL_STYLE_NUMBER) ||
864             nElement == XML_ELEMENT(TEXT, XML_LIST_LEVEL_STYLE_BULLET) ||
865             nElement == XML_ELEMENT(TEXT, XML_LIST_LEVEL_STYLE_IMAGE )    ) )
866     {
867         rtl::Reference<SvxXMLListLevelStyleContext_Impl> xLevelStyle{
868             new SvxXMLListLevelStyleContext_Impl( GetImport(), nElement, xAttrList )};
869         if( !pLevelStyles )
870             pLevelStyles = std::make_unique<SvxXMLListStyle_Impl>();
871         pLevelStyles->push_back( xLevelStyle );
872 
873         return xLevelStyle;
874     }
875     XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
876     return nullptr;
877 }
878 
FillUnoNumRule(const Reference<container::XIndexReplace> & rNumRule) const879 void SvxXMLListStyleContext::FillUnoNumRule(
880         const Reference<container::XIndexReplace> & rNumRule) const
881 {
882     try
883     {
884         if( pLevelStyles && rNumRule.is() )
885         {
886             sal_Int32 l_nLevels = rNumRule->getCount();
887             for (const auto& pLevelStyle : *pLevelStyles)
888             {
889                 sal_Int32 nLevel = pLevelStyle->GetLevel();
890                 if( nLevel >= 0 && nLevel < l_nLevels )
891                 {
892                     Sequence<beans::PropertyValue> aProps =
893                         pLevelStyle->GetProperties();
894                     rNumRule->replaceByIndex( nLevel, Any(aProps) );
895                 }
896             }
897         }
898 
899         Reference < XPropertySet > xPropSet( rNumRule, UNO_QUERY );
900         Reference< XPropertySetInfo > xPropSetInfo;
901         if (xPropSet.is())
902             xPropSetInfo = xPropSet->getPropertySetInfo();
903         if( xPropSetInfo.is() &&
904             xPropSetInfo->hasPropertyByName( sIsContinuousNumbering ) )
905         {
906             xPropSet->setPropertyValue( sIsContinuousNumbering, Any(bConsecutive) );
907         }
908     }
909     catch (const Exception&)
910     {
911         TOOLS_WARN_EXCEPTION("xmloff.style", "" );
912     }
913 }
914 
CreateAndInsertLate(bool bOverwrite)915 void SvxXMLListStyleContext::CreateAndInsertLate( bool bOverwrite )
916 {
917     if( bOutline )
918     {
919         if( bOverwrite )
920         {
921             const Reference< XIndexReplace >& rNumRule =
922                 GetImport().GetTextImport()->GetChapterNumbering();
923             // We don't set xNumberingRules here, to avoid using them
924             // as numbering rules.
925             if( rNumRule.is() )
926                 FillUnoNumRule(rNumRule);
927         }
928     }
929     else
930     {
931         Reference < XStyle > xStyle;
932         const OUString& rName = GetDisplayName();
933         if( rName.isEmpty() )
934         {
935             SetValid( false );
936             return;
937         }
938 
939         const Reference < XNameContainer >& rNumStyles =
940                 GetImport().GetTextImport()->GetNumberingStyles();
941         if( !rNumStyles.is() )
942         {
943             SetValid( false );
944             return;
945         }
946 
947         bool bNew = false;
948         if( rNumStyles->hasByName( rName ) )
949         {
950             Any aAny = rNumStyles->getByName( rName );
951             aAny >>= xStyle;
952         }
953         else
954         {
955             Reference< XMultiServiceFactory > xFactory( GetImport().GetModel(),
956                                                         UNO_QUERY );
957             SAL_WARN_IF( !xFactory.is(), "xmloff", "no factory" );
958             if( !xFactory.is() )
959                 return;
960 
961             Reference < XInterface > xIfc = xFactory->createInstance("com.sun.star.style.NumberingStyle");
962             if( !xIfc.is() )
963                 return;
964             Reference < XStyle > xTmp( xIfc, UNO_QUERY );
965             xStyle = xTmp;
966             if( !xStyle.is() )
967                 return;
968 
969             rNumStyles->insertByName( rName, Any(xStyle) );
970             bNew = true;
971         }
972 
973         Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY );
974         Reference< XPropertySetInfo > xPropSetInfo =
975             xPropSet->getPropertySetInfo();
976         if( !bNew && xPropSetInfo->hasPropertyByName( sIsPhysical ) )
977         {
978             Any aAny = xPropSet->getPropertyValue( sIsPhysical );
979             bNew = !*o3tl::doAccess<bool>(aAny);
980         }
981 
982         if ( xPropSetInfo->hasPropertyByName( "Hidden" ) )
983             xPropSet->setPropertyValue( "Hidden", uno::makeAny( IsHidden( ) ) );
984 
985         if( rName != GetName() )
986             GetImport().AddStyleDisplayName( XmlStyleFamily::TEXT_LIST,
987                                              GetName(), rName );
988 
989         Any aAny = xPropSet->getPropertyValue( sNumberingRules );
990         aAny >>= xNumRules;
991         if( bOverwrite || bNew )
992         {
993             FillUnoNumRule(xNumRules);
994             xPropSet->setPropertyValue( sNumberingRules, Any(xNumRules) );
995         }
996         else
997         {
998             SetValid( false );
999         }
1000 
1001         SetNew( bNew );
1002     }
1003 }
1004 
CreateAndInsertAuto() const1005 void SvxXMLListStyleContext::CreateAndInsertAuto() const
1006 {
1007     SAL_WARN_IF( bOutline, "xmloff", "Outlines cannot be inserted here" );
1008     SAL_WARN_IF( xNumRules.is(), "xmloff", "Numbering Rule is existing already" );
1009 
1010     const OUString& rName = GetName();
1011     if( bOutline || xNumRules.is() || rName.isEmpty() )
1012     {
1013         const_cast<SvxXMLListStyleContext *>(this)->SetValid( false );
1014         return;
1015     }
1016 
1017     const_cast<SvxXMLListStyleContext *>(this)->xNumRules = CreateNumRule(
1018         GetImport().GetModel() );
1019 
1020     FillUnoNumRule(xNumRules);
1021 }
1022 
CreateNumRule(const Reference<XModel> & rModel)1023 Reference < XIndexReplace > SvxXMLListStyleContext::CreateNumRule(
1024                                 const Reference < XModel > & rModel )
1025 {
1026     Reference<XIndexReplace> xNumRule;
1027 
1028     Reference< XMultiServiceFactory > xFactory( rModel, UNO_QUERY );
1029     SAL_WARN_IF( !xFactory.is(), "xmloff", "no factory" );
1030     if( !xFactory.is() )
1031         return xNumRule;
1032 
1033     Reference < XInterface > xIfc = xFactory->createInstance("com.sun.star.text.NumberingRules");
1034     if( !xIfc.is() )
1035         return xNumRule;
1036 
1037     xNumRule.set( xIfc, UNO_QUERY );
1038     SAL_WARN_IF( !xNumRule.is(), "xmloff", "go no numbering rule" );
1039 
1040     return xNumRule;
1041 }
1042 
SetDefaultStyle(const Reference<XIndexReplace> & rNumRule,sal_Int16 nLevel,bool bOrdered)1043 void SvxXMLListStyleContext::SetDefaultStyle(
1044         const Reference < XIndexReplace > & rNumRule,
1045         sal_Int16 nLevel,
1046         bool bOrdered )
1047 {
1048     Sequence<beans::PropertyValue> aPropSeq( bOrdered ? 1 : 4  );
1049     beans::PropertyValue *pProps = aPropSeq.getArray();
1050 
1051     pProps->Name = "NumberingType";
1052     (pProps++)->Value <<= static_cast<sal_Int16>(bOrdered ? NumberingType::ARABIC
1053                                                  : NumberingType::CHAR_SPECIAL );
1054     if( !bOrdered )
1055     {
1056         // TODO: Bullet-Font
1057         awt::FontDescriptor aFDesc;
1058         aFDesc.Name =
1059 #ifdef _WIN32
1060                         "StarBats"
1061 #else
1062                         "starbats"
1063 #endif
1064                                         ;
1065         aFDesc.Family = FAMILY_DONTKNOW ;
1066         aFDesc.Pitch = PITCH_DONTKNOW ;
1067         aFDesc.CharSet = RTL_TEXTENCODING_SYMBOL ;
1068         aFDesc.Weight = WEIGHT_DONTKNOW;
1069         pProps->Name = "BulletFont";
1070         (pProps++)->Value <<= aFDesc;
1071 
1072         pProps->Name = "BulletChar";
1073         (pProps++)->Value <<= OUString(sal_Unicode(0xF000 + 149));
1074         pProps->Name = "CharStyleName";
1075         (pProps++)->Value <<= OUString( "Numbering Symbols"  );
1076     }
1077 
1078     rNumRule->replaceByIndex( nLevel, Any(aPropSeq) );
1079 }
1080 
1081 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1082