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