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 "vbapagebreaks.hxx" 24 #include "vbapagebreak.hxx" 25 #include <ooo/vba/excel/XWorksheet.hpp> 26 using namespace ::com::sun::star; 27 using namespace ::ooo::vba; 28 29 typedef ::cppu::WeakImplHelper1<container::XIndexAccess > RangePageBreaks_Base; 30 class RangePageBreaks : public RangePageBreaks_Base 31 { 32 private: 33 uno::Reference< XHelperInterface > mxParent; 34 uno::Reference< uno::XComponentContext > mxContext; 35 uno::Reference< sheet::XSheetPageBreak > mxSheetPageBreak; 36 sal_Bool m_bColumn; 37 38 public: 39 RangePageBreaks( const uno::Reference< XHelperInterface >& xParent, 40 const uno::Reference< uno::XComponentContext >& xContext, 41 uno::Reference< sheet::XSheetPageBreak >& xSheetPageBreak, 42 sal_Bool bColumn ) : mxParent( xParent ), mxContext( xContext ), mxSheetPageBreak( xSheetPageBreak ), m_bColumn( bColumn ) 43 { 44 } 45 46 sal_Int32 getAPIStartofRange( const uno::Reference< excel::XRange >& xRange ) throw (css::uno::RuntimeException) 47 { 48 if( m_bColumn ) 49 return xRange->getColumn() - 1; 50 return xRange->getRow() - 1; 51 } 52 53 sal_Int32 getAPIEndIndexofRange( const uno::Reference< excel::XRange >& xRange, sal_Int32 nUsedStart ) throw (uno::RuntimeException) 54 { 55 if( m_bColumn ) 56 return nUsedStart + xRange->Columns( uno::Any() )->getCount(); 57 return nUsedStart + xRange->Rows( uno::Any() )->getCount(); 58 } 59 60 uno::Sequence<sheet::TablePageBreakData> getAllPageBreaks() throw (uno::RuntimeException) 61 { 62 if( m_bColumn ) 63 return mxSheetPageBreak->getColumnPageBreaks(); 64 return mxSheetPageBreak->getRowPageBreaks(); 65 } 66 67 uno::Reference<container::XIndexAccess> getRowColContainer() throw (uno::RuntimeException) 68 { 69 uno::Reference< table::XColumnRowRange > xColumnRowRange( mxSheetPageBreak, uno::UNO_QUERY_THROW ); 70 uno::Reference<container::XIndexAccess> xIndexAccess; 71 if( m_bColumn ) 72 xIndexAccess.set( xColumnRowRange->getColumns(), uno::UNO_QUERY_THROW ); 73 else 74 xIndexAccess.set( xColumnRowRange->getRows(), uno::UNO_QUERY_THROW ); 75 return xIndexAccess; 76 } 77 78 sheet::TablePageBreakData getTablePageBreakData( sal_Int32 nAPIItemIndex ) throw ( script::BasicErrorException, uno::RuntimeException); 79 uno::Any Add( const css::uno::Any& Before ) throw ( css::script::BasicErrorException, css::uno::RuntimeException); 80 81 // XIndexAccess 82 virtual sal_Int32 SAL_CALL getCount( ) throw (uno::RuntimeException); 83 virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException); 84 virtual uno::Type SAL_CALL getElementType( ) throw (uno::RuntimeException) 85 { 86 if( m_bColumn ) 87 return excel::XVPageBreak::static_type(0); 88 return excel::XHPageBreak::static_type(0); 89 } 90 virtual sal_Bool SAL_CALL hasElements( ) throw (uno::RuntimeException) 91 { 92 return sal_True; 93 } 94 }; 95 96 /** @TODO Unlike MS Excel this method only considers the pagebreaks that intersect the used range 97 * To become completely compatible the print area has to be considered. As far as I found out this printarea 98 * also considers the position and sizes of shapes and manually inserted page breaks 99 * Note: In MS there is a limit of 1026 horizontal page breaks per sheet. 100 */ 101 sal_Int32 SAL_CALL RangePageBreaks::getCount( ) throw (uno::RuntimeException) 102 { 103 sal_Int32 nCount = 0; 104 uno::Reference< excel::XWorksheet > xWorksheet( mxParent, uno::UNO_QUERY_THROW ); 105 uno::Reference< excel::XRange > xRange = xWorksheet->getUsedRange(); 106 sal_Int32 nUsedStart = getAPIStartofRange( xRange ); 107 sal_Int32 nUsedEnd = getAPIEndIndexofRange( xRange, nUsedStart ); 108 uno::Sequence<sheet::TablePageBreakData> aTablePageBreakData = getAllPageBreaks(); 109 110 sal_Int32 nLength = aTablePageBreakData.getLength(); 111 for( sal_Int32 i=0; i<nLength; i++ ) 112 { 113 sal_Int32 nPos = aTablePageBreakData[i].Position; 114 if( nPos > nUsedEnd ) 115 return nCount; 116 if( nPos >= nUsedStart ) 117 nCount++; 118 } 119 120 return nCount; 121 } 122 123 uno::Any SAL_CALL RangePageBreaks::getByIndex( sal_Int32 Index ) throw (lang::IndexOutOfBoundsException, lang::WrappedTargetException, uno::RuntimeException) 124 { 125 if( (Index < getCount()) && ( Index >= 0 )) 126 { 127 sheet::TablePageBreakData aTablePageBreakData = getTablePageBreakData( Index ); 128 uno::Reference< container::XIndexAccess > xIndexAccess = getRowColContainer(); 129 sal_Int32 nPos = aTablePageBreakData.Position; 130 if( (nPos < xIndexAccess->getCount()) && (nPos > -1) ) 131 { 132 uno::Reference< beans::XPropertySet > xRowColPropertySet( xIndexAccess->getByIndex(nPos), uno::UNO_QUERY_THROW ); 133 if( m_bColumn ) 134 return uno::makeAny( uno::Reference< excel::XVPageBreak >( new ScVbaVPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) )); 135 return uno::makeAny( uno::Reference< excel::XHPageBreak >( new ScVbaHPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) )); 136 } 137 } 138 throw lang::IndexOutOfBoundsException(); 139 } 140 141 sheet::TablePageBreakData RangePageBreaks::getTablePageBreakData( sal_Int32 nAPIItemIndex ) throw ( script::BasicErrorException, uno::RuntimeException) 142 { 143 sal_Int32 index = -1; 144 sheet::TablePageBreakData aTablePageBreakData; 145 uno::Reference< excel::XWorksheet > xWorksheet( mxParent, uno::UNO_QUERY_THROW ); 146 uno::Reference< excel::XRange > xRange = xWorksheet->getUsedRange(); 147 sal_Int32 nUsedStart = getAPIStartofRange( xRange ); 148 sal_Int32 nUsedEnd = getAPIEndIndexofRange( xRange, nUsedStart ); 149 uno::Sequence<sheet::TablePageBreakData> aTablePageBreakDataList = getAllPageBreaks(); 150 151 sal_Int32 nLength = aTablePageBreakDataList.getLength(); 152 for( sal_Int32 i=0; i<nLength; i++ ) 153 { 154 aTablePageBreakData = aTablePageBreakDataList[i]; 155 sal_Int32 nPos = aTablePageBreakData.Position; 156 if( nPos >= nUsedStart ) 157 index++; 158 if( nPos > nUsedEnd ) 159 DebugHelper::exception(SbERR_METHOD_FAILED, rtl::OUString()); 160 if( index == nAPIItemIndex ) 161 return aTablePageBreakData; 162 } 163 164 return aTablePageBreakData; 165 } 166 167 uno::Any RangePageBreaks::Add( const css::uno::Any& Before ) throw ( css::script::BasicErrorException, css::uno::RuntimeException) 168 { 169 uno::Reference< excel::XRange > xRange; 170 Before >>= xRange; 171 if( !xRange.is() ) 172 { 173 DebugHelper::exception(SbERR_BAD_ARGUMENT, rtl::OUString()); 174 } 175 176 sal_Int32 nAPIRowColIndex = getAPIStartofRange( xRange ); 177 uno::Reference< container::XIndexAccess > xIndexAccess = getRowColContainer(); 178 uno::Reference< beans::XPropertySet > xRowColPropertySet( xIndexAccess->getByIndex(nAPIRowColIndex), uno::UNO_QUERY_THROW ); 179 xRowColPropertySet->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsStartOfNewPage" )), uno::makeAny(sal_True)); 180 sheet::TablePageBreakData aTablePageBreakData; 181 aTablePageBreakData.ManualBreak = sal_True; 182 aTablePageBreakData.Position = nAPIRowColIndex; 183 if( m_bColumn ) 184 return uno::makeAny( uno::Reference< excel::XVPageBreak >( new ScVbaVPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) )); 185 return uno::makeAny( uno::Reference< excel::XHPageBreak >( new ScVbaHPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) )); 186 } 187 188 189 class RangePageBreaksEnumWrapper : public EnumerationHelper_BASE 190 { 191 uno::Reference<container::XIndexAccess > m_xIndexAccess; 192 sal_Int32 nIndex; 193 public: 194 RangePageBreaksEnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) : m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {} 195 virtual ::sal_Bool SAL_CALL hasMoreElements( ) throw (uno::RuntimeException) 196 { 197 return ( nIndex < m_xIndexAccess->getCount() ); 198 } 199 200 virtual uno::Any SAL_CALL nextElement( ) throw (container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException) 201 { 202 if ( nIndex < m_xIndexAccess->getCount() ) 203 return m_xIndexAccess->getByIndex( nIndex++ ); 204 throw container::NoSuchElementException(); 205 } 206 }; 207 208 ScVbaHPageBreaks::ScVbaHPageBreaks( const uno::Reference< XHelperInterface >& xParent, 209 const uno::Reference< uno::XComponentContext >& xContext, 210 uno::Reference< sheet::XSheetPageBreak >& xSheetPageBreak) throw (uno::RuntimeException): 211 ScVbaHPageBreaks_BASE( xParent,xContext, new RangePageBreaks( xParent, xContext, xSheetPageBreak, sal_False )), 212 mxSheetPageBreak( xSheetPageBreak ) 213 { 214 } 215 216 uno::Any SAL_CALL ScVbaHPageBreaks::Add( const uno::Any& Before) throw ( script::BasicErrorException, uno::RuntimeException) 217 { 218 RangePageBreaks* pPageBreaks = dynamic_cast< RangePageBreaks* >( m_xIndexAccess.get() ); 219 if( pPageBreaks ) 220 { 221 return pPageBreaks->Add( Before ); 222 } 223 return uno::Any(); 224 } 225 226 uno::Reference< container::XEnumeration > 227 ScVbaHPageBreaks::createEnumeration() throw (uno::RuntimeException) 228 { 229 return new RangePageBreaksEnumWrapper( m_xIndexAccess ); 230 } 231 232 uno::Any 233 ScVbaHPageBreaks::createCollectionObject( const css::uno::Any& aSource ) 234 { 235 return aSource; // its already a pagebreak object 236 } 237 238 uno::Type 239 ScVbaHPageBreaks::getElementType() throw (uno::RuntimeException) 240 { 241 return excel::XHPageBreak::static_type(0); 242 } 243 244 rtl::OUString& 245 ScVbaHPageBreaks::getServiceImplName() 246 { 247 static rtl::OUString sImplName( RTL_CONSTASCII_USTRINGPARAM("ScVbaHPageBreaks") ); 248 return sImplName; 249 } 250 251 uno::Sequence< rtl::OUString > 252 ScVbaHPageBreaks::getServiceNames() 253 { 254 static uno::Sequence< rtl::OUString > aServiceNames; 255 if ( aServiceNames.getLength() == 0 ) 256 { 257 aServiceNames.realloc( 1 ); 258 aServiceNames[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.excel.HPageBreaks" ) ); 259 } 260 return aServiceNames; 261 } 262 263 //VPageBreak 264 ScVbaVPageBreaks::ScVbaVPageBreaks( const uno::Reference< XHelperInterface >& xParent, 265 const uno::Reference< uno::XComponentContext >& xContext, 266 uno::Reference< sheet::XSheetPageBreak >& xSheetPageBreak ) throw ( uno::RuntimeException ) 267 : ScVbaVPageBreaks_BASE( xParent, xContext, new RangePageBreaks( xParent, xContext, xSheetPageBreak, sal_True ) ), 268 mxSheetPageBreak( xSheetPageBreak ) 269 { 270 } 271 272 ScVbaVPageBreaks::~ScVbaVPageBreaks() 273 { 274 } 275 276 uno::Any SAL_CALL 277 ScVbaVPageBreaks::Add( const uno::Any& Before ) throw ( script::BasicErrorException, uno::RuntimeException ) 278 { 279 RangePageBreaks* pPageBreaks = dynamic_cast< RangePageBreaks* >( m_xIndexAccess.get() ); 280 if( pPageBreaks ) 281 { 282 return pPageBreaks->Add( Before ); 283 } 284 return uno::Any(); 285 } 286 287 uno::Reference< container::XEnumeration > 288 ScVbaVPageBreaks::createEnumeration() throw ( uno::RuntimeException ) 289 { 290 return new RangePageBreaksEnumWrapper( m_xIndexAccess ); 291 } 292 293 uno::Any 294 ScVbaVPageBreaks::createCollectionObject( const css::uno::Any& aSource ) 295 { 296 return aSource; // its already a pagebreak object 297 } 298 299 uno::Type 300 ScVbaVPageBreaks::getElementType() throw ( uno::RuntimeException ) 301 { 302 return excel::XVPageBreak::static_type( 0 ); 303 } 304 305 rtl::OUString& 306 ScVbaVPageBreaks::getServiceImplName() 307 { 308 static rtl::OUString sImplName( RTL_CONSTASCII_USTRINGPARAM( "ScVbaVPageBreaks" ) ); 309 return sImplName; 310 } 311 312 uno::Sequence< rtl::OUString > 313 ScVbaVPageBreaks::getServiceNames() 314 { 315 static uno::Sequence< rtl::OUString > aServiceNames; 316 if ( aServiceNames.getLength() == 0 ) 317 { 318 aServiceNames.realloc( 1 ); 319 aServiceNames[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.excel.VPageBreaks" ) ); 320 } 321 return aServiceNames; 322 } 323 324