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