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 #include "vbaborders.hxx" 20 21 #include <sal/macros.h> 22 #include <cppuhelper/implbase.hxx> 23 #include <ooo/vba/excel/XlBordersIndex.hpp> 24 #include <ooo/vba/excel/XlBorderWeight.hpp> 25 #include <ooo/vba/excel/XlLineStyle.hpp> 26 #include <ooo/vba/excel/XlColorIndex.hpp> 27 #include <com/sun/star/beans/XPropertySet.hpp> 28 #include <com/sun/star/table/TableBorder.hpp> 29 #include <com/sun/star/table/XColumnRowRange.hpp> 30 31 #include "vbapalette.hxx" 32 33 using namespace ::com::sun::star; 34 using namespace ::ooo::vba; 35 using namespace ::ooo::vba::excel; 36 37 typedef ::cppu::WeakImplHelper<container::XIndexAccess > RangeBorders_Base; 38 typedef InheritedHelperInterfaceWeakImpl<excel::XBorder > ScVbaBorder_Base; 39 40 // #TODO sort these indexes to match the order in which Excel iterates over the 41 // borders, the enumeration will match the order in this list 42 static const sal_Int16 supportedIndexTable[] = { XlBordersIndex::xlEdgeLeft, XlBordersIndex::xlEdgeTop, XlBordersIndex::xlEdgeBottom, XlBordersIndex::xlEdgeRight, XlBordersIndex::xlDiagonalDown, XlBordersIndex::xlDiagonalUp, XlBordersIndex::xlInsideVertical, XlBordersIndex::xlInsideHorizontal }; 43 44 static const char sTableBorder[] = "TableBorder"; 45 46 // Equiv widths in 1/100 mm 47 const static sal_Int32 OOLineThin = 35; 48 const static sal_Int32 OOLineMedium = 88; 49 const static sal_Int32 OOLineThick = 141; 50 const static sal_Int32 OOLineHairline = 2; 51 52 class ScVbaBorder : public ScVbaBorder_Base 53 { 54 private: 55 uno::Reference< beans::XPropertySet > m_xProps; 56 sal_Int32 const m_LineType; 57 ScVbaPalette m_Palette; 58 void setBorderLine( const table::BorderLine& rBorderLine ) 59 { 60 table::TableBorder aTableBorder; 61 m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder; 62 63 switch ( m_LineType ) 64 { 65 case XlBordersIndex::xlEdgeLeft: 66 aTableBorder.IsLeftLineValid = true; 67 aTableBorder.LeftLine= rBorderLine; 68 break; 69 case XlBordersIndex::xlEdgeTop: 70 aTableBorder.IsTopLineValid = true; 71 aTableBorder.TopLine = rBorderLine; 72 break; 73 74 case XlBordersIndex::xlEdgeBottom: 75 aTableBorder.IsBottomLineValid = true; 76 aTableBorder.BottomLine = rBorderLine; 77 break; 78 case XlBordersIndex::xlEdgeRight: 79 aTableBorder.IsRightLineValid = true; 80 aTableBorder.RightLine = rBorderLine; 81 break; 82 case XlBordersIndex::xlInsideVertical: 83 aTableBorder.IsVerticalLineValid = true; 84 aTableBorder.VerticalLine = rBorderLine; 85 break; 86 case XlBordersIndex::xlInsideHorizontal: 87 aTableBorder.IsHorizontalLineValid = true; 88 aTableBorder.HorizontalLine = rBorderLine; 89 break; 90 case XlBordersIndex::xlDiagonalDown: 91 case XlBordersIndex::xlDiagonalUp: 92 // #TODO have to ignore at the momement, would be 93 // nice to investigate what we can do here 94 break; 95 default: 96 return; 97 } 98 m_xProps->setPropertyValue( sTableBorder, uno::makeAny(aTableBorder) ); 99 } 100 101 bool getBorderLine( table::BorderLine& rBorderLine ) 102 { 103 table::TableBorder aTableBorder; 104 m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder; 105 switch ( m_LineType ) 106 { 107 case XlBordersIndex::xlEdgeLeft: 108 if ( aTableBorder.IsLeftLineValid ) 109 rBorderLine = aTableBorder.LeftLine; 110 break; 111 case XlBordersIndex::xlEdgeTop: 112 if ( aTableBorder.IsTopLineValid ) 113 rBorderLine = aTableBorder.TopLine; 114 break; 115 116 case XlBordersIndex::xlEdgeBottom: 117 if ( aTableBorder.IsBottomLineValid ) 118 rBorderLine = aTableBorder.BottomLine; 119 break; 120 case XlBordersIndex::xlEdgeRight: 121 if ( aTableBorder.IsRightLineValid ) 122 rBorderLine = aTableBorder.RightLine; 123 break; 124 case XlBordersIndex::xlInsideVertical: 125 if ( aTableBorder.IsVerticalLineValid ) 126 rBorderLine = aTableBorder.VerticalLine; 127 break; 128 case XlBordersIndex::xlInsideHorizontal: 129 if ( aTableBorder.IsHorizontalLineValid ) 130 rBorderLine = aTableBorder.HorizontalLine; 131 break; 132 133 case XlBordersIndex::xlDiagonalDown: 134 case XlBordersIndex::xlDiagonalUp: 135 // #TODO have to ignore at the momement, would be 136 // nice to investigate what we can do here 137 break; 138 default: 139 return false; 140 } 141 return true; 142 } 143 144 protected: 145 virtual OUString getServiceImplName() override 146 { 147 return OUString("ScVbaBorder"); 148 } 149 virtual css::uno::Sequence<OUString> getServiceNames() override 150 { 151 static uno::Sequence< OUString > const aServiceNames 152 { 153 "ooo.vba.excel.Border" 154 }; 155 return aServiceNames; 156 } 157 public: 158 ScVbaBorder( const uno::Reference< beans::XPropertySet > & xProps, const uno::Reference< uno::XComponentContext >& xContext, sal_Int32 lineType, const ScVbaPalette& rPalette) : ScVbaBorder_Base( uno::Reference< XHelperInterface >( xProps, uno::UNO_QUERY ), xContext ), m_xProps( xProps ), m_LineType( lineType ), m_Palette( rPalette ) {} 159 160 // XBorder 161 uno::Any SAL_CALL getColor() override 162 { 163 table::BorderLine aBorderLine; 164 if ( getBorderLine( aBorderLine ) ) 165 return uno::makeAny( OORGBToXLRGB( Color(aBorderLine.Color) ) ); 166 throw uno::RuntimeException("No Implementation available" ); 167 } 168 void SAL_CALL setColor( const uno::Any& _color ) override 169 { 170 sal_Int32 nColor = 0; 171 _color >>= nColor; 172 table::BorderLine aBorderLine; 173 if ( !getBorderLine( aBorderLine ) ) 174 throw uno::RuntimeException("No Implementation available" ); 175 176 aBorderLine.Color = XLRGBToOORGB( nColor ); 177 setBorderLine( aBorderLine ); 178 179 } 180 181 uno::Any SAL_CALL getColorIndex() override 182 { 183 sal_Int32 nColor = 0; 184 XLRGBToOORGB( getColor() ) >>= nColor; 185 uno::Reference< container::XIndexAccess > xIndex = m_Palette.getPalette(); 186 sal_Int32 nElems = xIndex->getCount(); 187 sal_Int32 nIndex = -1; 188 for ( sal_Int32 count=0; count<nElems; ++count ) 189 { 190 sal_Int32 nPaletteColor = 0; 191 xIndex->getByIndex( count ) >>= nPaletteColor; 192 if ( nPaletteColor == nColor ) 193 { 194 nIndex = count + 1; 195 break; 196 } 197 } 198 return uno::makeAny(nIndex); 199 } 200 201 void SAL_CALL setColorIndex( const uno::Any& _colorindex ) override 202 { 203 sal_Int32 nColor = 0; 204 _colorindex >>= nColor; 205 if ( !nColor || nColor == XlColorIndex::xlColorIndexAutomatic ) 206 nColor = 1; 207 setColor( OORGBToXLRGB( m_Palette.getPalette()->getByIndex( --nColor ) ) ); 208 } 209 uno::Any SAL_CALL getWeight() override 210 { 211 table::BorderLine aBorderLine; 212 if ( getBorderLine( aBorderLine ) ) 213 { 214 switch ( aBorderLine.OuterLineWidth ) 215 { 216 case 0: // Thin = default OO thickness 217 case OOLineThin: 218 return uno::makeAny( XlBorderWeight::xlThin ); 219 case OOLineMedium: 220 return uno::makeAny( XlBorderWeight::xlMedium ); 221 case OOLineThick: 222 return uno::makeAny( XlBorderWeight::xlThick ); 223 case OOLineHairline: 224 return uno::makeAny( XlBorderWeight::xlHairline ); 225 default: 226 break; 227 } 228 } 229 throw uno::RuntimeException("Method failed" ); 230 } 231 void SAL_CALL setWeight( const uno::Any& _weight ) override 232 { 233 sal_Int32 nWeight = 0; 234 _weight >>= nWeight; 235 table::BorderLine aBorderLine; 236 if ( !getBorderLine( aBorderLine ) ) 237 throw uno::RuntimeException("Method failed" ); 238 239 switch ( nWeight ) 240 { 241 case XlBorderWeight::xlThin: 242 aBorderLine.OuterLineWidth = OOLineThin; 243 break; 244 case XlBorderWeight::xlMedium: 245 aBorderLine.OuterLineWidth = OOLineMedium; 246 break; 247 case XlBorderWeight::xlThick: 248 aBorderLine.OuterLineWidth = OOLineThick; 249 break; 250 case XlBorderWeight::xlHairline: 251 aBorderLine.OuterLineWidth = OOLineHairline; 252 break; 253 default: 254 throw uno::RuntimeException("Bad param" ); 255 } 256 setBorderLine( aBorderLine ); 257 258 } 259 260 void SAL_CALL setTintAndShade( const uno::Any& /*rAny*/ ) override 261 { 262 // TODO implement 263 } 264 uno::Any SAL_CALL getTintAndShade() override 265 { 266 // TODO implement 267 return uno::makeAny(static_cast<double>(0)); 268 } 269 270 uno::Any SAL_CALL getLineStyle() override 271 { 272 // always return xlContinuous; 273 return uno::makeAny( XlLineStyle::xlContinuous ); 274 } 275 void SAL_CALL setLineStyle( const uno::Any& _linestyle ) override 276 { 277 // Urk no choice but to silently ignore we don't support this attribute 278 // #TODO would be nice to support the excel line styles 279 sal_Int32 nLineStyle = 0; 280 _linestyle >>= nLineStyle; 281 table::BorderLine aBorderLine; 282 if ( !getBorderLine( aBorderLine ) ) 283 throw uno::RuntimeException("Method failed" ); 284 285 switch ( nLineStyle ) 286 { 287 case XlLineStyle::xlContinuous: 288 case XlLineStyle::xlDash: 289 case XlLineStyle::xlDashDot: 290 case XlLineStyle::xlDashDotDot: 291 case XlLineStyle::xlDot: 292 case XlLineStyle::xlDouble: 293 case XlLineStyle::xlLineStyleNone: 294 case XlLineStyle::xlSlantDashDot: 295 break; 296 default: 297 throw uno::RuntimeException("Bad param" ); 298 } 299 setBorderLine( aBorderLine ); 300 301 } 302 }; 303 304 class RangeBorders : public RangeBorders_Base 305 { 306 private: 307 uno::Reference< table::XCellRange > m_xRange; 308 uno::Reference< uno::XComponentContext > m_xContext; 309 ScVbaPalette m_Palette; 310 sal_Int32 getTableIndex( sal_Int32 nConst ) 311 { 312 // okay return position of the index in the table 313 sal_Int32 nIndexes = getCount(); 314 sal_Int32 realIndex = 0; 315 const sal_Int16* pTableEntry = supportedIndexTable; 316 for ( ; realIndex < nIndexes; ++realIndex, ++pTableEntry ) 317 { 318 if ( *pTableEntry == nConst ) 319 return realIndex; 320 } 321 return getCount(); // error condition 322 } 323 public: 324 RangeBorders( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< uno::XComponentContext > & xContext, const ScVbaPalette& rPalette ) : m_xRange( xRange ), m_xContext( xContext ), m_Palette( rPalette ) 325 { 326 } 327 // XIndexAccess 328 virtual ::sal_Int32 SAL_CALL getCount( ) override 329 { 330 return SAL_N_ELEMENTS( supportedIndexTable ); 331 } 332 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override 333 { 334 335 sal_Int32 nIndex = getTableIndex( Index ); 336 if ( nIndex >= 0 && nIndex < getCount() ) 337 { 338 uno::Reference< beans::XPropertySet > xProps( m_xRange, uno::UNO_QUERY_THROW ); 339 return uno::makeAny( uno::Reference< excel::XBorder >( new ScVbaBorder( xProps, m_xContext, supportedIndexTable[ nIndex ], m_Palette )) ); 340 } 341 throw lang::IndexOutOfBoundsException(); 342 } 343 virtual uno::Type SAL_CALL getElementType( ) override 344 { 345 return cppu::UnoType<excel::XBorder>::get(); 346 } 347 virtual sal_Bool SAL_CALL hasElements( ) override 348 { 349 return true; 350 } 351 }; 352 353 static uno::Reference< container::XIndexAccess > 354 rangeToBorderIndexAccess( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< uno::XComponentContext > & xContext, const ScVbaPalette& rPalette ) 355 { 356 return new RangeBorders( xRange, xContext, rPalette ); 357 } 358 359 class RangeBorderEnumWrapper : public EnumerationHelper_BASE 360 { 361 uno::Reference<container::XIndexAccess > m_xIndexAccess; 362 sal_Int32 nIndex; 363 public: 364 explicit RangeBorderEnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) : m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {} 365 virtual sal_Bool SAL_CALL hasMoreElements( ) override 366 { 367 return ( nIndex < m_xIndexAccess->getCount() ); 368 } 369 370 virtual uno::Any SAL_CALL nextElement( ) override 371 { 372 if ( nIndex < m_xIndexAccess->getCount() ) 373 return m_xIndexAccess->getByIndex( nIndex++ ); 374 throw container::NoSuchElementException(); 375 } 376 }; 377 378 ScVbaBorders::ScVbaBorders( const uno::Reference< XHelperInterface >& xParent, 379 const uno::Reference< uno::XComponentContext > & xContext, 380 const uno::Reference< table::XCellRange >& xRange, 381 const ScVbaPalette& rPalette ) 382 : ScVbaBorders_BASE( xParent, xContext, rangeToBorderIndexAccess( xRange ,xContext, rPalette ) ), bRangeIsSingleCell( false ) 383 { 384 uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, uno::UNO_QUERY_THROW ); 385 if ( xColumnRowRange->getRows()->getCount() == 1 && xColumnRowRange->getColumns()->getCount() == 1 ) 386 bRangeIsSingleCell = true; 387 m_xProps.set( xRange, uno::UNO_QUERY_THROW ); 388 } 389 390 uno::Reference< container::XEnumeration > 391 ScVbaBorders::createEnumeration() 392 { 393 return new RangeBorderEnumWrapper( m_xIndexAccess ); 394 } 395 396 uno::Any 397 ScVbaBorders::createCollectionObject( const css::uno::Any& aSource ) 398 { 399 return aSource; // it's already a Border object 400 } 401 402 uno::Type 403 ScVbaBorders::getElementType() 404 { 405 return cppu::UnoType<excel::XBorders>::get(); 406 } 407 408 uno::Any 409 ScVbaBorders::getItemByIntIndex( const sal_Int32 nIndex ) 410 { 411 return createCollectionObject( m_xIndexAccess->getByIndex( nIndex ) ); 412 } 413 414 uno::Any SAL_CALL ScVbaBorders::getColor() 415 { 416 sal_Int32 count = getCount(); 417 uno::Any color; 418 for( sal_Int32 i = 0; i < count ; i++ ) 419 { 420 if( XlBordersIndex::xlDiagonalDown != supportedIndexTable[i] && XlBordersIndex::xlDiagonalUp != supportedIndexTable[i] ) 421 { 422 uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); 423 if( color.hasValue() ) 424 { 425 if( color != xBorder->getColor() ) 426 return uno::makeAny( uno::Reference< uno::XInterface >() ); 427 } 428 else 429 color = xBorder->getColor(); 430 } 431 } 432 return color; 433 } 434 void SAL_CALL ScVbaBorders::setColor( const uno::Any& _color ) 435 { 436 sal_Int32 count = getCount(); 437 for( sal_Int32 i = 0; i < count ; i++ ) 438 { 439 uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); 440 xBorder->setColor( _color ); 441 } 442 } 443 uno::Any SAL_CALL ScVbaBorders::getColorIndex() 444 { 445 sal_Int32 count = getCount(); 446 uno::Any nColorIndex; 447 for( sal_Int32 i = 0; i < count ; i++ ) 448 { 449 if( XlBordersIndex::xlDiagonalDown != supportedIndexTable[i] && XlBordersIndex::xlDiagonalUp != supportedIndexTable[i] ) 450 { 451 uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); 452 if( nColorIndex.hasValue() ) 453 { 454 if( nColorIndex != xBorder->getColorIndex() ) 455 return uno::makeAny( uno::Reference< uno::XInterface >() ); 456 } 457 else 458 nColorIndex = xBorder->getColorIndex(); 459 } 460 } 461 return nColorIndex; 462 } 463 void SAL_CALL ScVbaBorders::setColorIndex( const uno::Any& _colorindex ) 464 { 465 sal_Int32 count = getCount(); 466 for( sal_Int32 i = 0; i < count ; i++ ) 467 { 468 uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); 469 xBorder->setColorIndex( _colorindex ); 470 } 471 } 472 473 static bool 474 lcl_areAllLineWidthsSame( const table::TableBorder& maTableBorder, bool bIsCell ) 475 { 476 477 bool bRes = false; 478 if (bIsCell) 479 { 480 bRes = ((maTableBorder.TopLine.OuterLineWidth == maTableBorder.BottomLine.OuterLineWidth) && 481 (maTableBorder.TopLine.OuterLineWidth == maTableBorder.LeftLine.OuterLineWidth) && 482 (maTableBorder.TopLine.OuterLineWidth == maTableBorder.RightLine.OuterLineWidth)); 483 } 484 else 485 { 486 bRes = ((maTableBorder.TopLine.OuterLineWidth == maTableBorder.BottomLine.OuterLineWidth) && 487 (maTableBorder.TopLine.OuterLineWidth == maTableBorder.LeftLine.OuterLineWidth) && 488 (maTableBorder.TopLine.OuterLineWidth == maTableBorder.HorizontalLine.OuterLineWidth) && 489 (maTableBorder.TopLine.OuterLineWidth == maTableBorder.VerticalLine.OuterLineWidth) && 490 (maTableBorder.TopLine.OuterLineWidth == maTableBorder.RightLine.OuterLineWidth)); 491 } 492 return bRes; 493 } 494 495 uno::Any SAL_CALL ScVbaBorders::getLineStyle() 496 { 497 table::TableBorder aTableBorder; 498 m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder; 499 500 sal_Int32 aLinestyle = XlLineStyle::xlLineStyleNone; 501 502 if ( lcl_areAllLineWidthsSame( aTableBorder, bRangeIsSingleCell )) 503 { 504 if (aTableBorder.TopLine.LineDistance != 0) 505 { 506 aLinestyle = XlLineStyle::xlDouble; 507 } 508 else if ( aTableBorder.TopLine.OuterLineWidth != 0 ) 509 { 510 aLinestyle = XlLineStyle::xlContinuous; 511 } 512 } 513 return uno::makeAny( aLinestyle ); 514 } 515 void SAL_CALL ScVbaBorders::setLineStyle( const uno::Any& _linestyle ) 516 { 517 sal_Int32 count = getCount(); 518 for( sal_Int32 i = 0; i < count ; i++ ) 519 { 520 uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); 521 xBorder->setLineStyle( _linestyle ); 522 } 523 } 524 uno::Any SAL_CALL ScVbaBorders::getWeight() 525 { 526 sal_Int32 count = getCount(); 527 uno::Any weight; 528 for( sal_Int32 i = 0; i < count ; i++ ) 529 { 530 if( XlBordersIndex::xlDiagonalDown != supportedIndexTable[i] && XlBordersIndex::xlDiagonalUp != supportedIndexTable[i] ) 531 { 532 uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); 533 if( weight.hasValue() ) 534 { 535 if( weight != xBorder->getWeight() ) 536 return uno::makeAny( uno::Reference< uno::XInterface >() ); 537 } 538 else 539 weight = xBorder->getWeight(); 540 } 541 } 542 return weight; 543 } 544 545 uno::Any SAL_CALL ScVbaBorders::getTintAndShade() 546 { 547 // TODO implement 548 return uno::makeAny(static_cast<double>(0)); 549 } 550 551 void SAL_CALL ScVbaBorders::setTintAndShade(const uno::Any& /*rAny*/) 552 { 553 // TODO implement 554 } 555 556 void SAL_CALL ScVbaBorders::setWeight( const uno::Any& _weight ) 557 { 558 sal_Int32 count = getCount(); 559 for( sal_Int32 i = 0; i < count ; i++ ) 560 { 561 uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW ); 562 xBorder->setWeight( _weight ); 563 } 564 } 565 566 OUString 567 ScVbaBorders::getServiceImplName() 568 { 569 return OUString("ScVbaBorders"); 570 } 571 572 uno::Sequence< OUString > 573 ScVbaBorders::getServiceNames() 574 { 575 static uno::Sequence< OUString > const aServiceNames 576 { 577 "ooo.vba.excel.Borders" 578 }; 579 return aServiceNames; 580 } 581 582 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 583
