xref: /trunk/main/xmloff/source/text/XMLTextColumnsContext.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 #include <com/sun/star/text/XTextColumns.hpp>
31 #include <com/sun/star/text/TextColumn.hpp>
32 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
33 #include <com/sun/star/style/VerticalAlignment.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <xmloff/xmltkmap.hxx>
36 #include <xmloff/xmluconv.hxx>
37 #include <xmloff/nmspmap.hxx>
38 #include "xmloff/xmlnmspe.hxx"
39 #include <xmloff/xmlimp.hxx>
40 #include <xmloff/xmltoken.hxx>
41 #include "XMLTextColumnsContext.hxx"
42 #define _SVSTDARR_USHORTS
43 #include <svl/svstdarr.hxx>
44 
45 using ::rtl::OUString;
46 using ::rtl::OUStringBuffer;
47 
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::uno;
50 using namespace ::com::sun::star::lang;
51 using namespace ::com::sun::star::text;
52 using namespace ::com::sun::star::style;
53 using namespace ::com::sun::star::beans;
54 using namespace ::xmloff::token;
55 
56 enum SvXMLTokenMapAttrs
57 {
58     XML_TOK_COLUMN_WIDTH,
59     XML_TOK_COLUMN_MARGIN_LEFT,
60     XML_TOK_COLUMN_MARGIN_RIGHT,
61     XML_TOK_COLUMN_END=XML_TOK_UNKNOWN
62 };
63 
64 enum SvXMLSepTokenMapAttrs
65 {
66     XML_TOK_COLUMN_SEP_WIDTH,
67     XML_TOK_COLUMN_SEP_HEIGHT,
68     XML_TOK_COLUMN_SEP_COLOR,
69     XML_TOK_COLUMN_SEP_ALIGN,
70     XML_TOK_COLUMN_SEP_END=XML_TOK_UNKNOWN
71 };
72 
73 static __FAR_DATA SvXMLTokenMapEntry aColAttrTokenMap[] =
74 {
75     { XML_NAMESPACE_STYLE,  XML_REL_WIDTH,      XML_TOK_COLUMN_WIDTH },
76     { XML_NAMESPACE_FO,     XML_START_INDENT,   XML_TOK_COLUMN_MARGIN_LEFT },
77     { XML_NAMESPACE_FO,     XML_END_INDENT,     XML_TOK_COLUMN_MARGIN_RIGHT },
78     XML_TOKEN_MAP_END
79 };
80 
81 static __FAR_DATA SvXMLTokenMapEntry aColSepAttrTokenMap[] =
82 {
83     { XML_NAMESPACE_STYLE,  XML_WIDTH,          XML_TOK_COLUMN_SEP_WIDTH },
84     { XML_NAMESPACE_STYLE,  XML_COLOR,          XML_TOK_COLUMN_SEP_COLOR },
85     { XML_NAMESPACE_STYLE,  XML_HEIGHT,         XML_TOK_COLUMN_SEP_HEIGHT },
86     { XML_NAMESPACE_STYLE,  XML_VERTICAL_ALIGN, XML_TOK_COLUMN_SEP_ALIGN },
87     XML_TOKEN_MAP_END
88 };
89 
90 SvXMLEnumMapEntry __READONLY_DATA pXML_Sep_Align_Enum[] =
91 {
92     { XML_TOP,          VerticalAlignment_TOP   },
93     { XML_MIDDLE,       VerticalAlignment_MIDDLE },
94     { XML_BOTTOM,       VerticalAlignment_BOTTOM },
95     { XML_TOKEN_INVALID, 0 }
96 };
97 
98 class XMLTextColumnContext_Impl: public SvXMLImportContext
99 {
100     text::TextColumn aColumn;
101 
102 public:
103     TYPEINFO();
104 
105     XMLTextColumnContext_Impl( SvXMLImport& rImport, sal_uInt16 nPrfx,
106                                const OUString& rLName,
107                                const uno::Reference<
108                                     xml::sax::XAttributeList > & xAttrList,
109                                const SvXMLTokenMap& rTokenMap );
110 
111     virtual ~XMLTextColumnContext_Impl();
112 
113     text::TextColumn& getTextColumn() { return aColumn; }
114 };
115 
116 TYPEINIT1( XMLTextColumnContext_Impl, SvXMLImportContext );
117 
118 XMLTextColumnContext_Impl::XMLTextColumnContext_Impl(
119                                SvXMLImport& rImport, sal_uInt16 nPrfx,
120                                const OUString& rLName,
121                                const uno::Reference<
122                                     xml::sax::XAttributeList > & xAttrList,
123                                const SvXMLTokenMap& rTokenMap ) :
124     SvXMLImportContext( rImport, nPrfx, rLName )
125 {
126     aColumn.Width = 0;
127     aColumn.LeftMargin = 0;
128     aColumn.RightMargin = 0;
129 
130     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
131     for( sal_Int16 i=0; i < nAttrCount; i++ )
132     {
133         const OUString& rAttrName = xAttrList->getNameByIndex( i );
134         OUString aLocalName;
135         sal_uInt16 nPrefix =
136             GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
137                                                             &aLocalName );
138         const OUString& rValue = xAttrList->getValueByIndex( i );
139 
140         sal_Int32 nVal;
141         switch( rTokenMap.Get( nPrefix, aLocalName ) )
142         {
143         case XML_TOK_COLUMN_WIDTH:
144             {
145                 sal_Int32 nPos = rValue.indexOf( (sal_Unicode)'*' );
146                 if( nPos != -1 && nPos+1 == rValue.getLength() )
147                 {
148                     OUString sTmp( rValue.copy( 0, nPos ) );
149                     if( GetImport().GetMM100UnitConverter().
150                                         convertNumber( nVal, sTmp, 0, USHRT_MAX ) )
151                     aColumn.Width = nVal;
152                 }
153             }
154             break;
155         case XML_TOK_COLUMN_MARGIN_LEFT:
156             if( GetImport().GetMM100UnitConverter().
157                                         convertMeasure( nVal, rValue ) )
158                 aColumn.LeftMargin = nVal;
159             break;
160         case XML_TOK_COLUMN_MARGIN_RIGHT:
161 
162             if( GetImport().GetMM100UnitConverter().
163                                         convertMeasure( nVal, rValue ) )
164                 aColumn.RightMargin = nVal;
165             break;
166         default:
167             break;
168         }
169     }
170 }
171 
172 XMLTextColumnContext_Impl::~XMLTextColumnContext_Impl()
173 {
174 }
175 
176 // --------------------------------------------------------------------------
177 
178 class XMLTextColumnSepContext_Impl: public SvXMLImportContext
179 {
180     sal_Int32 nWidth;
181     sal_Int32 nColor;
182     sal_Int8 nHeight;
183     VerticalAlignment eVertAlign;
184 
185 
186 public:
187     TYPEINFO();
188 
189     XMLTextColumnSepContext_Impl( SvXMLImport& rImport, sal_uInt16 nPrfx,
190                                const OUString& rLName,
191                                const uno::Reference<
192                                     xml::sax::XAttributeList > & xAttrList,
193                                const SvXMLTokenMap& rTokenMap );
194 
195     virtual ~XMLTextColumnSepContext_Impl();
196 
197     sal_Int32 GetWidth() const { return nWidth; }
198     sal_Int32 GetColor() const { return  nColor; }
199     sal_Int8 GetHeight() const { return nHeight; }
200     VerticalAlignment GetVertAlign() const { return eVertAlign; }
201 };
202 
203 
204 TYPEINIT1( XMLTextColumnSepContext_Impl, SvXMLImportContext );
205 
206 XMLTextColumnSepContext_Impl::XMLTextColumnSepContext_Impl(
207                                SvXMLImport& rImport, sal_uInt16 nPrfx,
208                                const OUString& rLName,
209                                const uno::Reference<
210                                     xml::sax::XAttributeList > & xAttrList,
211                                const SvXMLTokenMap& rTokenMap ) :
212     SvXMLImportContext( rImport, nPrfx, rLName ),
213     nWidth( 2 ),
214     nColor( 0 ),
215     nHeight( 100 ),
216     eVertAlign( VerticalAlignment_TOP )
217 {
218     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
219     for( sal_Int16 i=0; i < nAttrCount; i++ )
220     {
221         const OUString& rAttrName = xAttrList->getNameByIndex( i );
222         OUString aLocalName;
223         sal_uInt16 nPrefix =
224             GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
225                                                             &aLocalName );
226         const OUString& rValue = xAttrList->getValueByIndex( i );
227 
228         sal_Int32 nVal;
229         switch( rTokenMap.Get( nPrefix, aLocalName ) )
230         {
231         case XML_TOK_COLUMN_SEP_WIDTH:
232             if( GetImport().GetMM100UnitConverter().
233                                 convertMeasure( nVal, rValue ) )
234                 nWidth = nVal;
235             break;
236         case XML_TOK_COLUMN_SEP_HEIGHT:
237             if( GetImport().GetMM100UnitConverter().
238                                         convertPercent( nVal, rValue ) &&
239                 nVal >=1 && nVal <= 100 )
240                 nHeight = (sal_Int8)nVal;
241             break;
242         case XML_TOK_COLUMN_SEP_COLOR:
243             {
244                 Color aColor;
245                 if( GetImport().GetMM100UnitConverter().
246                                             convertColor( aColor, rValue ) )
247                     nColor = (sal_Int32)aColor.GetColor();
248             }
249             break;
250         case XML_TOK_COLUMN_SEP_ALIGN:
251             {
252                 sal_uInt16 nAlign;
253                 if( GetImport().GetMM100UnitConverter().
254                                         convertEnum( nAlign, rValue,
255                                                      pXML_Sep_Align_Enum ) )
256                     eVertAlign = (VerticalAlignment)nAlign;
257             }
258             break;
259         }
260     }
261 }
262 
263 XMLTextColumnSepContext_Impl::~XMLTextColumnSepContext_Impl()
264 {
265 }
266 
267 // --------------------------------------------------------------------------
268 
269 typedef XMLTextColumnContext_Impl *XMLTextColumnContext_ImplPtr;
270 SV_DECL_PTRARR( XMLTextColumnsArray_Impl, XMLTextColumnContext_ImplPtr, 5, 5 )
271 
272 TYPEINIT1( XMLTextColumnsContext, XMLElementPropertyContext );
273 
274 XMLTextColumnsContext::XMLTextColumnsContext(
275                                 SvXMLImport& rImport, sal_uInt16 nPrfx,
276                                 const OUString& rLName,
277                                 const Reference< xml::sax::XAttributeList >&
278                                     xAttrList,
279                                 const XMLPropertyState& rProp,
280                                 ::std::vector< XMLPropertyState > &rProps )
281 :   XMLElementPropertyContext( rImport, nPrfx, rLName, rProp, rProps )
282 ,   sSeparatorLineIsOn(RTL_CONSTASCII_USTRINGPARAM("SeparatorLineIsOn"))
283 ,   sSeparatorLineWidth(RTL_CONSTASCII_USTRINGPARAM("SeparatorLineWidth"))
284 ,   sSeparatorLineColor(RTL_CONSTASCII_USTRINGPARAM("SeparatorLineColor"))
285 ,   sSeparatorLineRelativeHeight(RTL_CONSTASCII_USTRINGPARAM("SeparatorLineRelativeHeight"))
286 ,   sSeparatorLineVerticalAlignment(RTL_CONSTASCII_USTRINGPARAM("SeparatorLineVerticalAlignment"))
287 ,   sIsAutomatic(RTL_CONSTASCII_USTRINGPARAM("IsAutomatic"))
288 ,   sAutomaticDistance(RTL_CONSTASCII_USTRINGPARAM("AutomaticDistance"))
289 ,   pColumns( 0 )
290 ,   pColumnSep( 0 )
291 ,   pColumnAttrTokenMap( new SvXMLTokenMap(aColAttrTokenMap) )
292 ,   pColumnSepAttrTokenMap( new SvXMLTokenMap(aColSepAttrTokenMap) )
293 ,   nCount( 0 )
294 ,   bAutomatic( sal_False )
295 ,   nAutomaticDistance( 0 )
296 {
297     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
298     sal_Int32 nVal;
299     for( sal_Int16 i=0; i < nAttrCount; i++ )
300     {
301         const OUString& rAttrName = xAttrList->getNameByIndex( i );
302         OUString aLocalName;
303         sal_uInt16 nPrefix =
304             GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
305                                                             &aLocalName );
306         const OUString& rValue = xAttrList->getValueByIndex( i );
307         if( XML_NAMESPACE_FO == nPrefix )
308         {
309             if( IsXMLToken( aLocalName, XML_COLUMN_COUNT ) &&
310                 GetImport().GetMM100UnitConverter().
311                                 convertNumber( nVal, rValue, 0, SHRT_MAX ) )
312             {
313                 nCount = (sal_Int16)nVal;
314             }
315             else if( IsXMLToken( aLocalName, XML_COLUMN_GAP ) )
316             {
317                 bAutomatic = GetImport().GetMM100UnitConverter().
318                     convertMeasure( nAutomaticDistance, rValue );
319             }
320         }
321     }
322 }
323 
324 XMLTextColumnsContext::~XMLTextColumnsContext()
325 {
326     if( pColumns )
327     {
328         sal_uInt16 nColCount = pColumns->Count();
329         while( nColCount )
330         {
331             nColCount--;
332             XMLTextColumnContext_Impl *pColumn = (*pColumns)[nColCount];
333             pColumns->Remove( nColCount, 1 );
334             pColumn->ReleaseRef();
335         }
336     }
337     if( pColumnSep )
338         pColumnSep->ReleaseRef();
339 
340     delete pColumns;
341     delete pColumnAttrTokenMap;
342     delete pColumnSepAttrTokenMap;
343 }
344 
345 SvXMLImportContext *XMLTextColumnsContext::CreateChildContext(
346     sal_uInt16 nPrefix,
347     const OUString& rLocalName,
348     const uno::Reference< xml::sax::XAttributeList > & xAttrList )
349 {
350     SvXMLImportContext *pContext = 0;
351 
352     if( XML_NAMESPACE_STYLE == nPrefix &&
353         IsXMLToken( rLocalName, XML_COLUMN ) )
354     {
355         XMLTextColumnContext_Impl *pColumn =
356             new XMLTextColumnContext_Impl( GetImport(), nPrefix, rLocalName,
357                                            xAttrList, *pColumnAttrTokenMap );
358 
359         // add new tabstop to array of tabstops
360         if( !pColumns )
361             pColumns = new XMLTextColumnsArray_Impl;
362 
363         pColumns->Insert( pColumn, pColumns->Count() );
364         pColumn->AddRef();
365 
366         pContext = pColumn;
367     }
368     else if( XML_NAMESPACE_STYLE == nPrefix &&
369              IsXMLToken( rLocalName, XML_COLUMN_SEP ) )
370     {
371         pColumnSep =
372             new XMLTextColumnSepContext_Impl( GetImport(), nPrefix, rLocalName,
373                                            xAttrList, *pColumnSepAttrTokenMap );
374         pColumnSep->AddRef();
375 
376         pContext = pColumnSep;
377     }
378     else
379     {
380         pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
381     }
382 
383     return pContext;
384 }
385 
386 void XMLTextColumnsContext::EndElement( )
387 {
388     Reference<XMultiServiceFactory> xFactory(GetImport().GetModel(),UNO_QUERY);
389     if( !xFactory.is() )
390         return;
391 
392     Reference<XInterface> xIfc = xFactory->createInstance(
393         OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.text.TextColumns")));
394     if( !xIfc.is() )
395         return;
396 
397     Reference< XTextColumns > xColumns( xIfc, UNO_QUERY );
398     if ( 0 == nCount )
399     {
400         // zero columns = no columns -> 1 column
401         xColumns->setColumnCount( 1 );
402     }
403     else if( !bAutomatic && pColumns &&
404              pColumns->Count() == (sal_uInt16)nCount )
405     {
406         // if we have column descriptions, one per column, and we don't use
407         // automatic width, then set the column widths
408 
409         sal_Int32 nRelWidth = 0;
410         sal_uInt16 nColumnsWithWidth = 0;
411         sal_Int16 i;
412 
413         for( i = 0; i < nCount; i++ )
414         {
415             const TextColumn& rColumn =
416                 (*pColumns)[(sal_uInt16)i]->getTextColumn();
417             if( rColumn.Width > 0 )
418             {
419                 nRelWidth += rColumn.Width;
420                 nColumnsWithWidth++;
421             }
422         }
423         if( nColumnsWithWidth < nCount )
424         {
425             sal_Int32 nColWidth = 0==nRelWidth
426                                         ? USHRT_MAX / nCount
427                                         : nRelWidth / nColumnsWithWidth;
428 
429             for( i=0; i < nCount; i++ )
430             {
431                 TextColumn& rColumn =
432                     (*pColumns)[(sal_uInt16)i]->getTextColumn();
433                 if( rColumn.Width == 0 )
434                 {
435                     rColumn.Width = nColWidth;
436                     nRelWidth += rColumn.Width;
437                     if( 0 == --nColumnsWithWidth )
438                         break;
439                 }
440             }
441         }
442 
443         Sequence< TextColumn > aColumns( (sal_Int32)nCount );
444         TextColumn *pTextColumns = aColumns.getArray();
445         for( i=0; i < nCount; i++ )
446             *pTextColumns++ = (*pColumns)[(sal_uInt16)i]->getTextColumn();
447 
448         xColumns->setColumns( aColumns );
449     }
450     else
451     {
452         // only set column count (and let the columns be distributed
453         // automatically)
454 
455         xColumns->setColumnCount( nCount );
456     }
457 
458     Reference < XPropertySet > xPropSet( xColumns, UNO_QUERY );
459     if( xPropSet.is() )
460     {
461         Any aAny;
462         sal_Bool bOn = pColumnSep != 0;
463 
464         aAny.setValue( &bOn, ::getBooleanCppuType() );
465         xPropSet->setPropertyValue( sSeparatorLineIsOn, aAny );
466 
467         if( pColumnSep )
468         {
469             if( pColumnSep->GetWidth() )
470             {
471                 aAny <<= pColumnSep->GetWidth();
472                 xPropSet->setPropertyValue( sSeparatorLineWidth, aAny );
473             }
474             if( pColumnSep->GetHeight() )
475             {
476                 aAny <<= pColumnSep->GetHeight();
477                 xPropSet->setPropertyValue( sSeparatorLineRelativeHeight,
478                                             aAny );
479             }
480 
481 
482             aAny <<= pColumnSep->GetColor();
483             xPropSet->setPropertyValue( sSeparatorLineColor, aAny );
484 
485 
486             aAny <<= pColumnSep->GetVertAlign();
487             xPropSet->setPropertyValue( sSeparatorLineVerticalAlignment, aAny );
488         }
489 
490         // handle 'automatic columns': column distance
491         if( bAutomatic )
492         {
493             aAny <<= nAutomaticDistance;
494             xPropSet->setPropertyValue( sAutomaticDistance, aAny );
495         }
496     }
497 
498     aProp.maValue <<= xColumns;
499 
500     SetInsert( sal_True );
501     XMLElementPropertyContext::EndElement();
502 
503 }
504