LibreOffice Module xmloff (master)  1
XMLTextColumnsContext.cxx
Go to the documentation of this file.
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 <sal/config.h>
21 
22 #include <com/sun/star/frame/XModel.hpp>
23 #include <com/sun/star/text/XTextColumns.hpp>
24 #include <com/sun/star/text/TextColumn.hpp>
25 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
26 #include <com/sun/star/style/VerticalAlignment.hpp>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <sax/tools/converter.hxx>
29 #include <xmloff/xmltkmap.hxx>
30 #include <xmloff/xmluconv.hxx>
31 #include <xmloff/nmspmap.hxx>
32 #include <xmloff/xmlnmspe.hxx>
33 #include <xmloff/xmlimp.hxx>
34 #include <xmloff/xmltoken.hxx>
35 #include <xmloff/xmlement.hxx>
37 
38 using namespace ::com::sun::star;
39 using namespace ::com::sun::star::uno;
40 using namespace ::com::sun::star::lang;
41 using namespace ::com::sun::star::text;
42 using namespace ::com::sun::star::style;
43 using namespace ::com::sun::star::beans;
44 using namespace ::xmloff::token;
45 
46 namespace {
47 
49 {
50  XML_TOK_COLUMN_WIDTH,
51  XML_TOK_COLUMN_MARGIN_LEFT,
52  XML_TOK_COLUMN_MARGIN_RIGHT
53 };
54 
56 {
57  XML_TOK_COLUMN_SEP_WIDTH,
58  XML_TOK_COLUMN_SEP_HEIGHT,
59  XML_TOK_COLUMN_SEP_COLOR,
60  XML_TOK_COLUMN_SEP_ALIGN,
61  XML_TOK_COLUMN_SEP_STYLE
62 };
63 
64 }
65 
67 {
68  { XML_NAMESPACE_STYLE, XML_REL_WIDTH, XML_TOK_COLUMN_WIDTH },
69  { XML_NAMESPACE_FO, XML_START_INDENT, XML_TOK_COLUMN_MARGIN_LEFT },
70  { XML_NAMESPACE_FO, XML_END_INDENT, XML_TOK_COLUMN_MARGIN_RIGHT },
72 };
73 
75 {
76  { XML_NAMESPACE_STYLE, XML_WIDTH, XML_TOK_COLUMN_SEP_WIDTH },
77  { XML_NAMESPACE_STYLE, XML_COLOR, XML_TOK_COLUMN_SEP_COLOR },
78  { XML_NAMESPACE_STYLE, XML_HEIGHT, XML_TOK_COLUMN_SEP_HEIGHT },
79  { XML_NAMESPACE_STYLE, XML_VERTICAL_ALIGN, XML_TOK_COLUMN_SEP_ALIGN },
80  { XML_NAMESPACE_STYLE, XML_STYLE, XML_TOK_COLUMN_SEP_STYLE },
82 };
83 
85 {
86  { XML_NONE, 0 },
87  { XML_SOLID, 1 },
88  { XML_DOTTED, 2 },
89  { XML_DASHED, 3 },
90  { XML_TOKEN_INVALID, 0 }
91 };
92 
94 {
95  { XML_TOP, VerticalAlignment_TOP },
96  { XML_MIDDLE, VerticalAlignment_MIDDLE },
97  { XML_BOTTOM, VerticalAlignment_BOTTOM },
98  { XML_TOKEN_INVALID, VerticalAlignment(0) }
99 };
100 
102 {
103  text::TextColumn aColumn;
104 
105 public:
106 
107  XMLTextColumnContext_Impl( SvXMLImport& rImport, sal_uInt16 nPrfx,
108  const OUString& rLName,
109  const uno::Reference<
110  xml::sax::XAttributeList > & xAttrList,
111  const SvXMLTokenMap& rTokenMap );
112 
113  text::TextColumn& getTextColumn() { return aColumn; }
114 };
115 
116 
118  SvXMLImport& rImport, sal_uInt16 nPrfx,
119  const OUString& rLName,
120  const uno::Reference<
121  xml::sax::XAttributeList > & xAttrList,
122  const SvXMLTokenMap& rTokenMap ) :
123  SvXMLImportContext( rImport, nPrfx, rLName )
124 {
125  aColumn.Width = 0;
126  aColumn.LeftMargin = 0;
127  aColumn.RightMargin = 0;
128 
129  sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
130  for( sal_Int16 i=0; i < nAttrCount; i++ )
131  {
132  const OUString& rAttrName = xAttrList->getNameByIndex( i );
133  OUString aLocalName;
134  sal_uInt16 nPrefix =
136  &aLocalName );
137  const OUString& rValue = xAttrList->getValueByIndex( i );
138 
139  sal_Int32 nVal;
140  switch( rTokenMap.Get( nPrefix, aLocalName ) )
141  {
142  case XML_TOK_COLUMN_WIDTH:
143  {
144  sal_Int32 nPos = rValue.indexOf( '*' );
145  if( nPos != -1 && nPos+1 == rValue.getLength() )
146  {
148  nVal,
149  std::u16string_view(rValue).substr(0, nPos),
150  0, USHRT_MAX))
151  aColumn.Width = nVal;
152  }
153  }
154  break;
155  case XML_TOK_COLUMN_MARGIN_LEFT:
157  convertMeasureToCore( nVal, rValue ) )
158  aColumn.LeftMargin = nVal;
159  break;
160  case XML_TOK_COLUMN_MARGIN_RIGHT:
161 
163  convertMeasureToCore( nVal, rValue ) )
164  aColumn.RightMargin = nVal;
165  break;
166  default:
167  break;
168  }
169  }
170 }
171 
173 {
174  sal_Int32 nWidth;
175  sal_Int32 nColor;
178  VerticalAlignment eVertAlign;
179 
180 public:
181 
182  XMLTextColumnSepContext_Impl( SvXMLImport& rImport, sal_uInt16 nPrfx,
183  const OUString& rLName,
184  const uno::Reference<
185  xml::sax::XAttributeList > & xAttrList,
186  const SvXMLTokenMap& rTokenMap );
187 
188  sal_Int32 GetWidth() const { return nWidth; }
189  sal_Int32 GetColor() const { return nColor; }
190  sal_Int8 GetHeight() const { return nHeight; }
191  sal_Int8 GetStyle() const { return nStyle; }
192  VerticalAlignment GetVertAlign() const { return eVertAlign; }
193 };
194 
195 
197  SvXMLImport& rImport, sal_uInt16 nPrfx,
198  const OUString& rLName,
199  const uno::Reference<
200  xml::sax::XAttributeList > & xAttrList,
201  const SvXMLTokenMap& rTokenMap ) :
202  SvXMLImportContext( rImport, nPrfx, rLName ),
203  nWidth( 2 ),
204  nColor( 0 ),
205  nHeight( 100 ),
206  nStyle( 1 ),
207  eVertAlign( VerticalAlignment_TOP )
208 {
209  sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
210  for( sal_Int16 i=0; i < nAttrCount; i++ )
211  {
212  const OUString& rAttrName = xAttrList->getNameByIndex( i );
213  OUString aLocalName;
214  sal_uInt16 nPrefix =
216  &aLocalName );
217  const OUString& rValue = xAttrList->getValueByIndex( i );
218 
219  sal_Int32 nVal;
220  switch( rTokenMap.Get( nPrefix, aLocalName ) )
221  {
222  case XML_TOK_COLUMN_SEP_WIDTH:
224  convertMeasureToCore( nVal, rValue ) )
225  nWidth = nVal;
226  break;
227  case XML_TOK_COLUMN_SEP_HEIGHT:
228  if (::sax::Converter::convertPercent( nVal, rValue ) &&
229  nVal >=1 && nVal <= 100 )
230  nHeight = static_cast<sal_Int8>(nVal);
231  break;
232  case XML_TOK_COLUMN_SEP_COLOR:
234  break;
235  case XML_TOK_COLUMN_SEP_ALIGN:
237  pXML_Sep_Align_Enum );
238  break;
239  case XML_TOK_COLUMN_SEP_STYLE:
241  pXML_Sep_Style_Enum );
242  break;
243  }
244  }
245 }
246 
247 static const OUStringLiteral gsSeparatorLineIsOn("SeparatorLineIsOn");
248 static const OUStringLiteral gsSeparatorLineWidth("SeparatorLineWidth");
249 static const OUStringLiteral gsSeparatorLineColor("SeparatorLineColor");
250 static const OUStringLiteral gsSeparatorLineRelativeHeight("SeparatorLineRelativeHeight");
251 static const OUStringLiteral gsSeparatorLineVerticalAlignment("SeparatorLineVerticalAlignment");
252 static const OUStringLiteral gsAutomaticDistance("AutomaticDistance");
253 static const OUStringLiteral gsSeparatorLineStyle("SeparatorLineStyle");
254 
256  SvXMLImport& rImport, sal_uInt16 nPrfx,
257  const OUString& rLName,
258  const Reference< xml::sax::XAttributeList >&
259  xAttrList,
260  const XMLPropertyState& rProp,
261  ::std::vector< XMLPropertyState > &rProps )
262 : XMLElementPropertyContext( rImport, nPrfx, rLName, rProp, rProps )
263 , pColumnAttrTokenMap( new SvXMLTokenMap(aColAttrTokenMap) )
264 , pColumnSepAttrTokenMap( new SvXMLTokenMap(aColSepAttrTokenMap) )
265 , nCount( 0 )
266 , bAutomatic( false )
267 , nAutomaticDistance( 0 )
268 {
269  sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
270  sal_Int32 nVal;
271  for( sal_Int16 i=0; i < nAttrCount; i++ )
272  {
273  const OUString& rAttrName = xAttrList->getNameByIndex( i );
274  OUString aLocalName;
275  sal_uInt16 nPrefix =
277  &aLocalName );
278  const OUString& rValue = xAttrList->getValueByIndex( i );
279  if( XML_NAMESPACE_FO == nPrefix )
280  {
281  if( IsXMLToken( aLocalName, XML_COLUMN_COUNT ) &&
282  ::sax::Converter::convertNumber( nVal, rValue, 0, SHRT_MAX ))
283  {
284  nCount = static_cast<sal_Int16>(nVal);
285  }
286  else if( IsXMLToken( aLocalName, XML_COLUMN_GAP ) )
287  {
289  convertMeasureToCore( nAutomaticDistance, rValue );
290  }
291  }
292  }
293 }
294 
296  sal_uInt16 nPrefix,
297  const OUString& rLocalName,
298  const uno::Reference< xml::sax::XAttributeList > & xAttrList )
299 {
300  SvXMLImportContext *pContext = nullptr;
301 
302  if( XML_NAMESPACE_STYLE == nPrefix &&
303  IsXMLToken( rLocalName, XML_COLUMN ) )
304  {
306  new XMLTextColumnContext_Impl( GetImport(), nPrefix, rLocalName,
307  xAttrList, *pColumnAttrTokenMap )};
308 
309  // add new tabstop to array of tabstops
310  if( !pColumns )
311  pColumns = std::make_unique<XMLTextColumnsArray_Impl>();
312 
313  pColumns->push_back( xColumn );
314 
315  pContext = xColumn.get();
316  }
317  else if( XML_NAMESPACE_STYLE == nPrefix &&
318  IsXMLToken( rLocalName, XML_COLUMN_SEP ) )
319  {
320  mxColumnSep.set(
321  new XMLTextColumnSepContext_Impl( GetImport(), nPrefix, rLocalName,
322  xAttrList, *pColumnSepAttrTokenMap ));
323 
324  pContext = mxColumnSep.get();
325  }
326 
327  return pContext;
328 }
329 
331 {
332  Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(),UNO_QUERY);
333  if( !xFactory.is() )
334  return;
335 
336  Reference<XInterface> xIfc = xFactory->createInstance("com.sun.star.text.TextColumns");
337  if( !xIfc.is() )
338  return;
339 
340  Reference< XTextColumns > xColumns( xIfc, UNO_QUERY );
341  if ( 0 == nCount )
342  {
343  // zero columns = no columns -> 1 column
344  xColumns->setColumnCount( 1 );
345  }
346  else if( !bAutomatic && pColumns &&
347  pColumns->size() == static_cast<sal_uInt16>(nCount) )
348  {
349  // if we have column descriptions, one per column, and we don't use
350  // automatic width, then set the column widths
351 
352  sal_Int32 nRelWidth = 0;
353  sal_uInt16 nColumnsWithWidth = 0;
354  sal_Int16 i;
355 
356  for( i = 0; i < nCount; i++ )
357  {
358  const TextColumn& rColumn =
359  (*pColumns)[static_cast<sal_uInt16>(i)]->getTextColumn();
360  if( rColumn.Width > 0 )
361  {
362  nRelWidth += rColumn.Width;
363  nColumnsWithWidth++;
364  }
365  }
366  if( nColumnsWithWidth < nCount )
367  {
368  sal_Int32 nColWidth = 0==nRelWidth
369  ? USHRT_MAX / nCount
370  : nRelWidth / nColumnsWithWidth;
371 
372  for( i=0; i < nCount; i++ )
373  {
374  TextColumn& rColumn =
375  (*pColumns)[static_cast<sal_uInt16>(i)]->getTextColumn();
376  if( rColumn.Width == 0 )
377  {
378  rColumn.Width = nColWidth;
379  nRelWidth += rColumn.Width;
380  if( 0 == --nColumnsWithWidth )
381  break;
382  }
383  }
384  }
385 
386  Sequence< TextColumn > aColumns( static_cast<sal_Int32>(nCount) );
387  TextColumn *pTextColumns = aColumns.getArray();
388  for( i=0; i < nCount; i++ )
389  *pTextColumns++ = (*pColumns)[static_cast<sal_uInt16>(i)]->getTextColumn();
390 
391  xColumns->setColumns( aColumns );
392  }
393  else
394  {
395  // only set column count (and let the columns be distributed
396  // automatically)
397 
398  xColumns->setColumnCount( nCount );
399  }
400 
401  Reference < XPropertySet > xPropSet( xColumns, UNO_QUERY );
402  if( xPropSet.is() )
403  {
404  bool bOn = mxColumnSep != nullptr;
405 
406  xPropSet->setPropertyValue( gsSeparatorLineIsOn, Any(bOn) );
407 
408  if( mxColumnSep.is() )
409  {
410  if( mxColumnSep->GetWidth() )
411  {
412  xPropSet->setPropertyValue( gsSeparatorLineWidth, Any(mxColumnSep->GetWidth()) );
413  }
414  if( mxColumnSep->GetHeight() )
415  {
416  xPropSet->setPropertyValue( gsSeparatorLineRelativeHeight,
417  Any(mxColumnSep->GetHeight()) );
418  }
419  if ( mxColumnSep->GetStyle() )
420  {
421  xPropSet->setPropertyValue( gsSeparatorLineStyle, Any(mxColumnSep->GetStyle()) );
422  }
423 
424  xPropSet->setPropertyValue( gsSeparatorLineColor, Any(mxColumnSep->GetColor()) );
425 
426  xPropSet->setPropertyValue( gsSeparatorLineVerticalAlignment, Any(mxColumnSep->GetVertAlign()) );
427  }
428 
429  // handle 'automatic columns': column distance
430  if( bAutomatic )
431  {
432  xPropSet->setPropertyValue( gsAutomaticDistance, Any(nAutomaticDistance) );
433  }
434  }
435 
436  aProp.maValue <<= xColumns;
437 
438  SetInsert( true );
440 
441 }
442 
443 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsXMLToken(const OUString &rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3422
constexpr sal_uInt16 XML_NAMESPACE_STYLE
Definition: xmlnmspe.hxx:30
virtual void EndElement() override
EndElement is called before a context will be destructed, but after an elements context has been pars...
XMLTextColumnContext_Impl(SvXMLImport &rImport, sal_uInt16 nPrfx, const OUString &rLName, const uno::Reference< xml::sax::XAttributeList > &xAttrList, const SvXMLTokenMap &rTokenMap)
static const OUStringLiteral gsSeparatorLineStyle("SeparatorLineStyle")
std::unique_ptr< SvXMLTokenMap > pColumnSepAttrTokenMap
static bool convertEnum(EnumT &rEnum, const OUString &rValue, const SvXMLEnumMapEntry< EnumT > *pMap)
convert string to enum using given enum map, if the enum is not found in the map, this method will re...
Definition: xmluconv.hxx:128
signed char sal_Int8
static const OUStringLiteral gsSeparatorLineColor("SeparatorLineColor")
XMLTextColumnsContext(SvXMLImport &rImport, sal_uInt16 nPrfx, const OUString &rLName, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList, const XMLPropertyState &rProp,::std::vector< XMLPropertyState > &rProps)
SvXMLTokenMapAttrs
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:62
static const OUStringLiteral gsAutomaticDistance("AutomaticDistance")
SvXMLNamespaceMap & GetNamespaceMap()
Definition: xmlimp.hxx:397
static const OUStringLiteral gsSeparatorLineRelativeHeight("SeparatorLineRelativeHeight")
static const SvXMLTokenMapEntry aColAttrTokenMap[]
sal_uInt16 GetKeyByAttrName(const OUString &rAttrName, OUString *pPrefix, OUString *pLocalName, OUString *pNamespace) const
Definition: nmspmap.cxx:437
#define XML_TOKEN_MAP_END
Definition: xmltkmap.hxx:33
rtl::Reference< XMLTextColumnSepContext_Impl > mxColumnSep
text::TextColumn & getTextColumn()
css::uno::Any const & rValue
Definition: ImageStyle.hxx:38
int nCount
VerticalAlignment GetVertAlign() const
XMLTextColumnSepContext_Impl(SvXMLImport &rImport, sal_uInt16 nPrfx, const OUString &rLName, const uno::Reference< xml::sax::XAttributeList > &xAttrList, const SvXMLTokenMap &rTokenMap)
int i
sal_uInt16 Get(sal_uInt16 nPrefix, const OUString &rLName) const
Definition: xmltkmap.cxx:93
static const OUStringLiteral gsSeparatorLineIsOn("SeparatorLineIsOn")
static const OUStringLiteral gsSeparatorLineWidth("SeparatorLineWidth")
static SvXMLEnumMapEntry< VerticalAlignment > const pXML_Sep_Align_Enum[]
static const OUStringLiteral gsSeparatorLineVerticalAlignment("SeparatorLineVerticalAlignment")
virtual SvXMLImportContextRef CreateChildContext(sal_uInt16 nPrefix, const OUString &rLocalName, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList) override
Create a children element context.
This class deliberately does not support XWeak, to improve performance when loading large documents...
Definition: xmlictxt.hxx:44
constexpr sal_uInt16 XML_NAMESPACE_FO
Definition: xmlnmspe.hxx:34
Map an XMLTokenEnum to an enum value.
Definition: ximpshap.hxx:40
css::uno::Any maValue
Definition: maptype.hxx:107
static const SvXMLTokenMapEntry aColSepAttrTokenMap[]
SvXMLSepTokenMapAttrs
static bool convertColor(sal_Int32 &rColor, const OUString &rValue)
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Handling of tokens in XML:
Smart struct to transport an Any with an index to the appropriate property-name.
Definition: maptype.hxx:104
const SvXMLUnitConverter & GetMM100UnitConverter() const
Definition: xmlimp.hxx:399
static SvXMLEnumMapEntry< sal_Int8 > const pXML_Sep_Style_Enum[]
std::unique_ptr< SvXMLTokenMap > pColumnAttrTokenMap
Reference< XColumn > xColumn
Reference< XSingleServiceFactory > xFactory
sal_uInt16 nPos
std::unique_ptr< XMLTextColumnsArray_Impl > pColumns
virtual void EndElement() override
EndElement is called before a context will be destructed, but after an elements context has been pars...
static bool convertPercent(sal_Int32 &rValue, const OUString &rString)
static bool convertNumber(sal_Int32 &rValue, std::u16string_view aString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)