1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #include "vbaborders.hxx"
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/XCellRange.hpp>
30 #include <com/sun/star/table/XColumnRowRange.hpp>
33 #include "vbapalette.hxx"
35 using namespace ::com::sun::star
;
36 using namespace ::ooo::vba
;
37 using namespace ::ooo::vba::excel
;
39 typedef ::cppu::WeakImplHelper
<container::XIndexAccess
> RangeBorders_Base
;
40 typedef InheritedHelperInterfaceWeakImpl
<excel::XBorder
> ScVbaBorder_Base
;
42 // #TODO sort these indexes to match the order in which Excel iterates over the
43 // borders, the enumeration will match the order in this list
44 const sal_Int16 supportedIndexTable
[] = { XlBordersIndex::xlEdgeLeft
, XlBordersIndex::xlEdgeTop
, XlBordersIndex::xlEdgeBottom
, XlBordersIndex::xlEdgeRight
, XlBordersIndex::xlDiagonalDown
, XlBordersIndex::xlDiagonalUp
, XlBordersIndex::xlInsideVertical
, XlBordersIndex::xlInsideHorizontal
};
46 constexpr OUString sTableBorder
= u
"TableBorder"_ustr
;
48 // Equiv widths in 1/100 mm
49 const sal_Int32 OOLineThin
= 26;
50 const sal_Int32 OOLineMedium
= 88;
51 const sal_Int32 OOLineThick
= 141;
52 const sal_Int32 OOLineHairline
= 2;
56 class ScVbaBorder
: public ScVbaBorder_Base
59 uno::Reference
< beans::XPropertySet
> m_xProps
;
61 ScVbaPalette m_Palette
;
62 void setBorderLine( const table::BorderLine
& rBorderLine
)
64 table::TableBorder aTableBorder
;
65 m_xProps
->getPropertyValue( sTableBorder
) >>= aTableBorder
;
69 case XlBordersIndex::xlEdgeLeft
:
70 aTableBorder
.IsLeftLineValid
= true;
71 aTableBorder
.LeftLine
= rBorderLine
;
73 case XlBordersIndex::xlEdgeTop
:
74 aTableBorder
.IsTopLineValid
= true;
75 aTableBorder
.TopLine
= rBorderLine
;
78 case XlBordersIndex::xlEdgeBottom
:
79 aTableBorder
.IsBottomLineValid
= true;
80 aTableBorder
.BottomLine
= rBorderLine
;
82 case XlBordersIndex::xlEdgeRight
:
83 aTableBorder
.IsRightLineValid
= true;
84 aTableBorder
.RightLine
= rBorderLine
;
86 case XlBordersIndex::xlInsideVertical
:
87 aTableBorder
.IsVerticalLineValid
= true;
88 aTableBorder
.VerticalLine
= rBorderLine
;
90 case XlBordersIndex::xlInsideHorizontal
:
91 aTableBorder
.IsHorizontalLineValid
= true;
92 aTableBorder
.HorizontalLine
= rBorderLine
;
94 case XlBordersIndex::xlDiagonalDown
:
95 case XlBordersIndex::xlDiagonalUp
:
96 // #TODO have to ignore at the moment, would be
97 // nice to investigate what we can do here
102 m_xProps
->setPropertyValue( sTableBorder
, uno::Any(aTableBorder
) );
105 bool getBorderLine( table::BorderLine
& rBorderLine
)
107 table::TableBorder aTableBorder
;
108 m_xProps
->getPropertyValue( sTableBorder
) >>= aTableBorder
;
109 switch ( m_LineType
)
111 case XlBordersIndex::xlEdgeLeft
:
112 if ( aTableBorder
.IsLeftLineValid
)
113 rBorderLine
= aTableBorder
.LeftLine
;
115 case XlBordersIndex::xlEdgeTop
:
116 if ( aTableBorder
.IsTopLineValid
)
117 rBorderLine
= aTableBorder
.TopLine
;
120 case XlBordersIndex::xlEdgeBottom
:
121 if ( aTableBorder
.IsBottomLineValid
)
122 rBorderLine
= aTableBorder
.BottomLine
;
124 case XlBordersIndex::xlEdgeRight
:
125 if ( aTableBorder
.IsRightLineValid
)
126 rBorderLine
= aTableBorder
.RightLine
;
128 case XlBordersIndex::xlInsideVertical
:
129 if ( aTableBorder
.IsVerticalLineValid
)
130 rBorderLine
= aTableBorder
.VerticalLine
;
132 case XlBordersIndex::xlInsideHorizontal
:
133 if ( aTableBorder
.IsHorizontalLineValid
)
134 rBorderLine
= aTableBorder
.HorizontalLine
;
137 case XlBordersIndex::xlDiagonalDown
:
138 case XlBordersIndex::xlDiagonalUp
:
139 // #TODO have to ignore at the moment, would be
140 // nice to investigate what we can do here
149 virtual OUString
getServiceImplName() override
151 return u
"ScVbaBorder"_ustr
;
153 virtual css::uno::Sequence
<OUString
> getServiceNames() override
155 static uno::Sequence
< OUString
> const aServiceNames
157 u
"ooo.vba.excel.Border"_ustr
159 return aServiceNames
;
162 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
) {}
165 uno::Any SAL_CALL
getColor() override
167 table::BorderLine aBorderLine
;
168 if ( getBorderLine( aBorderLine
) )
169 return uno::Any( OORGBToXLRGB( Color(ColorTransparency
, aBorderLine
.Color
) ) );
170 throw uno::RuntimeException(u
"No Implementation available"_ustr
);
172 void SAL_CALL
setColor( const uno::Any
& _color
) override
174 sal_Int32 nColor
= 0;
176 table::BorderLine aBorderLine
;
177 if ( !getBorderLine( aBorderLine
) )
178 throw uno::RuntimeException(u
"No Implementation available"_ustr
);
180 aBorderLine
.Color
= XLRGBToOORGB( nColor
);
181 setBorderLine( aBorderLine
);
185 uno::Any SAL_CALL
getColorIndex() override
187 sal_Int32 nColor
= 0;
188 XLRGBToOORGB( getColor() ) >>= nColor
;
189 uno::Reference
< container::XIndexAccess
> xIndex
= m_Palette
.getPalette();
190 sal_Int32 nElems
= xIndex
->getCount();
191 sal_Int32 nIndex
= -1;
192 for ( sal_Int32 count
=0; count
<nElems
; ++count
)
194 sal_Int32 nPaletteColor
= 0;
195 xIndex
->getByIndex( count
) >>= nPaletteColor
;
196 if ( nPaletteColor
== nColor
)
202 return uno::Any(nIndex
);
205 void SAL_CALL
setColorIndex( const uno::Any
& _colorindex
) override
207 sal_Int32 nColor
= 0;
208 _colorindex
>>= nColor
;
209 if ( !nColor
|| nColor
== XlColorIndex::xlColorIndexAutomatic
)
211 setColor( OORGBToXLRGB( m_Palette
.getPalette()->getByIndex( --nColor
) ) );
213 uno::Any SAL_CALL
getWeight() override
215 table::BorderLine aBorderLine
;
216 if ( getBorderLine( aBorderLine
) )
218 switch ( aBorderLine
.OuterLineWidth
)
220 case 0: // Thin = default OO thickness
222 return uno::Any( XlBorderWeight::xlThin
);
224 return uno::Any( XlBorderWeight::xlMedium
);
226 return uno::Any( XlBorderWeight::xlThick
);
228 return uno::Any( XlBorderWeight::xlHairline
);
233 throw uno::RuntimeException(u
"Method failed"_ustr
);
235 void SAL_CALL
setWeight( const uno::Any
& _weight
) override
237 sal_Int32 nWeight
= 0;
239 table::BorderLine aBorderLine
;
240 if ( !getBorderLine( aBorderLine
) )
241 throw uno::RuntimeException(u
"Method failed"_ustr
);
245 case XlBorderWeight::xlThin
:
246 aBorderLine
.OuterLineWidth
= OOLineThin
;
248 case XlBorderWeight::xlMedium
:
249 aBorderLine
.OuterLineWidth
= OOLineMedium
;
251 case XlBorderWeight::xlThick
:
252 aBorderLine
.OuterLineWidth
= OOLineThick
;
254 case XlBorderWeight::xlHairline
:
255 aBorderLine
.OuterLineWidth
= OOLineHairline
;
258 throw uno::RuntimeException(u
"Bad param"_ustr
);
260 setBorderLine( aBorderLine
);
264 void SAL_CALL
setTintAndShade( const uno::Any
& /*rAny*/ ) override
268 uno::Any SAL_CALL
getTintAndShade() override
271 return uno::Any(static_cast<double>(0));
274 uno::Any SAL_CALL
getLineStyle() override
276 // always return xlContinuous;
277 return uno::Any( XlLineStyle::xlContinuous
);
279 void SAL_CALL
setLineStyle( const uno::Any
& _linestyle
) override
281 // Urk no choice but to silently ignore we don't support this attribute
282 // #TODO would be nice to support the excel line styles
283 sal_Int32 nLineStyle
= 0;
284 _linestyle
>>= nLineStyle
;
285 table::BorderLine aBorderLine
;
286 if ( !getBorderLine( aBorderLine
) )
287 throw uno::RuntimeException(u
"Method failed"_ustr
);
289 switch ( nLineStyle
)
291 case XlLineStyle::xlContinuous
:
292 case XlLineStyle::xlDash
:
293 case XlLineStyle::xlDashDot
:
294 case XlLineStyle::xlDashDotDot
:
295 case XlLineStyle::xlDot
:
296 case XlLineStyle::xlDouble
:
297 case XlLineStyle::xlLineStyleNone
:
298 case XlLineStyle::xlSlantDashDot
:
301 throw uno::RuntimeException(u
"Bad param"_ustr
);
303 setBorderLine( aBorderLine
);
308 class RangeBorders
: public RangeBorders_Base
311 uno::Reference
< table::XCellRange
> m_xRange
;
312 uno::Reference
< uno::XComponentContext
> m_xContext
;
313 ScVbaPalette m_Palette
;
314 sal_Int32
getTableIndex( sal_Int32 nConst
)
316 // okay return position of the index in the table
317 sal_Int32 nIndexes
= getCount();
318 sal_Int32 realIndex
= 0;
319 const sal_Int16
* pTableEntry
= supportedIndexTable
;
320 for ( ; realIndex
< nIndexes
; ++realIndex
, ++pTableEntry
)
322 if ( *pTableEntry
== nConst
)
325 return getCount(); // error condition
328 RangeBorders( uno::Reference
< table::XCellRange
> xRange
, uno::Reference
< uno::XComponentContext
> xContext
, const ScVbaPalette
& rPalette
) : m_xRange(std::move( xRange
)), m_xContext(std::move( xContext
)), m_Palette( rPalette
)
332 virtual ::sal_Int32 SAL_CALL
getCount( ) override
334 return SAL_N_ELEMENTS( supportedIndexTable
);
336 virtual uno::Any SAL_CALL
getByIndex( ::sal_Int32 Index
) override
339 sal_Int32 nIndex
= getTableIndex( Index
);
340 if ( nIndex
>= 0 && nIndex
< getCount() )
342 uno::Reference
< beans::XPropertySet
> xProps( m_xRange
, uno::UNO_QUERY_THROW
);
343 return uno::Any( uno::Reference
< excel::XBorder
>( new ScVbaBorder( xProps
, m_xContext
, supportedIndexTable
[ nIndex
], m_Palette
)) );
345 throw lang::IndexOutOfBoundsException();
347 virtual uno::Type SAL_CALL
getElementType( ) override
349 return cppu::UnoType
<excel::XBorder
>::get();
351 virtual sal_Bool SAL_CALL
hasElements( ) override
359 static uno::Reference
< container::XIndexAccess
>
360 rangeToBorderIndexAccess( const uno::Reference
< table::XCellRange
>& xRange
, const uno::Reference
< uno::XComponentContext
> & xContext
, const ScVbaPalette
& rPalette
)
362 return new RangeBorders( xRange
, xContext
, rPalette
);
367 class RangeBorderEnumWrapper
: public EnumerationHelper_BASE
369 uno::Reference
<container::XIndexAccess
> m_xIndexAccess
;
372 explicit RangeBorderEnumWrapper( uno::Reference
< container::XIndexAccess
> xIndexAccess
) : m_xIndexAccess(std::move( xIndexAccess
)), m_nIndex( 0 ) {}
373 virtual sal_Bool SAL_CALL
hasMoreElements( ) override
375 return ( m_nIndex
< m_xIndexAccess
->getCount() );
378 virtual uno::Any SAL_CALL
nextElement( ) override
380 if ( m_nIndex
< m_xIndexAccess
->getCount() )
381 return m_xIndexAccess
->getByIndex( m_nIndex
++ );
382 throw container::NoSuchElementException();
388 ScVbaBorders::ScVbaBorders( const uno::Reference
< XHelperInterface
>& xParent
,
389 const uno::Reference
< uno::XComponentContext
> & xContext
,
390 const uno::Reference
< table::XCellRange
>& xRange
,
391 const ScVbaPalette
& rPalette
)
392 : ScVbaBorders_BASE( xParent
, xContext
, rangeToBorderIndexAccess( xRange
,xContext
, rPalette
) ), bRangeIsSingleCell( false )
394 uno::Reference
< table::XColumnRowRange
> xColumnRowRange(xRange
, uno::UNO_QUERY_THROW
);
395 if ( xColumnRowRange
->getRows()->getCount() == 1 && xColumnRowRange
->getColumns()->getCount() == 1 )
396 bRangeIsSingleCell
= true;
397 m_xProps
.set( xRange
, uno::UNO_QUERY_THROW
);
400 uno::Reference
< container::XEnumeration
>
401 ScVbaBorders::createEnumeration()
403 return new RangeBorderEnumWrapper( m_xIndexAccess
);
407 ScVbaBorders::createCollectionObject( const css::uno::Any
& aSource
)
409 return aSource
; // it's already a Border object
413 ScVbaBorders::getElementType()
415 return cppu::UnoType
<excel::XBorders
>::get();
419 ScVbaBorders::getItemByIntIndex( const sal_Int32 nIndex
)
421 return createCollectionObject( m_xIndexAccess
->getByIndex( nIndex
) );
424 uno::Any SAL_CALL
ScVbaBorders::getColor()
426 sal_Int32 count
= getCount();
428 for( sal_Int32 i
= 0; i
< count
; i
++ )
430 if( XlBordersIndex::xlDiagonalDown
!= supportedIndexTable
[i
] && XlBordersIndex::xlDiagonalUp
!= supportedIndexTable
[i
] )
432 uno::Reference
< XBorder
> xBorder( getItemByIntIndex( supportedIndexTable
[i
] ), uno::UNO_QUERY_THROW
);
433 if( color
.hasValue() )
435 if( color
!= xBorder
->getColor() )
436 return uno::Any( uno::Reference
< uno::XInterface
>() );
439 color
= xBorder
->getColor();
444 void SAL_CALL
ScVbaBorders::setColor( const uno::Any
& _color
)
446 sal_Int32 count
= getCount();
447 for( sal_Int32 i
= 0; i
< count
; i
++ )
449 uno::Reference
< XBorder
> xBorder( getItemByIntIndex( supportedIndexTable
[i
] ), uno::UNO_QUERY_THROW
);
450 xBorder
->setColor( _color
);
453 uno::Any SAL_CALL
ScVbaBorders::getColorIndex()
455 sal_Int32 count
= getCount();
456 uno::Any nColorIndex
;
457 for( sal_Int32 i
= 0; i
< count
; i
++ )
459 if( XlBordersIndex::xlDiagonalDown
!= supportedIndexTable
[i
] && XlBordersIndex::xlDiagonalUp
!= supportedIndexTable
[i
] )
461 uno::Reference
< XBorder
> xBorder( getItemByIntIndex( supportedIndexTable
[i
] ), uno::UNO_QUERY_THROW
);
462 if( nColorIndex
.hasValue() )
464 if( nColorIndex
!= xBorder
->getColorIndex() )
465 return uno::Any( uno::Reference
< uno::XInterface
>() );
468 nColorIndex
= xBorder
->getColorIndex();
473 void SAL_CALL
ScVbaBorders::setColorIndex( const uno::Any
& _colorindex
)
475 sal_Int32 count
= getCount();
476 for( sal_Int32 i
= 0; i
< count
; i
++ )
478 uno::Reference
< XBorder
> xBorder( getItemByIntIndex( supportedIndexTable
[i
] ), uno::UNO_QUERY_THROW
);
479 xBorder
->setColorIndex( _colorindex
);
484 lcl_areAllLineWidthsSame( const table::TableBorder
& maTableBorder
, bool bIsCell
)
490 bRes
= ((maTableBorder
.TopLine
.OuterLineWidth
== maTableBorder
.BottomLine
.OuterLineWidth
) &&
491 (maTableBorder
.TopLine
.OuterLineWidth
== maTableBorder
.LeftLine
.OuterLineWidth
) &&
492 (maTableBorder
.TopLine
.OuterLineWidth
== maTableBorder
.RightLine
.OuterLineWidth
));
496 bRes
= ((maTableBorder
.TopLine
.OuterLineWidth
== maTableBorder
.BottomLine
.OuterLineWidth
) &&
497 (maTableBorder
.TopLine
.OuterLineWidth
== maTableBorder
.LeftLine
.OuterLineWidth
) &&
498 (maTableBorder
.TopLine
.OuterLineWidth
== maTableBorder
.HorizontalLine
.OuterLineWidth
) &&
499 (maTableBorder
.TopLine
.OuterLineWidth
== maTableBorder
.VerticalLine
.OuterLineWidth
) &&
500 (maTableBorder
.TopLine
.OuterLineWidth
== maTableBorder
.RightLine
.OuterLineWidth
));
505 uno::Any SAL_CALL
ScVbaBorders::getLineStyle()
507 table::TableBorder aTableBorder
;
508 m_xProps
->getPropertyValue( sTableBorder
) >>= aTableBorder
;
510 sal_Int32 aLinestyle
= XlLineStyle::xlLineStyleNone
;
512 if ( lcl_areAllLineWidthsSame( aTableBorder
, bRangeIsSingleCell
))
514 if (aTableBorder
.TopLine
.LineDistance
!= 0)
516 aLinestyle
= XlLineStyle::xlDouble
;
518 else if ( aTableBorder
.TopLine
.OuterLineWidth
!= 0 )
520 aLinestyle
= XlLineStyle::xlContinuous
;
523 return uno::Any( aLinestyle
);
525 void SAL_CALL
ScVbaBorders::setLineStyle( const uno::Any
& _linestyle
)
527 sal_Int32 count
= getCount();
528 for( sal_Int32 i
= 0; i
< count
; i
++ )
530 uno::Reference
< XBorder
> xBorder( getItemByIntIndex( supportedIndexTable
[i
] ), uno::UNO_QUERY_THROW
);
531 xBorder
->setLineStyle( _linestyle
);
534 uno::Any SAL_CALL
ScVbaBorders::getWeight()
536 sal_Int32 count
= getCount();
538 for( sal_Int32 i
= 0; i
< count
; i
++ )
540 if( XlBordersIndex::xlDiagonalDown
!= supportedIndexTable
[i
] && XlBordersIndex::xlDiagonalUp
!= supportedIndexTable
[i
] )
542 uno::Reference
< XBorder
> xBorder( getItemByIntIndex( supportedIndexTable
[i
] ), uno::UNO_QUERY_THROW
);
543 if( weight
.hasValue() )
545 if( weight
!= xBorder
->getWeight() )
546 return uno::Any( uno::Reference
< uno::XInterface
>() );
549 weight
= xBorder
->getWeight();
555 uno::Any SAL_CALL
ScVbaBorders::getTintAndShade()
558 return uno::Any(static_cast<double>(0));
561 void SAL_CALL
ScVbaBorders::setTintAndShade(const uno::Any
& /*rAny*/)
566 void SAL_CALL
ScVbaBorders::setWeight( const uno::Any
& _weight
)
568 sal_Int32 count
= getCount();
569 for( sal_Int32 i
= 0; i
< count
; i
++ )
571 uno::Reference
< XBorder
> xBorder( getItemByIntIndex( supportedIndexTable
[i
] ), uno::UNO_QUERY_THROW
);
572 xBorder
->setWeight( _weight
);
577 ScVbaBorders::getServiceImplName()
579 return u
"ScVbaBorders"_ustr
;
582 uno::Sequence
< OUString
>
583 ScVbaBorders::getServiceNames()
585 static uno::Sequence
< OUString
> const aServiceNames
587 u
"ooo.vba.excel.Borders"_ustr
589 return aServiceNames
;
592 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */