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_svx.hxx" 30 #include <svx/framelinkarray.hxx> 31 32 #include <math.h> 33 #include <vector> 34 #include <algorithm> 35 #include <vcl/outdev.hxx> 36 37 namespace svx { 38 namespace frame { 39 40 // ============================================================================ 41 42 43 Cell::Cell() : 44 mnAddLeft( 0 ), 45 mnAddRight( 0 ), 46 mnAddTop( 0 ), 47 mnAddBottom( 0 ), 48 mbMergeOrig( false ), 49 mbOverlapX( false ), 50 mbOverlapY( false ) 51 { 52 } 53 54 void Cell::MirrorSelfX( bool bMirrorStyles, bool bSwapDiag ) 55 { 56 std::swap( maLeft, maRight ); 57 std::swap( mnAddLeft, mnAddRight ); 58 if( bMirrorStyles ) 59 { 60 maLeft.MirrorSelf(); 61 maRight.MirrorSelf(); 62 } 63 if( bSwapDiag ) 64 { 65 std::swap( maTLBR, maBLTR ); 66 if( bMirrorStyles ) 67 { 68 maTLBR.MirrorSelf(); 69 maBLTR.MirrorSelf(); 70 } 71 } 72 } 73 74 void Cell::MirrorSelfY( bool bMirrorStyles, bool bSwapDiag ) 75 { 76 std::swap( maTop, maBottom ); 77 std::swap( mnAddTop, mnAddBottom ); 78 if( bMirrorStyles ) 79 { 80 maTop.MirrorSelf(); 81 maBottom.MirrorSelf(); 82 } 83 if( bSwapDiag ) 84 std::swap( maTLBR, maBLTR ); 85 /* Do not mirror diagonal styles, because they are oriented vertical. 86 Therefore swapping the styles is sufficient for correct behaviour. */ 87 } 88 89 // ---------------------------------------------------------------------------- 90 91 92 void lclRecalcCoordVec( LongVec& rCoords, const LongVec& rSizes ) 93 { 94 DBG_ASSERT( rCoords.size() == rSizes.size() + 1, "lclRecalcCoordVec - inconsistent vectors" ); 95 LongVec::iterator aCIt = rCoords.begin(); 96 LongVec::const_iterator aSIt = rSizes.begin(), aSEnd = rSizes.end(); 97 for( ; aSIt != aSEnd; ++aCIt, ++aSIt ) 98 *(aCIt + 1) = *aCIt + *aSIt; 99 } 100 101 void lclSetMergedRange( CellVec& rCells, size_t nWidth, size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow ) 102 { 103 for( size_t nCol = nFirstCol; nCol <= nLastCol; ++nCol ) 104 { 105 for( size_t nRow = nFirstRow; nRow <= nLastRow; ++nRow ) 106 { 107 Cell& rCell = rCells[ nRow * nWidth + nCol ]; 108 rCell.mbMergeOrig = false; 109 rCell.mbOverlapX = nCol > nFirstCol; 110 rCell.mbOverlapY = nRow > nFirstRow; 111 } 112 } 113 rCells[ nFirstRow * nWidth + nFirstCol ].mbMergeOrig = true; 114 } 115 116 // ---------------------------------------------------------------------------- 117 118 static const Style OBJ_STYLE_NONE; 119 static const Cell OBJ_CELL_NONE; 120 121 const bool DIAG_DBL_CLIP_DEFAULT = false; 122 123 // ============================================================================ 124 125 ArrayImpl::ArrayImpl( size_t nWidth, size_t nHeight, bool bDiagDblClip ) : 126 mnWidth( nWidth ), 127 mnHeight( nHeight ), 128 mnFirstClipCol( 0 ), 129 mnFirstClipRow( 0 ), 130 mnLastClipCol( nWidth - 1 ), 131 mnLastClipRow( nHeight - 1 ), 132 mbXCoordsDirty( false ), 133 mbYCoordsDirty( false ), 134 mbDiagDblClip( bDiagDblClip ) 135 { 136 // default-construct all vectors 137 maCells.resize( mnWidth * mnHeight ); 138 maWidths.resize( mnWidth, 0L ); 139 maHeights.resize( mnHeight, 0L ); 140 maXCoords.resize( mnWidth + 1, 0L ); 141 maYCoords.resize( mnHeight + 1, 0L ); 142 } 143 144 const Cell& ArrayImpl::GetCell( size_t nCol, size_t nRow ) const 145 { 146 return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : OBJ_CELL_NONE; 147 } 148 149 Cell& ArrayImpl::GetCellAcc( size_t nCol, size_t nRow ) 150 { 151 static Cell aDummy; 152 return IsValidPos( nCol, nRow ) ? maCells[ GetIndex( nCol, nRow ) ] : aDummy; 153 } 154 155 size_t ArrayImpl::GetMergedFirstCol( size_t nCol, size_t nRow ) const 156 { 157 size_t nFirstCol = nCol; 158 while( (nFirstCol > 0) && GetCell( nFirstCol, nRow ).mbOverlapX ) --nFirstCol; 159 return nFirstCol; 160 } 161 162 size_t ArrayImpl::GetMergedFirstRow( size_t nCol, size_t nRow ) const 163 { 164 size_t nFirstRow = nRow; 165 while( (nFirstRow > 0) && GetCell( nCol, nFirstRow ).mbOverlapY ) --nFirstRow; 166 return nFirstRow; 167 } 168 169 size_t ArrayImpl::GetMergedLastCol( size_t nCol, size_t nRow ) const 170 { 171 size_t nLastCol = nCol + 1; 172 while( (nLastCol < mnWidth) && GetCell( nLastCol, nRow ).mbOverlapX ) ++nLastCol; 173 return nLastCol - 1; 174 } 175 176 size_t ArrayImpl::GetMergedLastRow( size_t nCol, size_t nRow ) const 177 { 178 size_t nLastRow = nRow + 1; 179 while( (nLastRow < mnHeight) && GetCell( nCol, nLastRow ).mbOverlapY ) ++nLastRow; 180 return nLastRow - 1; 181 } 182 183 const Cell& ArrayImpl::GetMergedOriginCell( size_t nCol, size_t nRow ) const 184 { 185 return GetCell( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) ); 186 } 187 188 Cell& ArrayImpl::GetMergedOriginCellAcc( size_t nCol, size_t nRow ) 189 { 190 return GetCellAcc( GetMergedFirstCol( nCol, nRow ), GetMergedFirstRow( nCol, nRow ) ); 191 } 192 193 bool ArrayImpl::IsMergedOverlappedLeft( size_t nCol, size_t nRow ) const 194 { 195 const Cell& rCell = GetCell( nCol, nRow ); 196 return rCell.mbOverlapX || (rCell.mnAddLeft > 0); 197 } 198 199 bool ArrayImpl::IsMergedOverlappedRight( size_t nCol, size_t nRow ) const 200 { 201 return GetCell( nCol + 1, nRow ).mbOverlapX || (GetCell( nCol, nRow ).mnAddRight > 0); 202 } 203 204 bool ArrayImpl::IsMergedOverlappedTop( size_t nCol, size_t nRow ) const 205 { 206 const Cell& rCell = GetCell( nCol, nRow ); 207 return rCell.mbOverlapY || (rCell.mnAddTop > 0); 208 } 209 210 bool ArrayImpl::IsMergedOverlappedBottom( size_t nCol, size_t nRow ) const 211 { 212 return GetCell( nCol, nRow + 1 ).mbOverlapY || (GetCell( nCol, nRow ).mnAddBottom > 0); 213 } 214 215 bool ArrayImpl::IsColInClipRange( size_t nCol ) const 216 { 217 return (mnFirstClipCol <= nCol) && (nCol <= mnLastClipCol); 218 } 219 220 bool ArrayImpl::IsRowInClipRange( size_t nRow ) const 221 { 222 return (mnFirstClipRow <= nRow) && (nRow <= mnLastClipRow); 223 } 224 225 bool ArrayImpl::IsInClipRange( size_t nCol, size_t nRow ) const 226 { 227 return IsColInClipRange( nCol ) && IsRowInClipRange( nRow ); 228 } 229 230 long ArrayImpl::GetColPosition( size_t nCol ) const 231 { 232 if( mbXCoordsDirty ) 233 { 234 lclRecalcCoordVec( maXCoords, maWidths ); 235 mbXCoordsDirty = false; 236 } 237 return maXCoords[ nCol ]; 238 } 239 240 long ArrayImpl::GetRowPosition( size_t nRow ) const 241 { 242 if( mbYCoordsDirty ) 243 { 244 lclRecalcCoordVec( maYCoords, maHeights ); 245 mbYCoordsDirty = false; 246 } 247 return maYCoords[ nRow ]; 248 } 249 250 long ArrayImpl::GetColWidth( size_t nFirstCol, size_t nLastCol ) const 251 { 252 return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol ); 253 } 254 255 long ArrayImpl::GetRowHeight( size_t nFirstRow, size_t nLastRow ) const 256 { 257 return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow ); 258 } 259 260 double ArrayImpl::GetHorDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const 261 { 262 double fAngle = 0.0; 263 if( IsValidPos( nCol, nRow ) ) 264 { 265 if( bSimple || !GetCell( nCol, nRow ).IsMerged() ) 266 { 267 fAngle = frame::GetHorDiagAngle( maWidths[ nCol ] + 1, maHeights[ nRow ] + 1 ); 268 } 269 else 270 { 271 // return correct angle for each cell in the merged range 272 size_t nFirstCol = GetMergedFirstCol( nCol, nRow ); 273 size_t nFirstRow = GetMergedFirstRow( nCol, nRow ); 274 const Cell& rCell = GetCell( nFirstCol, nFirstRow ); 275 long nWidth = GetColWidth( nFirstCol, GetMergedLastCol( nCol, nRow ) ) + rCell.mnAddLeft + rCell.mnAddRight; 276 long nHeight = GetRowHeight( nFirstRow, GetMergedLastRow( nCol, nRow ) ) + rCell.mnAddTop + rCell.mnAddBottom; 277 fAngle = frame::GetHorDiagAngle( nWidth + 1, nHeight + 1 ); 278 } 279 } 280 return fAngle; 281 } 282 283 double ArrayImpl::GetVerDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const 284 { 285 double fAngle = GetHorDiagAngle( nCol, nRow, bSimple ); 286 return (fAngle > 0.0) ? (F_PI2 - fAngle) : 0.0; 287 } 288 289 // ============================================================================ 290 291 class MergedCellIterator 292 { 293 public: 294 explicit MergedCellIterator( const Array& rArray, size_t nCol, size_t nRow ); 295 296 inline bool Is() const { return (mnCol <= mnLastCol) && (mnRow <= mnLastRow); } 297 inline size_t Col() const { return mnCol; } 298 inline size_t Row() const { return mnRow; } 299 300 MergedCellIterator& operator++(); 301 302 private: 303 size_t mnFirstCol; 304 size_t mnFirstRow; 305 size_t mnLastCol; 306 size_t mnLastRow; 307 size_t mnCol; 308 size_t mnRow; 309 }; 310 311 // ---------------------------------------------------------------------------- 312 313 MergedCellIterator::MergedCellIterator( const Array& rArray, size_t nCol, size_t nRow ) 314 { 315 DBG_ASSERT( rArray.IsMerged( nCol, nRow ), "svx::frame::MergedCellIterator::MergedCellIterator - not in merged range" ); 316 rArray.GetMergedRange( mnFirstCol, mnFirstRow, mnLastCol, mnLastRow, nCol, nRow ); 317 mnCol = mnFirstCol; 318 mnRow = mnFirstRow; 319 } 320 321 MergedCellIterator& MergedCellIterator::operator++() 322 { 323 DBG_ASSERT( Is(), "svx::frame::MergedCellIterator::operator++() - already invalid" ); 324 if( ++mnCol > mnLastCol ) 325 { 326 mnCol = mnFirstCol; 327 ++mnRow; 328 } 329 return *this; 330 } 331 332 // ============================================================================ 333 334 #define DBG_FRAME_ERROR( funcname, error ) DBG_ERRORFILE( "svx::frame::Array::" funcname " - " error ) 335 #define DBG_FRAME_CHECK( cond, funcname, error ) DBG_ASSERT( cond, "svx::frame::Array::" funcname " - " error ) 336 #define DBG_FRAME_CHECK_COL( col, funcname ) DBG_FRAME_CHECK( (col) < GetColCount(), funcname, "invalid column index" ) 337 #define DBG_FRAME_CHECK_ROW( row, funcname ) DBG_FRAME_CHECK( (row) < GetRowCount(), funcname, "invalid row index" ) 338 #define DBG_FRAME_CHECK_COLROW( col, row, funcname ) DBG_FRAME_CHECK( ((col) < GetColCount()) && ((row) < GetRowCount()), funcname, "invalid cell index" ) 339 #define DBG_FRAME_CHECK_INDEX( index, funcname ) DBG_FRAME_CHECK( (index) < GetCellCount(), funcname, "invalid cell index" ) 340 #define DBG_FRAME_CHECK_COL_1( col, funcname ) DBG_FRAME_CHECK( (col) <= GetColCount(), funcname, "invalid column index" ) 341 #define DBG_FRAME_CHECK_ROW_1( row, funcname ) DBG_FRAME_CHECK( (row) <= GetRowCount(), funcname, "invalid row index" ) 342 343 // ---------------------------------------------------------------------------- 344 345 #define CELL( col, row ) mxImpl->GetCell( col, row ) 346 #define CELLACC( col, row ) mxImpl->GetCellAcc( col, row ) 347 #define ORIGCELL( col, row ) mxImpl->GetMergedOriginCell( col, row ) 348 #define ORIGCELLACC( col, row ) mxImpl->GetMergedOriginCellAcc( col, row ) 349 350 // ---------------------------------------------------------------------------- 351 352 Array::Array() 353 { 354 Initialize( 0, 0 ); 355 } 356 357 Array::Array( size_t nWidth, size_t nHeight ) 358 { 359 Initialize( nWidth, nHeight ); 360 } 361 362 Array::~Array() 363 { 364 } 365 366 // array size and column/row indexes ------------------------------------------ 367 368 void Array::Initialize( size_t nWidth, size_t nHeight ) 369 { 370 bool bDiagDblClip = mxImpl.get() ? mxImpl->mbDiagDblClip : DIAG_DBL_CLIP_DEFAULT; 371 mxImpl.reset( new ArrayImpl( nWidth, nHeight, bDiagDblClip ) ); 372 } 373 374 void Array::Clear() 375 { 376 Initialize( mxImpl->mnWidth, mxImpl->mnHeight ); 377 } 378 379 size_t Array::GetColCount() const 380 { 381 return mxImpl->mnWidth; 382 } 383 384 size_t Array::GetRowCount() const 385 { 386 return mxImpl->mnHeight; 387 } 388 389 size_t Array::GetCellCount() const 390 { 391 return mxImpl->maCells.size(); 392 } 393 394 size_t Array::GetColFromIndex( size_t nCellIndex ) const 395 { 396 DBG_FRAME_CHECK_INDEX( nCellIndex, "GetColFromIndex" ); 397 return mxImpl->mnWidth ? (nCellIndex % mxImpl->mnWidth) : 0; 398 } 399 400 size_t Array::GetRowFromIndex( size_t nCellIndex ) const 401 { 402 DBG_FRAME_CHECK_INDEX( nCellIndex, "GetRowFromIndex" ); 403 return mxImpl->mnWidth ? (nCellIndex / mxImpl->mnWidth) : 0; 404 } 405 406 size_t Array::GetCellIndex( size_t nCol, size_t nRow, bool bRTL ) const 407 { 408 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetCellIndex" ); 409 if (bRTL) 410 nCol = mxImpl->GetMirrorCol(nCol); 411 return mxImpl->GetIndex( nCol, nRow ); 412 } 413 414 // cell border styles --------------------------------------------------------- 415 416 void Array::SetCellStyleLeft( size_t nCol, size_t nRow, const Style& rStyle ) 417 { 418 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" ); 419 CELLACC( nCol, nRow ).maLeft = rStyle; 420 } 421 422 void Array::SetCellStyleRight( size_t nCol, size_t nRow, const Style& rStyle ) 423 { 424 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" ); 425 CELLACC( nCol, nRow ).maRight = rStyle; 426 } 427 428 void Array::SetCellStyleTop( size_t nCol, size_t nRow, const Style& rStyle ) 429 { 430 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" ); 431 CELLACC( nCol, nRow ).maTop = rStyle; 432 } 433 434 void Array::SetCellStyleBottom( size_t nCol, size_t nRow, const Style& rStyle ) 435 { 436 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" ); 437 CELLACC( nCol, nRow ).maBottom = rStyle; 438 } 439 440 void Array::SetCellStyleTLBR( size_t nCol, size_t nRow, const Style& rStyle ) 441 { 442 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" ); 443 CELLACC( nCol, nRow ).maTLBR = rStyle; 444 } 445 446 void Array::SetCellStyleBLTR( size_t nCol, size_t nRow, const Style& rStyle ) 447 { 448 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" ); 449 CELLACC( nCol, nRow ).maBLTR = rStyle; 450 } 451 452 void Array::SetCellStyleDiag( size_t nCol, size_t nRow, const Style& rTLBR, const Style& rBLTR ) 453 { 454 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleDiag" ); 455 Cell& rCell = CELLACC( nCol, nRow ); 456 rCell.maTLBR = rTLBR; 457 rCell.maBLTR = rBLTR; 458 } 459 460 void Array::SetColumnStyleLeft( size_t nCol, const Style& rStyle ) 461 { 462 DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleLeft" ); 463 for( size_t nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 464 SetCellStyleLeft( nCol, nRow, rStyle ); 465 } 466 467 void Array::SetColumnStyleRight( size_t nCol, const Style& rStyle ) 468 { 469 DBG_FRAME_CHECK_COL( nCol, "SetColumnStyleRight" ); 470 for( size_t nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 471 SetCellStyleRight( nCol, nRow, rStyle ); 472 } 473 474 void Array::SetRowStyleTop( size_t nRow, const Style& rStyle ) 475 { 476 DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleTop" ); 477 for( size_t nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 478 SetCellStyleTop( nCol, nRow, rStyle ); 479 } 480 481 void Array::SetRowStyleBottom( size_t nRow, const Style& rStyle ) 482 { 483 DBG_FRAME_CHECK_ROW( nRow, "SetRowStyleBottom" ); 484 for( size_t nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 485 SetCellStyleBottom( nCol, nRow, rStyle ); 486 } 487 488 const Style& Array::GetCellStyleLeft( size_t nCol, size_t nRow, bool bSimple ) const 489 { 490 // simple: always return own left style 491 if( bSimple ) 492 return CELL( nCol, nRow ).maLeft; 493 // outside clipping rows or overlapped in merged cells: invisible 494 if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedLeft( nCol, nRow ) ) 495 return OBJ_STYLE_NONE; 496 // left clipping border: always own left style 497 if( nCol == mxImpl->mnFirstClipCol ) 498 return ORIGCELL( nCol, nRow ).maLeft; 499 // right clipping border: always right style of left neighbor cell 500 if( nCol == mxImpl->mnLastClipCol + 1 ) 501 return ORIGCELL( nCol - 1, nRow ).maRight; 502 // outside clipping columns: invisible 503 if( !mxImpl->IsColInClipRange( nCol ) ) 504 return OBJ_STYLE_NONE; 505 // inside clipping range: maximum of own left style and right style of left neighbor cell 506 return std::max( ORIGCELL( nCol, nRow ).maLeft, ORIGCELL( nCol - 1, nRow ).maRight ); 507 } 508 509 const Style& Array::GetCellStyleRight( size_t nCol, size_t nRow, bool bSimple ) const 510 { 511 // simple: always return own right style 512 if( bSimple ) 513 return CELL( nCol, nRow ).maRight; 514 // outside clipping rows or overlapped in merged cells: invisible 515 if( !mxImpl->IsRowInClipRange( nRow ) || mxImpl->IsMergedOverlappedRight( nCol, nRow ) ) 516 return OBJ_STYLE_NONE; 517 // left clipping border: always left style of right neighbor cell 518 if( nCol + 1 == mxImpl->mnFirstClipCol ) 519 return ORIGCELL( nCol + 1, nRow ).maLeft; 520 // right clipping border: always own right style 521 if( nCol == mxImpl->mnLastClipCol ) 522 return ORIGCELL( nCol, nRow ).maRight; 523 // outside clipping columns: invisible 524 if( !mxImpl->IsColInClipRange( nCol ) ) 525 return OBJ_STYLE_NONE; 526 // inside clipping range: maximum of own right style and left style of right neighbor cell 527 return std::max( ORIGCELL( nCol, nRow ).maRight, ORIGCELL( nCol + 1, nRow ).maLeft ); 528 } 529 530 const Style& Array::GetCellStyleTop( size_t nCol, size_t nRow, bool bSimple ) const 531 { 532 // simple: always return own top style 533 if( bSimple ) 534 return CELL( nCol, nRow ).maTop; 535 // outside clipping columns or overlapped in merged cells: invisible 536 if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedTop( nCol, nRow ) ) 537 return OBJ_STYLE_NONE; 538 // top clipping border: always own top style 539 if( nRow == mxImpl->mnFirstClipRow ) 540 return ORIGCELL( nCol, nRow ).maTop; 541 // bottom clipping border: always bottom style of top neighbor cell 542 if( nRow == mxImpl->mnLastClipRow + 1 ) 543 return ORIGCELL( nCol, nRow - 1 ).maBottom; 544 // outside clipping rows: invisible 545 if( !mxImpl->IsRowInClipRange( nRow ) ) 546 return OBJ_STYLE_NONE; 547 // inside clipping range: maximum of own top style and bottom style of top neighbor cell 548 return std::max( ORIGCELL( nCol, nRow ).maTop, ORIGCELL( nCol, nRow - 1 ).maBottom ); 549 } 550 551 const Style& Array::GetCellStyleBottom( size_t nCol, size_t nRow, bool bSimple ) const 552 { 553 // simple: always return own bottom style 554 if( bSimple ) 555 return CELL( nCol, nRow ).maBottom; 556 // outside clipping columns or overlapped in merged cells: invisible 557 if( !mxImpl->IsColInClipRange( nCol ) || mxImpl->IsMergedOverlappedBottom( nCol, nRow ) ) 558 return OBJ_STYLE_NONE; 559 // top clipping border: always top style of bottom neighbor cell 560 if( nRow + 1 == mxImpl->mnFirstClipRow ) 561 return ORIGCELL( nCol, nRow + 1 ).maTop; 562 // bottom clipping border: always own bottom style 563 if( nRow == mxImpl->mnLastClipRow ) 564 return ORIGCELL( nCol, nRow ).maBottom; 565 // outside clipping rows: invisible 566 if( !mxImpl->IsRowInClipRange( nRow ) ) 567 return OBJ_STYLE_NONE; 568 // inside clipping range: maximum of own bottom style and top style of bottom neighbor cell 569 return std::max( ORIGCELL( nCol, nRow ).maBottom, ORIGCELL( nCol, nRow + 1 ).maTop ); 570 } 571 572 const Style& Array::GetCellStyleTLBR( size_t nCol, size_t nRow, bool bSimple ) const 573 { 574 return bSimple ? CELL( nCol, nRow ).maTLBR : 575 (mxImpl->IsInClipRange( nCol, nRow ) ? ORIGCELL( nCol, nRow ).maTLBR : OBJ_STYLE_NONE); 576 } 577 578 const Style& Array::GetCellStyleBLTR( size_t nCol, size_t nRow, bool bSimple ) const 579 { 580 return bSimple ? CELL( nCol, nRow ).maBLTR : 581 (mxImpl->IsInClipRange( nCol, nRow ) ? ORIGCELL( nCol, nRow ).maBLTR : OBJ_STYLE_NONE); 582 } 583 584 const Style& Array::GetCellStyleTL( size_t nCol, size_t nRow ) const 585 { 586 // not in clipping range: always invisible 587 if( !mxImpl->IsInClipRange( nCol, nRow ) ) 588 return OBJ_STYLE_NONE; 589 // return style only for top-left cell 590 size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); 591 size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); 592 return ((nCol == nFirstCol) && (nRow == nFirstRow)) ? 593 CELL( nFirstCol, nFirstRow ).maTLBR : OBJ_STYLE_NONE; 594 } 595 596 const Style& Array::GetCellStyleBR( size_t nCol, size_t nRow ) const 597 { 598 // not in clipping range: always invisible 599 if( !mxImpl->IsInClipRange( nCol, nRow ) ) 600 return OBJ_STYLE_NONE; 601 // return style only for bottom-right cell 602 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 603 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 604 return ((nCol == nLastCol) && (nRow == nLastRow)) ? 605 CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) ).maTLBR : OBJ_STYLE_NONE; 606 } 607 608 const Style& Array::GetCellStyleBL( size_t nCol, size_t nRow ) const 609 { 610 // not in clipping range: always invisible 611 if( !mxImpl->IsInClipRange( nCol, nRow ) ) 612 return OBJ_STYLE_NONE; 613 // return style only for bottom-left cell 614 size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); 615 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 616 return ((nCol == nFirstCol) && (nRow == nLastRow)) ? 617 CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).maBLTR : OBJ_STYLE_NONE; 618 } 619 620 const Style& Array::GetCellStyleTR( size_t nCol, size_t nRow ) const 621 { 622 // not in clipping range: always invisible 623 if( !mxImpl->IsInClipRange( nCol, nRow ) ) 624 return OBJ_STYLE_NONE; 625 // return style only for top-right cell 626 size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); 627 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 628 return ((nCol == nLastCol) && (nRow == nFirstRow)) ? 629 CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow ).maBLTR : OBJ_STYLE_NONE; 630 } 631 632 // cell merging --------------------------------------------------------------- 633 634 void Array::SetMergedRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow ) 635 { 636 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetMergedRange" ); 637 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetMergedRange" ); 638 #if OSL_DEBUG_LEVEL >= 2 639 { 640 bool bFound = false; 641 for( size_t nCurrCol = nFirstCol; !bFound && (nCurrCol <= nLastCol); ++nCurrCol ) 642 for( size_t nCurrRow = nFirstRow; !bFound && (nCurrRow <= nLastRow); ++nCurrRow ) 643 bFound = CELL( nCurrCol, nCurrRow ).IsMerged(); 644 DBG_FRAME_CHECK( !bFound, "SetMergedRange", "overlapping merged ranges" ); 645 } 646 #endif 647 if( mxImpl->IsValidPos( nFirstCol, nFirstRow ) && mxImpl->IsValidPos( nLastCol, nLastRow ) ) 648 lclSetMergedRange( mxImpl->maCells, mxImpl->mnWidth, nFirstCol, nFirstRow, nLastCol, nLastRow ); 649 } 650 651 void Array::RemoveMergedRange( size_t nCol, size_t nRow ) 652 { 653 DBG_FRAME_CHECK_COLROW( nCol, nRow, "RemoveMergedRange" ); 654 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 655 { 656 Cell& rCell = CELLACC( aIt.Col(), aIt.Row() ); 657 rCell.mbMergeOrig = rCell.mbOverlapX = rCell.mbOverlapY = false; 658 rCell.mnAddLeft = rCell.mnAddRight = rCell.mnAddTop = rCell.mnAddBottom = 0; 659 } 660 } 661 662 void Array::SetAddMergedLeftSize( size_t nCol, size_t nRow, long nAddSize ) 663 { 664 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedLeftSize" ); 665 DBG_FRAME_CHECK( mxImpl->GetMergedFirstCol( nCol, nRow ) == 0, "SetAddMergedLeftSize", "additional border inside array" ); 666 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 667 CELLACC( aIt.Col(), aIt.Row() ).mnAddLeft = nAddSize; 668 } 669 670 void Array::SetAddMergedRightSize( size_t nCol, size_t nRow, long nAddSize ) 671 { 672 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedRightSize" ); 673 DBG_FRAME_CHECK( mxImpl->GetMergedLastCol( nCol, nRow ) + 1 == mxImpl->mnWidth, "SetAddMergedRightSize", "additional border inside array" ); 674 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 675 CELLACC( aIt.Col(), aIt.Row() ).mnAddRight = nAddSize; 676 } 677 678 void Array::SetAddMergedTopSize( size_t nCol, size_t nRow, long nAddSize ) 679 { 680 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedTopSize" ); 681 DBG_FRAME_CHECK( mxImpl->GetMergedFirstRow( nCol, nRow ) == 0, "SetAddMergedTopSize", "additional border inside array" ); 682 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 683 CELLACC( aIt.Col(), aIt.Row() ).mnAddTop = nAddSize; 684 } 685 686 void Array::SetAddMergedBottomSize( size_t nCol, size_t nRow, long nAddSize ) 687 { 688 DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetAddMergedBottomSize" ); 689 DBG_FRAME_CHECK( mxImpl->GetMergedLastRow( nCol, nRow ) + 1 == mxImpl->mnHeight, "SetAddMergedBottomSize", "additional border inside array" ); 690 for( MergedCellIterator aIt( *this, nCol, nRow ); aIt.Is(); ++aIt ) 691 CELLACC( aIt.Col(), aIt.Row() ).mnAddBottom = nAddSize; 692 } 693 694 bool Array::IsMerged( size_t nCol, size_t nRow ) const 695 { 696 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMerged" ); 697 return CELL( nCol, nRow ).IsMerged(); 698 } 699 700 bool Array::IsMergedOrigin( size_t nCol, size_t nRow ) const 701 { 702 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOrigin" ); 703 return CELL( nCol, nRow ).mbMergeOrig; 704 } 705 706 bool Array::IsMergedOverlapped( size_t nCol, size_t nRow ) const 707 { 708 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlapped" ); 709 return CELL( nCol, nRow ).IsOverlapped(); 710 } 711 712 bool Array::IsMergedOverlappedLeft( size_t nCol, size_t nRow ) const 713 { 714 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedLeft" ); 715 return mxImpl->IsMergedOverlappedLeft( nCol, nRow ); 716 } 717 718 bool Array::IsMergedOverlappedRight( size_t nCol, size_t nRow ) const 719 { 720 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedRight" ); 721 return mxImpl->IsMergedOverlappedRight( nCol, nRow ); 722 } 723 724 bool Array::IsMergedOverlappedTop( size_t nCol, size_t nRow ) const 725 { 726 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedTop" ); 727 return mxImpl->IsMergedOverlappedTop( nCol, nRow ); 728 } 729 730 bool Array::IsMergedOverlappedBottom( size_t nCol, size_t nRow ) const 731 { 732 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsMergedOverlappedBottom" ); 733 return mxImpl->IsMergedOverlappedBottom( nCol, nRow ); 734 } 735 736 void Array::GetMergedOrigin( size_t& rnFirstCol, size_t& rnFirstRow, size_t nCol, size_t nRow ) const 737 { 738 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetMergedOrigin" ); 739 rnFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); 740 rnFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); 741 } 742 743 void Array::GetMergedSize( size_t& rnWidth, size_t& rnHeight, size_t nCol, size_t nRow ) const 744 { 745 size_t nFirstCol, nFirstRow, nLastCol, nLastRow; 746 GetMergedRange( nFirstCol, nFirstRow, nLastCol, nLastRow, nCol, nRow ); 747 rnWidth = nLastCol - nFirstCol + 1; 748 rnHeight = nLastRow - nFirstRow + 1; 749 } 750 751 void Array::GetMergedRange( size_t& rnFirstCol, size_t& rnFirstRow, 752 size_t& rnLastCol, size_t& rnLastRow, size_t nCol, size_t nRow ) const 753 { 754 GetMergedOrigin( rnFirstCol, rnFirstRow, nCol, nRow ); 755 rnLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 756 rnLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 757 } 758 759 // clipping ------------------------------------------------------------------- 760 761 void Array::SetClipRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow ) 762 { 763 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "SetClipRange" ); 764 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "SetClipRange" ); 765 mxImpl->mnFirstClipCol = nFirstCol; 766 mxImpl->mnFirstClipRow = nFirstRow; 767 mxImpl->mnLastClipCol = nLastCol; 768 mxImpl->mnLastClipRow = nLastRow; 769 } 770 771 void Array::RemoveClipRange() 772 { 773 if( !mxImpl->maCells.empty() ) 774 SetClipRange( 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1 ); 775 } 776 777 bool Array::IsInClipRange( size_t nCol, size_t nRow ) const 778 { 779 DBG_FRAME_CHECK_COLROW( nCol, nRow, "IsInClipRange" ); 780 return mxImpl->IsInClipRange( nCol, nRow ); 781 } 782 783 Rectangle Array::GetClipRangeRectangle() const 784 { 785 return Rectangle( 786 mxImpl->GetColPosition( mxImpl->mnFirstClipCol ), 787 mxImpl->GetRowPosition( mxImpl->mnFirstClipRow ), 788 mxImpl->GetColPosition( mxImpl->mnLastClipCol + 1 ), 789 mxImpl->GetRowPosition( mxImpl->mnLastClipRow + 1 ) ); 790 } 791 792 // cell coordinates ----------------------------------------------------------- 793 794 void Array::SetXOffset( long nXOffset ) 795 { 796 mxImpl->maXCoords[ 0 ] = nXOffset; 797 mxImpl->mbXCoordsDirty = true; 798 } 799 800 void Array::SetYOffset( long nYOffset ) 801 { 802 mxImpl->maYCoords[ 0 ] = nYOffset; 803 mxImpl->mbYCoordsDirty = true; 804 } 805 806 void Array::SetColWidth( size_t nCol, long nWidth ) 807 { 808 DBG_FRAME_CHECK_COL( nCol, "SetColWidth" ); 809 mxImpl->maWidths[ nCol ] = nWidth; 810 mxImpl->mbXCoordsDirty = true; 811 } 812 813 void Array::SetRowHeight( size_t nRow, long nHeight ) 814 { 815 DBG_FRAME_CHECK_ROW( nRow, "SetRowHeight" ); 816 mxImpl->maHeights[ nRow ] = nHeight; 817 mxImpl->mbYCoordsDirty = true; 818 } 819 820 void Array::SetAllColWidths( long nWidth ) 821 { 822 std::fill( mxImpl->maWidths.begin(), mxImpl->maWidths.end(), nWidth ); 823 mxImpl->mbXCoordsDirty = true; 824 } 825 826 void Array::SetAllRowHeights( long nHeight ) 827 { 828 std::fill( mxImpl->maHeights.begin(), mxImpl->maHeights.end(), nHeight ); 829 mxImpl->mbYCoordsDirty = true; 830 } 831 832 long Array::GetColPosition( size_t nCol ) const 833 { 834 DBG_FRAME_CHECK_COL_1( nCol, "GetColPosition" ); 835 return mxImpl->GetColPosition( nCol ); 836 } 837 838 long Array::GetRowPosition( size_t nRow ) const 839 { 840 DBG_FRAME_CHECK_ROW_1( nRow, "GetRowPosition" ); 841 return mxImpl->GetRowPosition( nRow ); 842 } 843 844 long Array::GetColWidth( size_t nCol ) const 845 { 846 DBG_FRAME_CHECK_COL( nCol, "GetColWidth" ); 847 return mxImpl->maWidths[ nCol ]; 848 } 849 850 long Array::GetColWidth( size_t nFirstCol, size_t nLastCol ) const 851 { 852 DBG_FRAME_CHECK_COL( nFirstCol, "GetColWidth" ); 853 DBG_FRAME_CHECK_COL( nLastCol, "GetColWidth" ); 854 return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol ); 855 } 856 857 long Array::GetRowHeight( size_t nRow ) const 858 { 859 DBG_FRAME_CHECK_ROW( nRow, "GetRowHeight" ); 860 return mxImpl->maHeights[ nRow ]; 861 } 862 863 long Array::GetRowHeight( size_t nFirstRow, size_t nLastRow ) const 864 { 865 DBG_FRAME_CHECK_ROW( nFirstRow, "GetRowHeight" ); 866 DBG_FRAME_CHECK_ROW( nLastRow, "GetRowHeight" ); 867 return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow ); 868 } 869 870 long Array::GetWidth() const 871 { 872 return GetColPosition( mxImpl->mnWidth ) - GetColPosition( 0 ); 873 } 874 875 long Array::GetHeight() const 876 { 877 return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 ); 878 } 879 880 Point Array::GetCellPosition( size_t nCol, size_t nRow, bool bSimple ) const 881 { 882 size_t nFirstCol = bSimple ? nCol : mxImpl->GetMergedFirstCol( nCol, nRow ); 883 size_t nFirstRow = bSimple ? nRow : mxImpl->GetMergedFirstRow( nCol, nRow ); 884 return Point( GetColPosition( nFirstCol ), GetRowPosition( nFirstRow ) ); 885 } 886 887 Size Array::GetCellSize( size_t nCol, size_t nRow, bool bSimple ) const 888 { 889 size_t nFirstCol = bSimple ? nCol : mxImpl->GetMergedFirstCol( nCol, nRow ); 890 size_t nFirstRow = bSimple ? nRow : mxImpl->GetMergedFirstRow( nCol, nRow ); 891 size_t nLastCol = bSimple ? nCol : mxImpl->GetMergedLastCol( nCol, nRow ); 892 size_t nLastRow = bSimple ? nRow : mxImpl->GetMergedLastRow( nCol, nRow ); 893 return Size( GetColWidth( nFirstCol, nLastCol ) + 1, GetRowHeight( nFirstRow, nLastRow ) + 1 ); 894 } 895 896 Rectangle Array::GetCellRect( size_t nCol, size_t nRow, bool bSimple ) const 897 { 898 Rectangle aRect( GetCellPosition( nCol, nRow, bSimple ), GetCellSize( nCol, nRow, bSimple ) ); 899 900 // adjust rectangle for partly visible merged cells 901 const Cell& rCell = CELL( nCol, nRow ); 902 if( !bSimple && rCell.IsMerged() ) 903 { 904 aRect.Left() -= rCell.mnAddLeft; 905 aRect.Right() += rCell.mnAddRight; 906 aRect.Top() -= rCell.mnAddTop; 907 aRect.Bottom() += rCell.mnAddBottom; 908 } 909 return aRect; 910 } 911 912 // diagonal frame borders ----------------------------------------------------- 913 914 double Array::GetHorDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const 915 { 916 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetHorDiagAngle" ); 917 return mxImpl->GetHorDiagAngle( nCol, nRow, bSimple ); 918 } 919 920 double Array::GetVerDiagAngle( size_t nCol, size_t nRow, bool bSimple ) const 921 { 922 DBG_FRAME_CHECK_COLROW( nCol, nRow, "GetVerDiagAngle" ); 923 return mxImpl->GetVerDiagAngle( nCol, nRow, bSimple ); 924 } 925 926 void Array::SetUseDiagDoubleClipping( bool bSet ) 927 { 928 mxImpl->mbDiagDblClip = bSet; 929 } 930 931 bool Array::GetUseDiagDoubleClipping() const 932 { 933 return mxImpl->mbDiagDblClip; 934 } 935 936 // mirroring ------------------------------------------------------------------ 937 938 void Array::MirrorSelfX( bool bMirrorStyles, bool bSwapDiag ) 939 { 940 CellVec aNewCells; 941 aNewCells.reserve( GetCellCount() ); 942 943 size_t nCol, nRow; 944 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 945 { 946 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 947 { 948 aNewCells.push_back( CELL( mxImpl->GetMirrorCol( nCol ), nRow ) ); 949 aNewCells.back().MirrorSelfX( bMirrorStyles, bSwapDiag ); 950 } 951 } 952 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 953 { 954 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 955 { 956 if( CELL( nCol, nRow ).mbMergeOrig ) 957 { 958 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 959 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 960 lclSetMergedRange( aNewCells, mxImpl->mnWidth, 961 mxImpl->GetMirrorCol( nLastCol ), nRow, 962 mxImpl->GetMirrorCol( nCol ), nLastRow ); 963 } 964 } 965 } 966 mxImpl->maCells.swap( aNewCells ); 967 968 std::reverse( mxImpl->maWidths.begin(), mxImpl->maWidths.end() ); 969 mxImpl->mbXCoordsDirty = true; 970 } 971 972 void Array::MirrorSelfY( bool bMirrorStyles, bool bSwapDiag ) 973 { 974 CellVec aNewCells; 975 aNewCells.reserve( GetCellCount() ); 976 977 size_t nCol, nRow; 978 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 979 { 980 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 981 { 982 aNewCells.push_back( CELL( nCol, mxImpl->GetMirrorRow( nRow ) ) ); 983 aNewCells.back().MirrorSelfY( bMirrorStyles, bSwapDiag ); 984 } 985 } 986 for( nRow = 0; nRow < mxImpl->mnHeight; ++nRow ) 987 { 988 for( nCol = 0; nCol < mxImpl->mnWidth; ++nCol ) 989 { 990 if( CELL( nCol, nRow ).mbMergeOrig ) 991 { 992 size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 993 size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 994 lclSetMergedRange( aNewCells, mxImpl->mnWidth, 995 nCol, mxImpl->GetMirrorRow( nLastRow ), 996 nLastCol, mxImpl->GetMirrorRow( nRow ) ); 997 } 998 } 999 } 1000 mxImpl->maCells.swap( aNewCells ); 1001 1002 std::reverse( mxImpl->maHeights.begin(), mxImpl->maHeights.end() ); 1003 mxImpl->mbYCoordsDirty = true; 1004 } 1005 1006 // drawing -------------------------------------------------------------------- 1007 1008 void Array::DrawCell( OutputDevice& rDev, size_t nCol, size_t nRow, const Color* pForceColor ) const 1009 { 1010 DrawRange( rDev, nCol, nRow, nCol, nRow, pForceColor ); 1011 } 1012 1013 void Array::DrawRange( OutputDevice& rDev, 1014 size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow, 1015 const Color* pForceColor ) const 1016 { 1017 DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "DrawRange" ); 1018 DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "DrawRange" ); 1019 1020 size_t nCol, nRow; 1021 1022 // *** diagonal frame borders *** 1023 1024 // set clipping region to clip partly visible merged cells 1025 rDev.Push( PUSH_CLIPREGION ); 1026 rDev.IntersectClipRegion( GetClipRangeRectangle() ); 1027 for( nRow = nFirstRow; nRow <= nLastRow; ++nRow ) 1028 { 1029 for( nCol = nFirstCol; nCol <= nLastCol; ++nCol ) 1030 { 1031 const Cell& rCell = CELL( nCol, nRow ); 1032 bool bOverlapX = rCell.mbOverlapX; 1033 bool bOverlapY = rCell.mbOverlapY; 1034 bool bFirstCol = nCol == nFirstCol; 1035 bool bFirstRow = nRow == nFirstRow; 1036 if( (!bOverlapX && !bOverlapY) || (bFirstCol && bFirstRow) || 1037 (!bOverlapY && bFirstCol) || (!bOverlapX && bFirstRow) ) 1038 { 1039 Rectangle aRect( GetCellRect( nCol, nRow ) ); 1040 if( (aRect.GetWidth() > 1) && (aRect.GetHeight() > 1) ) 1041 { 1042 size_t _nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow ); 1043 size_t _nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow ); 1044 size_t _nLastCol = mxImpl->GetMergedLastCol( nCol, nRow ); 1045 size_t _nLastRow = mxImpl->GetMergedLastRow( nCol, nRow ); 1046 1047 DrawDiagFrameBorders( rDev, aRect, 1048 GetCellStyleTLBR( _nFirstCol, _nFirstRow, true ), GetCellStyleBLTR( _nFirstCol, _nFirstRow, true ), 1049 GetCellStyleLeft( _nFirstCol, _nFirstRow ), GetCellStyleTop( _nFirstCol, _nFirstRow ), 1050 GetCellStyleRight( _nLastCol, _nLastRow ), GetCellStyleBottom( _nLastCol, _nLastRow ), 1051 GetCellStyleLeft( _nFirstCol, _nLastRow ), GetCellStyleBottom( _nFirstCol, _nLastRow ), 1052 GetCellStyleRight( _nLastCol, _nFirstRow ), GetCellStyleTop( _nLastCol, _nFirstRow ), 1053 pForceColor, mxImpl->mbDiagDblClip ); 1054 } 1055 } 1056 } 1057 } 1058 rDev.Pop(); // clip region 1059 1060 // *** horizontal frame borders *** 1061 1062 for( nRow = nFirstRow; nRow <= nLastRow + 1; ++nRow ) 1063 { 1064 double fAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow ); 1065 double fTAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow - 1 ); 1066 1067 // *Start*** variables store the data of the left end of the cached frame border 1068 Point aStartPos( mxImpl->GetColPosition( nFirstCol ), mxImpl->GetRowPosition( nRow ) ); 1069 const Style* pStart = &GetCellStyleTop( nFirstCol, nRow ); 1070 DiagStyle aStartLFromTR( GetCellStyleBL( nFirstCol, nRow - 1 ), fTAngle ); 1071 const Style* pStartLFromT = &GetCellStyleLeft( nFirstCol, nRow - 1 ); 1072 const Style* pStartLFromL = &GetCellStyleTop( nFirstCol - 1, nRow ); 1073 const Style* pStartLFromB = &GetCellStyleLeft( nFirstCol, nRow ); 1074 DiagStyle aStartLFromBR( GetCellStyleTL( nFirstCol, nRow ), fAngle ); 1075 1076 // *End*** variables store the data of the right end of the cached frame border 1077 DiagStyle aEndRFromTL( GetCellStyleBR( nFirstCol, nRow - 1 ), fTAngle ); 1078 const Style* pEndRFromT = &GetCellStyleRight( nFirstCol, nRow - 1 ); 1079 const Style* pEndRFromR = &GetCellStyleTop( nFirstCol + 1, nRow ); 1080 const Style* pEndRFromB = &GetCellStyleRight( nFirstCol, nRow ); 1081 DiagStyle aEndRFromBL( GetCellStyleTR( nFirstCol, nRow ), fAngle ); 1082 1083 for( nCol = nFirstCol + 1; nCol <= nLastCol; ++nCol ) 1084 { 1085 fAngle = mxImpl->GetHorDiagAngle( nCol, nRow ); 1086 fTAngle = mxImpl->GetHorDiagAngle( nCol, nRow - 1 ); 1087 1088 const Style& rCurr = *pEndRFromR; 1089 1090 DiagStyle aLFromTR( GetCellStyleBL( nCol, nRow - 1 ), fTAngle ); 1091 const Style& rLFromT = *pEndRFromT; 1092 const Style& rLFromL = *pStart; 1093 const Style& rLFromB = *pEndRFromB; 1094 DiagStyle aLFromBR( GetCellStyleTL( nCol, nRow ), fAngle ); 1095 1096 DiagStyle aRFromTL( GetCellStyleBR( nCol, nRow - 1 ), fTAngle ); 1097 const Style& rRFromT = GetCellStyleRight( nCol, nRow - 1 ); 1098 const Style& rRFromR = GetCellStyleTop( nCol + 1, nRow ); 1099 const Style& rRFromB = GetCellStyleRight( nCol, nRow ); 1100 DiagStyle aRFromBL( GetCellStyleTR( nCol, nRow ), fAngle ); 1101 1102 // check if current frame border can be connected to cached frame border 1103 if( !CheckFrameBorderConnectable( *pStart, rCurr, 1104 aEndRFromTL, rLFromT, aLFromTR, aEndRFromBL, rLFromB, aLFromBR ) ) 1105 { 1106 // draw previous frame border 1107 Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() ); 1108 if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) ) 1109 DrawHorFrameBorder( rDev, aStartPos, aEndPos, *pStart, 1110 aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR, 1111 aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor ); 1112 1113 // re-init "*Start***" variables 1114 aStartPos = aEndPos; 1115 pStart = &rCurr; 1116 aStartLFromTR = aLFromTR; 1117 pStartLFromT = &rLFromT; 1118 pStartLFromL = &rLFromL; 1119 pStartLFromB = &rLFromB; 1120 aStartLFromBR = aLFromBR; 1121 } 1122 1123 // store current styles in "*End***" variables 1124 aEndRFromTL = aRFromTL; 1125 pEndRFromT = &rRFromT; 1126 pEndRFromR = &rRFromR; 1127 pEndRFromB = &rRFromB; 1128 aEndRFromBL = aRFromBL; 1129 } 1130 1131 // draw last frame border 1132 Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() ); 1133 if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) ) 1134 DrawHorFrameBorder( rDev, aStartPos, aEndPos, *pStart, 1135 aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR, 1136 aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor ); 1137 } 1138 1139 // *** vertical frame borders *** 1140 1141 for( nCol = nFirstCol; nCol <= nLastCol + 1; ++nCol ) 1142 { 1143 double fAngle = mxImpl->GetVerDiagAngle( nCol, nFirstRow ); 1144 double fLAngle = mxImpl->GetVerDiagAngle( nCol - 1, nFirstRow ); 1145 1146 // *Start*** variables store the data of the top end of the cached frame border 1147 Point aStartPos( mxImpl->GetColPosition( nCol ), mxImpl->GetRowPosition( nFirstRow ) ); 1148 const Style* pStart = &GetCellStyleLeft( nCol, nFirstRow ); 1149 DiagStyle aStartTFromBL( GetCellStyleTR( nCol - 1, nFirstRow ), fLAngle ); 1150 const Style* pStartTFromL = &GetCellStyleTop( nCol - 1, nFirstRow ); 1151 const Style* pStartTFromT = &GetCellStyleLeft( nCol, nFirstRow - 1 ); 1152 const Style* pStartTFromR = &GetCellStyleTop( nCol, nFirstRow ); 1153 DiagStyle aStartTFromBR( GetCellStyleTL( nCol, nFirstRow ), fAngle ); 1154 1155 // *End*** variables store the data of the bottom end of the cached frame border 1156 DiagStyle aEndBFromTL( GetCellStyleBR( nCol - 1, nFirstRow ), fLAngle ); 1157 const Style* pEndBFromL = &GetCellStyleBottom( nCol - 1, nFirstRow ); 1158 const Style* pEndBFromB = &GetCellStyleLeft( nCol, nFirstRow + 1 ); 1159 const Style* pEndBFromR = &GetCellStyleBottom( nCol, nFirstRow ); 1160 DiagStyle aEndBFromTR( GetCellStyleBL( nCol, nFirstRow ), fAngle ); 1161 1162 for( nRow = nFirstRow + 1; nRow <= nLastRow; ++nRow ) 1163 { 1164 fAngle = mxImpl->GetVerDiagAngle( nCol, nRow ); 1165 fLAngle = mxImpl->GetVerDiagAngle( nCol - 1, nRow ); 1166 1167 const Style& rCurr = *pEndBFromB; 1168 1169 DiagStyle aTFromBL( GetCellStyleTR( nCol - 1, nRow ), fLAngle ); 1170 const Style& rTFromL = *pEndBFromL; 1171 const Style& rTFromT = *pStart; 1172 const Style& rTFromR = *pEndBFromR; 1173 DiagStyle aTFromBR( GetCellStyleTL( nCol, nRow ), fAngle ); 1174 1175 DiagStyle aBFromTL( GetCellStyleBR( nCol - 1, nRow ), fLAngle ); 1176 const Style& rBFromL = GetCellStyleBottom( nCol - 1, nRow ); 1177 const Style& rBFromB = GetCellStyleLeft( nCol, nRow + 1 ); 1178 const Style& rBFromR = GetCellStyleBottom( nCol, nRow ); 1179 DiagStyle aBFromTR( GetCellStyleBL( nCol, nRow ), fAngle ); 1180 1181 // check if current frame border can be connected to cached frame border 1182 if( !CheckFrameBorderConnectable( *pStart, rCurr, 1183 aEndBFromTL, rTFromL, aTFromBL, aEndBFromTR, rTFromR, aTFromBR ) ) 1184 { 1185 // draw previous frame border 1186 Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) ); 1187 if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) ) 1188 DrawVerFrameBorder( rDev, aStartPos, aEndPos, *pStart, 1189 aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR, 1190 aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR, pForceColor ); 1191 1192 // re-init "*Start***" variables 1193 aStartPos = aEndPos; 1194 pStart = &rCurr; 1195 aStartTFromBL = aTFromBL; 1196 pStartTFromL = &rTFromL; 1197 pStartTFromT = &rTFromT; 1198 pStartTFromR = &rTFromR; 1199 aStartTFromBR = aTFromBR; 1200 } 1201 1202 // store current styles in "*End***" variables 1203 aEndBFromTL = aBFromTL; 1204 pEndBFromL = &rBFromL; 1205 pEndBFromB = &rBFromB; 1206 pEndBFromR = &rBFromR; 1207 aEndBFromTR = aBFromTR; 1208 } 1209 1210 // draw last frame border 1211 Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) ); 1212 if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) ) 1213 DrawVerFrameBorder( rDev, aStartPos, aEndPos, *pStart, 1214 aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR, 1215 aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR, pForceColor ); 1216 } 1217 } 1218 1219 void Array::DrawArray( OutputDevice& rDev, const Color* pForceColor ) const 1220 { 1221 if( mxImpl->mnWidth && mxImpl->mnHeight ) 1222 DrawRange( rDev, 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, pForceColor ); 1223 } 1224 1225 // ---------------------------------------------------------------------------- 1226 1227 #undef ORIGCELLACC 1228 #undef ORIGCELL 1229 #undef CELLACC 1230 #undef CELL 1231 1232 // ---------------------------------------------------------------------------- 1233 1234 #undef DBG_FRAME_CHECK_ROW_1 1235 #undef DBG_FRAME_CHECK_COL_1 1236 #undef DBG_FRAME_CHECK_INDEX 1237 #undef DBG_FRAME_CHECK_COLROW 1238 #undef DBG_FRAME_CHECK_ROW 1239 #undef DBG_FRAME_CHECK_COL 1240 #undef DBG_FRAME_CHECK 1241 #undef DBG_FRAME_ERROR 1242 1243 // ============================================================================ 1244 1245 } // namespace frame 1246 } // namespace svx 1247 1248