1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 #include "vbaborders.hxx" 24 #include <ooo/vba/word/XBorder.hpp> 25 #include <ooo/vba/word/WdBorderType.hpp> 26 #include <ooo/vba/word/WdLineStyle.hpp> 27 #include <cppuhelper/implbase3.hxx> 28 #include <com/sun/star/beans/XPropertySet.hpp> 29 #include <com/sun/star/table/TableBorder.hpp> 30 #include <com/sun/star/table/ShadowFormat.hpp> 31 #include <com/sun/star/table/ShadowLocation.hpp> 32 #include "vbapalette.hxx" 33 34 using namespace ::com::sun::star; 35 using namespace ::ooo::vba; 36 37 38 typedef ::cppu::WeakImplHelper1<container::XIndexAccess > RangeBorders_Base; 39 typedef InheritedHelperInterfaceImpl1<word::XBorder > SwVbaBorder_Base; 40 41 // #TODO sort these indexes to match the order in which Word iterates over the 42 // borders, the enumeration will match the order in this list 43 static const sal_Int16 supportedIndexTable[] = { word::WdBorderType::wdBorderBottom, word::WdBorderType::wdBorderDiagonalDown, word::WdBorderType::wdBorderDiagonalUp, word::WdBorderType::wdBorderHorizontal, word::WdBorderType::wdBorderLeft, word::WdBorderType::wdBorderRight, word::WdBorderType::wdBorderTop, word::WdBorderType::wdBorderVertical }; 44 45 const static rtl::OUString sTableBorder( RTL_CONSTASCII_USTRINGPARAM("TableBorder") ); 46 47 // Equiv widths in in 1/100 mm 48 const static sal_Int32 OOLineThin = 35; 49 const static sal_Int32 OOLineMedium = 88; 50 const static sal_Int32 OOLineThick = 141; 51 const static sal_Int32 OOLineHairline = 2; 52 53 class SwVbaBorder : public SwVbaBorder_Base 54 { 55 private: 56 uno::Reference< beans::XPropertySet > m_xProps; 57 sal_Int32 m_LineType; 58 VbaPalette m_Palette; 59 bool setBorderLine( table::BorderLine& rBorderLine ) 60 { 61 table::TableBorder aTableBorder; 62 m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder; 63 64 switch ( m_LineType ) 65 { 66 case word::WdBorderType::wdBorderLeft: 67 aTableBorder.IsLeftLineValid = sal_True; 68 aTableBorder.LeftLine= rBorderLine; 69 break; 70 case word::WdBorderType::wdBorderTop: 71 aTableBorder.IsTopLineValid = sal_True; 72 aTableBorder.TopLine = rBorderLine; 73 break; 74 75 case word::WdBorderType::wdBorderBottom: 76 aTableBorder.IsBottomLineValid = sal_True; 77 aTableBorder.BottomLine = rBorderLine; 78 break; 79 case word::WdBorderType::wdBorderRight: 80 aTableBorder.IsRightLineValid = sal_True; 81 aTableBorder.RightLine = rBorderLine; 82 break; 83 case word::WdBorderType::wdBorderVertical: 84 aTableBorder.IsVerticalLineValid = sal_True; 85 aTableBorder.VerticalLine = rBorderLine; 86 break; 87 case word::WdBorderType::wdBorderHorizontal: 88 aTableBorder.IsHorizontalLineValid = sal_True; 89 aTableBorder.HorizontalLine = rBorderLine; 90 break; 91 case word::WdBorderType::wdBorderDiagonalDown: 92 case word::WdBorderType::wdBorderDiagonalUp: 93 // #TODO have to ignore at the momement, would be 94 // nice to investigate what we can do here 95 break; 96 default: 97 return false; 98 } 99 m_xProps->setPropertyValue( sTableBorder, uno::makeAny(aTableBorder) ); 100 return true; 101 } 102 103 bool getBorderLine( table::BorderLine& rBorderLine ) 104 { 105 table::TableBorder aTableBorder; 106 m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder; 107 switch ( m_LineType ) 108 { 109 case word::WdBorderType::wdBorderLeft: 110 if ( aTableBorder.IsLeftLineValid ) 111 rBorderLine = aTableBorder.LeftLine; 112 break; 113 case word::WdBorderType::wdBorderTop: 114 if ( aTableBorder.IsTopLineValid ) 115 rBorderLine = aTableBorder.TopLine; 116 break; 117 case word::WdBorderType::wdBorderBottom: 118 if ( aTableBorder.IsBottomLineValid ) 119 rBorderLine = aTableBorder.BottomLine; 120 break; 121 case word::WdBorderType::wdBorderRight: 122 if ( aTableBorder.IsRightLineValid ) 123 rBorderLine = aTableBorder.RightLine; 124 break; 125 case word::WdBorderType::wdBorderVertical: 126 if ( aTableBorder.IsVerticalLineValid ) 127 rBorderLine = aTableBorder.VerticalLine; 128 break; 129 case word::WdBorderType::wdBorderHorizontal: 130 if ( aTableBorder.IsHorizontalLineValid ) 131 rBorderLine = aTableBorder.HorizontalLine; 132 break; 133 134 case word::WdBorderType::wdBorderDiagonalDown: 135 case word::WdBorderType::wdBorderDiagonalUp: 136 // #TODO have to ignore at the momement, would be 137 // nice to investigate what we can do here 138 break; 139 default: 140 return false; 141 } 142 return true; 143 } 144 SwVbaBorder(); // no impl 145 protected: 146 virtual rtl::OUString& getServiceImplName() 147 { 148 static rtl::OUString sImplName( RTL_CONSTASCII_USTRINGPARAM("SwVbaBorder") ); 149 return sImplName; 150 } 151 virtual css::uno::Sequence<rtl::OUString> getServiceNames() 152 { 153 static uno::Sequence< rtl::OUString > aServiceNames; 154 if ( aServiceNames.getLength() == 0 ) 155 { 156 aServiceNames.realloc( 1 ); 157 aServiceNames[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.word.Border" ) ); 158 } 159 return aServiceNames; 160 } 161 public: 162 SwVbaBorder( const uno::Reference< beans::XPropertySet > & xProps, const uno::Reference< uno::XComponentContext >& xContext, sal_Int32 lineType, VbaPalette& rPalette) : SwVbaBorder_Base( uno::Reference< XHelperInterface >( xProps, uno::UNO_QUERY ), xContext ), m_xProps( xProps ), m_LineType( lineType ), m_Palette( rPalette ) {} 163 164 uno::Any SAL_CALL getLineStyle() throw (uno::RuntimeException) 165 { 166 sal_Int32 nLineStyle = word::WdLineStyle::wdLineStyleNone; 167 table::BorderLine aBorderLine; 168 if ( getBorderLine( aBorderLine ) ) 169 { 170 if( aBorderLine.InnerLineWidth !=0 && aBorderLine.OuterLineWidth !=0 ) 171 { 172 nLineStyle = word::WdLineStyle::wdLineStyleDouble; 173 } 174 else if( aBorderLine.InnerLineWidth !=0 || aBorderLine.OuterLineWidth !=0 ) 175 { 176 nLineStyle = word::WdLineStyle::wdLineStyleSingle; 177 } 178 else 179 { 180 nLineStyle = word::WdLineStyle::wdLineStyleNone; 181 } 182 } 183 return uno::makeAny( nLineStyle ); 184 } 185 void SAL_CALL setLineStyle( const uno::Any& _linestyle ) throw (uno::RuntimeException) 186 { 187 // Urk no choice but to silently ignore we don't support this attribute 188 // #TODO would be nice to support the word line styles 189 sal_Int32 nLineStyle = 0; 190 _linestyle >>= nLineStyle; 191 table::BorderLine aBorderLine; 192 if ( getBorderLine( aBorderLine ) ) 193 { 194 switch ( nLineStyle ) 195 { 196 case word::WdLineStyle::wdLineStyleNone: 197 { 198 aBorderLine.InnerLineWidth = 0; 199 aBorderLine.OuterLineWidth = 0; 200 break; 201 } 202 case word::WdLineStyle::wdLineStyleDashDot: 203 case word::WdLineStyle::wdLineStyleDashDotDot: 204 case word::WdLineStyle::wdLineStyleDashDotStroked: 205 case word::WdLineStyle::wdLineStyleDashLargeGap: 206 case word::WdLineStyle::wdLineStyleDashSmallGap: 207 case word::WdLineStyle::wdLineStyleDot: 208 case word::WdLineStyle::wdLineStyleDouble: 209 case word::WdLineStyle::wdLineStyleDoubleWavy: 210 case word::WdLineStyle::wdLineStyleEmboss3D: 211 case word::WdLineStyle::wdLineStyleEngrave3D: 212 case word::WdLineStyle::wdLineStyleInset: 213 case word::WdLineStyle::wdLineStyleOutset: 214 case word::WdLineStyle::wdLineStyleSingle: 215 case word::WdLineStyle::wdLineStyleSingleWavy: 216 case word::WdLineStyle::wdLineStyleThickThinLargeGap: 217 case word::WdLineStyle::wdLineStyleThickThinMedGap: 218 case word::WdLineStyle::wdLineStyleThickThinSmallGap: 219 case word::WdLineStyle::wdLineStyleThinThickLargeGap: 220 case word::WdLineStyle::wdLineStyleThinThickMedGap: 221 case word::WdLineStyle::wdLineStyleThinThickSmallGap: 222 case word::WdLineStyle::wdLineStyleThinThickThinLargeGap: 223 case word::WdLineStyle::wdLineStyleThinThickThinMedGap: 224 case word::WdLineStyle::wdLineStyleThinThickThinSmallGap: 225 case word::WdLineStyle::wdLineStyleTriple: 226 { 227 aBorderLine.InnerLineWidth = 0; 228 aBorderLine.OuterLineWidth = OOLineHairline; 229 break; 230 } 231 default: 232 throw uno::RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Bad param" ) ), uno::Reference< uno::XInterface >() ); 233 } 234 setBorderLine( aBorderLine ); 235 } 236 else 237 throw uno::RuntimeException( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "Method failed" ) ), uno::Reference< uno::XInterface >() ); 238 } 239 }; 240 241 class RangeBorders : public RangeBorders_Base 242 { 243 private: 244 uno::Reference< table::XCellRange > m_xRange; 245 uno::Reference< uno::XComponentContext > m_xContext; 246 VbaPalette m_Palette; 247 sal_Int32 getTableIndex( sal_Int32 nConst ) 248 { 249 // hokay return position of the index in the table 250 sal_Int32 nIndexes = getCount(); 251 sal_Int32 realIndex = 0; 252 const sal_Int16* pTableEntry = supportedIndexTable; 253 for ( ; realIndex < nIndexes; ++realIndex, ++pTableEntry ) 254 { 255 if ( *pTableEntry == nConst ) 256 return realIndex; 257 } 258 return getCount(); // error condition 259 } 260 public: 261 RangeBorders( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< uno::XComponentContext > & xContext, VbaPalette& rPalette ) : m_xRange( xRange ), m_xContext( xContext ), m_Palette( rPalette ) 262 { 263 } 264 // XIndexAccess 265 virtual ::sal_Int32 SAL_CALL getCount( ) throw (uno::RuntimeException) 266 { 267 return sizeof( supportedIndexTable ) / sizeof( supportedIndexTable[0] ); 268 } 269 virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException) 270 { 271 272 sal_Int32 nIndex = getTableIndex( Index ); 273 if ( nIndex >= 0 && nIndex < getCount() ) 274 { 275 uno::Reference< beans::XPropertySet > xProps( m_xRange, uno::UNO_QUERY_THROW ); 276 return uno::makeAny( uno::Reference< word::XBorder >( new SwVbaBorder( xProps, m_xContext, supportedIndexTable[ nIndex ], m_Palette )) ); 277 } 278 throw lang::IndexOutOfBoundsException(); 279 } 280 virtual uno::Type SAL_CALL getElementType( ) throw (uno::RuntimeException) 281 { 282 return word::XBorder::static_type(0); 283 } 284 virtual ::sal_Bool SAL_CALL hasElements( ) throw (uno::RuntimeException) 285 { 286 return sal_True; 287 } 288 }; 289 290 uno::Reference< container::XIndexAccess > 291 rangeToBorderIndexAccess( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< uno::XComponentContext > & xContext, VbaPalette& rPalette ) 292 { 293 return new RangeBorders( xRange, xContext, rPalette ); 294 } 295 296 class RangeBorderEnumWrapper : public EnumerationHelper_BASE 297 { 298 uno::Reference<container::XIndexAccess > m_xIndexAccess; 299 sal_Int32 nIndex; 300 public: 301 RangeBorderEnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) : m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {} 302 virtual ::sal_Bool SAL_CALL hasMoreElements( ) throw (uno::RuntimeException) 303 { 304 return ( nIndex < m_xIndexAccess->getCount() ); 305 } 306 307 virtual uno::Any SAL_CALL nextElement( ) throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException) 308 { 309 if ( nIndex < m_xIndexAccess->getCount() ) 310 return m_xIndexAccess->getByIndex( nIndex++ ); 311 throw container::NoSuchElementException(); 312 } 313 }; 314 315 // for Table borders 316 SwVbaBorders::SwVbaBorders( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< table::XCellRange >& xRange, VbaPalette& rPalette ): SwVbaBorders_BASE( xParent, xContext, rangeToBorderIndexAccess( xRange ,xContext, rPalette ) ) 317 { 318 m_xProps.set( xRange, uno::UNO_QUERY_THROW ); 319 } 320 321 uno::Reference< container::XEnumeration > 322 SwVbaBorders::createEnumeration() throw (uno::RuntimeException) 323 { 324 return new RangeBorderEnumWrapper( m_xIndexAccess ); 325 } 326 327 uno::Any 328 SwVbaBorders::createCollectionObject( const css::uno::Any& aSource ) 329 { 330 return aSource; // its already a Border object 331 } 332 333 uno::Type 334 SwVbaBorders::getElementType() throw (uno::RuntimeException) 335 { 336 return word::XBorders::static_type(0); 337 } 338 339 uno::Any 340 SwVbaBorders::getItemByIntIndex( const sal_Int32 nIndex ) throw (uno::RuntimeException) 341 { 342 return createCollectionObject( m_xIndexAccess->getByIndex( nIndex ) ); 343 } 344 345 sal_Bool SAL_CALL SwVbaBorders::getShadow() throw (uno::RuntimeException) 346 { 347 table::ShadowFormat aShadowFormat; 348 m_xProps->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ShadowFormat") ) ) >>= aShadowFormat; 349 return ( aShadowFormat.Location != table::ShadowLocation_NONE ); 350 } 351 352 void SAL_CALL SwVbaBorders::setShadow( sal_Bool /*_shadow*/ ) throw (uno::RuntimeException) 353 { 354 throw uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Not implemented") ), uno::Reference< uno::XInterface >() ); 355 } 356 357 rtl::OUString& 358 SwVbaBorders::getServiceImplName() 359 { 360 static rtl::OUString sImplName( RTL_CONSTASCII_USTRINGPARAM("SwVbaBorders") ); 361 return sImplName; 362 } 363 364 uno::Sequence< rtl::OUString > 365 SwVbaBorders::getServiceNames() 366 { 367 static uno::Sequence< rtl::OUString > aServiceNames; 368 if ( aServiceNames.getLength() == 0 ) 369 { 370 aServiceNames.realloc( 1 ); 371 aServiceNames[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.word.Borders" ) ); 372 } 373 return aServiceNames; 374 } 375